Takie zadanie dostaliśmy na laboratorium systemów rozproszonych:
Napisać serwer obsługujący grę w kółko i krzyżyk. Użytkownik jako programu klienta używa programu telnet.
Komunikacja między klientem a serwerem odbywa się za pomocą protokołu TCP przez wymianę tekstów.
Serwer wysyła do klienta w trybie tekstowym aktualną sytuację na planszy. Klient wysyła swoje ruchy też w postaci tekstowej.
Serwer po odebraniu połączenia od klienta oczekuje pewien ustalony czas i jeśli w tym czasie zgłosi się drugi klient, to serwer łączy tych klientów w parę, rozgrywającą partię między sobą.
Serwer jest wtedy pośrednikiem w tej grze. Jeśli w zadanym czasie nie zgłosi się drugi klient, to serwer przejmuje jego rolę i staje się partnerem w grze. Jeśli w czasie gry któryś z pary graczy rozłączy się, to serwer i w tym przypadku przejmuje jego rolę i kontynuuje grę za niego. Komunikacja między klientem a serwerem powinna być identyczna niezależnie od tego, czy klient gra z serwerem, czy z innym klientem.
Serwer musi móc równocześnie obsługiwać wielu pojedynczych klientów i wiele par klientów. Serwer powinien być odporny na różne złośliwe zachowania klienta: dane niezgodne z oczekiwanymi, nagłe zerwanie połączenia itp. Serwer utrzymuje wszystkie niezbędne informacje o wszystkich rozgrywanych w danym momencie grach. Serwer musi dbać o zwalnianie zasobów po odłączeniu się klienta. Program powinien być napisany w C lub C++ z użyciem interfejsu gniazd.
Gra jest tylko pretekstem dla implementacji komunikacji sieciowej i serwer nie musi implementować żadnej rozsądnej strategii. Serwer może grać w sposób zupełnie przypadkowy, byle zgodnie z zasadami gry. Serwer powinien jakoś reagować na niepoprawne zagrania klienta.
A oto rozwiązanie:
#include
#include
#include
#include
#include
#include
int plansza[3][3]; //Dla planszy
int polaczony; //Czy klient 2 jest podlaczony
int newsockfd2; //Socket klienta 2
void gra(int,int);
void error(char *msg)
{
perror(msg);
exit(1);
}
void* thr(void *sockfd)
{
//Tworzy watek podlaczajacy klienta.
int *sock;
int clilen2,sock2;
struct sockaddr_in cli2_addr;
printf("Startuje watekn");
sock=(int *)sockfd;
sock2=*sock;
newsockfd2 = accept(sock2,
(struct sockaddr *) &cli2_addr, &clilen2);
if (newsockfd2 < 0)
error("BLAD podczas accept klienta 2 n");
printf("Klient podlaczonyn");
polaczony=1;
}
int main(int argc, char *argv[])
{
int sockfd,sockfd2, newsockfd, portno, clilen, pid,watek,i;
struct sockaddr_in serv_addr, cli_addr, cli2_addr;
pthread_t tr;
printf("Startujemy serwer n");
polaczony=0;
//Budujemy serwer:
if (argc < 2) {
fprintf(stderr,"BLAD, brak portu.n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("BLAD otwierajac socket n");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
//Bind i sluchamy:
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error("ERROR on binding");
listen(sockfd,5);
clilen = sizeof(cli_addr);
//Petla. Czekamy na przychodzace polozenia.
while (1) {
//Podlaczenie klienta 1.
if(polaczony==0)
{
watek = pthread_create( &tr, NULL,thr, (void*) &sockfd);
while(polaczony==0)
{
sleep(1);
}
}
newsockfd=newsockfd2;
polaczony=0;
//Podlaczenie klienta 2.
watek = pthread_create( &tr, NULL,thr, (void*) &sockfd);
/////////////////////
for (i=0;i<10;i++)
{
if(polaczony==0)
{
sleep(1);
}
else
{
break;
}
}
//No i oddzielamy od glownego procesu.
pid = fork();
if (pid < 0)
error("BLAD podczas fork. n");
if (pid == 0) {
//Stary proces.
//Zamykamy niepotrzebne gniazdo.
close(sockfd);
//Zaczynamy gre,
gra(newsockfd,newsockfd2);
exit(0);
}
else close(newsockfd);
}
return 0;
}
/*****************GRA*********************
Tu sie zaczyna sama gra,
*****************************************/
int wypisz(char wynik[15])
{
//Funkcja sprawdza wynik, wypisuje co trzeba.
int i,j,zwr,wolnych;
zwr=0;
wolnych=0;
//sprawdczamy czy sa wolne miejsca na planszy
for(i=0;i<3;i++)
{
for(j=0;j<3;j++)
{
if(plansza[i][j]==0)
{
wolnych++;
}
}
}
if(wolnych==0)
{
zwr=-1;
}
//sprawdzamy w wierszach
for(i=0;i0))
zwr=plansza[i][2];
}
//W kolumnach
for(i=0;i0))
zwr=plansza[2][i];
}
//W skosach
if((plansza[0][0]==plansza[1][1])&&(plansza[1][1]==plansza[2][2])&&(plansza[2][2]>0))
zwr=plansza[2][2];
if((plansza[0][2]==plansza[1][1])&&(plansza[1][1]==plansza[2][0])&&(plansza[2][0]>0))
zwr=plansza[2][0];
//Koniec sprawdzania wyniku.
/*if(zwr==-1)
{
wynik=" NIEROZEGRANErn";
}
else if(zwr==1)
{
wynik="Gre wygral Xrn";
}
else if(zwr==2)
{
wynik="Gre wygral Orn";
}
else
{*/
//Wypisujemy wynik
for(i=0;i<3;i++)
{
for(j=0;j<3;j++)
{
if(plansza[i][j]==0)
{
wynik[(i)*5+j]=' ';
}
else if(plansza[i][j]==1)
{
wynik[(i)*5+j]='X';
}
else if(plansza[i][j]==2)
{
wynik[(i)*5+j]='O';
}
}
wynik[(i)*5+3]='r';
wynik[(i)*5+4]='n';
}
//}
return zwr;
}
// 'Sztuczna inteligencja' na poziomie wspolczesnego gimnazjalisty. Wstawia w pierwsze wolne miejsce.
int AIruch(int gracz)
{
int i,j;
i=0;
j=0;
while((plansza[i][j]!=0)&&(i2)
{
j=0;
i++;
}
}
if(i<3)
{
plansza[i][j]=gracz;
}
return 0;
}
void gra (int sock,int sock2)
{
//Sama gra.
int i,j,n;
char buffer[256];
char wynik[15];
int ruch;
int rozgrywka;
int dwoch;
//Init
for(i=0;i<3;i++)
{
for(j=0;j<3;j++)
{
plansza[i][j]=0;
}
}
rozgrywka=0;
dwoch=1;
//Dopoki gra sie nie skonczyla
while(rozgrywka==0)
{
// Kolejne ruchy.
write(sock,"Nowa tura graczu X rn",21);
write(sock2,"Nowa tura graczu O rn",21);
//Dopoki nie wykonany prawidlowefggo ruchu
ruch=0;
while(ruch==0)
{
j=5;
i=5;
//Dopoki nie wpisano prawidlowego znaku
while((i2))
{
bzero(buffer,256);
write(sock,"Wpisz wiersz graczu X rn",24);
read(sock,buffer,256);
i=0;
while((i<256)&&((buffer[i]'3')))
{
i++;
}
i=buffer[i]-49;
}
//Wopoki nie dobry znak
while((j2))
{
bzero(buffer,256);
write(sock,"Wpisz kolumne graczu X rn",25);
read(sock,buffer,256);
j=0;
while((j<256)&&((buffer[j]'3')))
{
j++;
}
j=buffer[j]-49;
}
//Wykonujemy ruch.
if(plansza[i][j]==0)
{
plansza[i][j]=1;
ruch=1;
}
}
rozgrywka=wypisz(wynik);
ruch=0;
//Jesli klient 2 jest podlaczony
if(polaczony==1)
{
//I tak samo.
while((ruch==0)&&(rozgrywka==0))
{
write(sock2,wynik,15);
i=5;
while((i2))
{
bzero(buffer,256);
write(sock2,"Wpisz wiersz graczu O rn",24);
read(sock2,buffer,256);
i=0;
while((i<256)&&((buffer[i]'3')))
{
i++;
}
i=buffer[i]-49;
}
j=5;
while((j2))
{
bzero(buffer,256);
write(sock2,"Wpisz kolumne graczu O rn",25);
read(sock2,buffer,256);
j=0;
while((j<256)&&((buffer[j]'3')))
{
j++;
}
j=buffer[j]-49;
}
//Wykonujemy ruch.
if(plansza[i][j]==0)
{
plansza[i][j]=2;
ruch=1;
}
}//Ruchy wykonane.
}
else
{
//Jesli klient 2 nie podlaczony - intelygencyja
AIruch(2);
}
rozgrywka=wypisz(wynik);
write(sock,wynik,15);
}
write(sock,wynik,15);
if(polaczony==1)
{
write(sock,wynik,15);
}
printf("Gra skonczona - wynik: [%i]n%sn",rozgrywka,wynik);
}