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); }