Описание реализации протокола на сервере.

После создания прослушивающего сокета, сервер входит в цикл приёма соединения:

В случае если происходит подключение нового клиента, выполняется тело цикла, в котором необходимо записать информацию о клиенте (дескриптор и IP адрес) в буфер, запустить отдельную нить для дальнейшего диалога с клиентом, передав указатель на данный буфер.

Работа нити, обрабатывающая клиента, начинается с отправки списка клиентов ожидающих подключения второго игрока

Далее ожидается сообщения от клиента о создании игры или подключения игре. Клиент создавший игру становится хозяином игры (и первый начинает ходить), а подключившийся — вторым игроком.

После получения запроса на игру в глобальном массиве games[] резервируется первый свободный элемент (признак свободности поля connfd1 и connfd2 равны -1). Для защиты от одновременного доступа к этой переменной, также используется мьютекс mutex_list_games.

Если же принят запрос на подключения, то ищется игра по ID переданному от клиента если к данной игре не подключился другой клиент, то игра полностью резервируется.

Далее в цикле с неблокируемым вводом обрабатываются запросы от клиента, и сообщения от нити обслуживающую клиента-противника. Здесь передается сообщения чата, ходы и информация о отключения клиента. Сообщения между нитями передаются через “переменные состояния” (mtx1 и mtx2), безопасность данного взаимодействия обеспечивается мьютексами

По завершении главного цикла, игрокам отправляются сообщения о победителе или об игре вничью и процесс завершается.

Описание реализации протокола на клиенте.

При соединении с сервером клиенту отправляется список клиентов ожидающих второго игрока. Далее по выбору клиента либо создается новая игра, либо происходит присоединение к уже созданной. После чего в цикле с неблокируемым вводом, происходит обмен запросов по протоколу. Взаимодействие с пользовательским интерфейсом происходит через “переменную состояния”, безопасность взаимодействия обеспечивается за счет мьютексов.

Внутри цикла происходит обработка всех сообщений и ошибок, согласно протоколу.

Описание пользовательского интерфейса клиента.

Управление отрисовкой интерфейса и терминалом происходит при помощи функций библиотек myTerm и myBigChars.

В частности myTerm используется для установки режима терминалов, для управления курсором, установки цвета, рисование рамок, вывод символов в определенной позиции на экране и т.д. MyBigChars содержит функции для вывода на экран т. н. «bigchar'ов» т.е. изображений размером 8х8 символов, записанных в файле. В данном случае — изображения крестика и нолика.

Управление интерфейсом организуется в потоке main, состоит из цикла, производящего чтение. Но в данном случае — чтение со стандартного потока ввода, т.е. с клавиатуры.

В зависимости от нажатой клавиши и текущего состояния выполняются те или иные действия по отрисовке интерфейса.

Исходный код board.h

#include "myBigChars.h"

#include "myTerm.h"

#include <fcntl.h>

#define max_row 32

#define max_col 50

#define BG White

#define FG Black

#define FGV Red

#define FBG Blue

#define MAXLINE 128

#define MAX_CH_IP 25

struct menu_type

{

int id;

char ip[MAX_CH_IP];

};

typedef enum { EMPTY, CROSS, ZERO } tPosSign;

typedef tPosSign board[3][3];

bigchar zero,cross,nul;

extern int initic();

extern int printBoard (board,int,int);

extern void setBoardPos(board, int, int, tPosSign);

extern void getBoardPos (board, int, int, tPosSign *);

extern int editBoard (board *, int *, int *);

extern int menu (struct menu_type *, int, int, int, int);

extern int victory(board,tPosSign *,int *,int *);

extern void win_printBoard (tPosSign,int,int);

Исходный код board.c

#include "board.h"

#include "error.h"

int initic()

{

int f,n;

nul.a=nul.b=0;

error_1_return(f=open("zero", O_RDONLY),"Ошибка при открытие файла zero",-1);

error_1_return(bigcharread(f, &zero, 1, &n),"Ошибка при считывание символа zero",-1);

close(f);

error_1_return(f=open("cross", O_RDONLY),"Ошибка при открытие файла cross",-1);

error_1_return(bigcharread(f, &cross, 1, &n),"Ошибка при считывание символа cross",-1);

close(f);

return 0;

}

int printBoard (board cletka,int x,int y)

{

int i,j;

bigchar bc;

getscreensize(&i,&j);

if (i<max_row || j<max_col)

{

printf("Ошибка: недостаточный размер экрана\n");

return -1;

}

setfgcolor(FG);

setbgcolor(BG);

box(1,1,30,30);

for (i=0;i<3;i++)

for (j=0;j<3;j++)

{

if (x==j&&y==i)

{

setfgcolor(FGV);

setbgcolor(BG);

}

else

{

setfgcolor(FG);

setbgcolor(BG);

}

box(2+j*10,2+i*10,8,8);

switch (cletka[i][j])

{

case ZERO:

bc=zero;

break;

case CROSS:

bc=cross;

break;

case EMPTY:

bc=nul;

break;

}

printbigchar(&bc,3+j*10,3+i*10,FG,BG);

}

return 0;

}

void setBoardPos(board cletka, int x, int y, tPosSign sign)

{

cletka[y][x] = sign;

bigchar bc;

switch (sign)

{

case ZERO:

bc=zero;

break;

case CROSS:

bc=cross;

break;

case EMPTY:

bc=nul;

break;

}

}

void getBoardPos(board cletka, int x, int y, tPosSign *sign)

{

*sign = cletka[y][x];

}

void edit_str(char str[], int x, int y,int wid)

{

int i;

gotoXY(x,y);

mywrite("%s",str);

for (i=strlen(str);i<wid;i++)

mywrite(" ");

}

int menu (struct menu_type *lst, int x, int y, int str,int wid)

{

int ed=0,i;

keys key;

clrscr();

setfgcolor(FGV);

setbgcolor(BG);

box(x,y,wid,str);

setfgcolor(FGV);

setbgcolor(FBG);

edit_str(lst[0].ip,x+1,y+1,wid);

setfgcolor(FG);

setbgcolor(BG);

for (i=1;i<str;i++)

edit_str(lst[i].ip,x+1,y+1+i,wid);

while (key!=K_ENTER && key!=K_ESC)

{

readkey(&key);

switch (key)

{

case K_DOWN:

setfgcolor(FG);

setbgcolor(BG);

edit_str(lst[ed].ip,x+1,y+1+ed,wid);

if (ed==str-1)

ed=0;

else

ed++;

setfgcolor(FGV);

setbgcolor(FBG);

edit_str(lst[ed].ip,x+1,y+1+ed,wid);

break;

case K_UP:

setfgcolor(FG);

setbgcolor(BG);

edit_str(lst[ed].ip,x+1,y+1+ed,wid);

if (ed==0)

ed=str-1;

else

ed--;

setfgcolor(FGV);

setbgcolor(FBG);

edit_str(lst[ed].ip,x+1,y+1+ed,wid);

break;

default:

break;

}

}

setfgcolor(FG);

setbgcolor(BG);

if (key==K_ESC)

return -1;

else

return ed;

}

int victory(board cletka,tPosSign *sign,int *napr,int *nom)

{

int i,j,k;

for (i=0;i<3;i++)

{

k=0;

for (j=1;j<3;j++)

if (cletka[i][j]==cletka[i][j-1]) k++;

if (k==2&&cletka[i][0]!=EMPTY)

{

*sign=cletka[i][0];

*napr=0;

*nom=i;

return 1;

}

}

for (j=0;j<3;j++)

{

k=0;

for (i=1;i<3;i++)

if (cletka[i][j]==cletka[i-1][j]) k++;

if (k==2&&cletka[0][j]!=EMPTY)

{

*sign=cletka[0][j];

*napr=1;

*nom=j;

return 1;

}

}

k=0;

for (i=1;i<3;i++)

if (cletka[i][i]==cletka[i-1][i-1]) k++;

if (k==2&&cletka[0][0]!=EMPTY)

{

*sign=cletka[0][0];

*napr=2;

*nom=0;

return 1;

}

k=0;

for (i=1;i<3;i++)

if (cletka[i][2-i]==cletka[i-1][3-i]) k++;

if (k==2&&cletka[0][2]!=EMPTY)

{

*sign=cletka[0][2];

*napr=2;

*nom=1;

return 1;

}

return 0;

}

void win_printBoard (tPosSign sign,int napr,int nom)

{

int i;

setfgcolor(FGV);

setbgcolor(BG);

switch (napr)

{

case 0:

for (i=0;i<3;i++)

box(2+i*10,2+nom*10,8,8);

break;

case 1:

for (i=0;i<3;i++)

box(2+nom*10,2+i*10,8,8);

break;

case 2:

if (nom)

{

box(2+2*10,2+0*10,8,8);

box(2+1*10,2+1*10,8,8);

box(2+0*10,2+2*10,8,8);

}

else

{

box(2+0*10,2+0*10,8,8);

box(2+1*10,2+1*10,8,8);

box(2+2*10,2+2*10,8,8);

}

break;

}

gotoXY(40,2);

if (sign==CROSS)

printf("CROSS WIN");

else

printf("ZERO WIN");

}

Исходный код client.c

#include <stdio.h>

#include <stdlib.h>

#include <getopt.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <arpa/inet.h>

#include <errno.h>

#include <string.h>

#include <unistd.h>

#include <signal.h>

#include <pthread.h>

#include "board.h"

#include "error.h"

#define max_mes 27

int x=0,y=0,maxx,maxy,mtx1=0,mtx2=0,hx,hy,och,reg=1,i,kol_mes=0,prin[max_mes];

char buffer[MAX_CH_IP],message[max_mes][MAXLINE];

pthread_mutex_t mutex1,mutex2;

board cletka={{EMPTY,EMPTY,EMPTY},{EMPTY,EMPTY,EMPTY},{EMPTY,EMPTY,EMPTY}};

tPosSign sign,sign_cl;

int com_str(int argc, char **argv,char ip[],int *pr)

{

const char* short_options = "s:p:";

const struct option long_options[] =

{

{"game-server",required_argument,NULL,200},

{"game-server-port",required_argument,NULL,201},

{NULL,0,NULL,0}

};

int rez;

int option_index;

while ((rez=getopt_long(argc,argv,short_options,long_options,&option_index))!=-1)

{

switch(rez)

{

case 200:

case 's':

{

strcpy(ip,optarg);

break;

}

case 201:

case 'p':

{

if (optarg!=NULL)

{

*pr=atoi(optarg);

if (*pr<=0)

{

printf("chisl\n");

return -1;

}

}

break;

}

}

}

return 0;

}

int ris()

{

int i;

clrscr();

getscreensize(&maxy,&maxx);

if (maxy<32 || maxx<=54)

{

printf("Недостаточный размер окна\n");

mytermrestore();

setcursor(1);

exit(-1);

}

else

{

if (reg)

{

printBoard(cletka,x,y);

box(33,1,maxx-34,27);

box(33,30,maxx-34,1);

}

else

{

printBoard(cletka,-1,-1);

box(33,1,maxx-34,27);

setfgcolor(FGV);

box(33,30,maxx-34,1);

}

// mytermrestore();

setfgcolor(Magenta);

gotoXY(34,2);

write(OUTPUT_STREAM,message[0],strlen(message[0]));

for (i=1;i<max_mes;i++)

{

gotoXY(34,2+i);

if (prin[i])

{

setfgcolor(FGV);

write(OUTPUT_STREAM,message[i],strlen(message[i]));

}

else

{

setfgcolor(FG);

write(OUTPUT_STREAM,message[i],strlen(message[i]));

}

}

// mytermregime(0,0,1,0,1);

}

printBoard(cletka,x,y);

return 0;

}

void handler(int signo)

{

getscreensize(&y,&x);

ris();

}

void add_str(char *ch1,int pri)

{

int i;

if (kol_mes<max_mes)

{

kol_mes++;

strcpy(message[kol_mes],ch1);

prin[kol_mes]=pri;

}

else

{

for (i=1;i<max_mes-1;i++)

{

strcpy(message[kol_mes+1],message[kol_mes]);

prin[i]=prin[i+1];

}

strcpy(message[i],ch1);

prin[i]=pri;

}

}

void *con_ser(void *arg)

{

int des=(int)(int *) arg,n,ot,t,b;

while (1)

{

fcntl(des, F_SETFL, FNDELAY|fcntl(des, F_GETFL, 0));

n=read(des,&ot,sizeof(int));

fcntl(des, F_SETFL, ~FNDELAY&fcntl(des, F_GETFL, 0));

if (n<0 && errno!=11) goto the_end;

if (n>0)

{

switch (ot)

{

case 5://text

error_pol_goto(read(des,&t,sizeof(int)),"Error",the_end);

error_pol_goto(read(des,&buffer,t),"Error",the_end);

buffer[t]='\0';

b=1;

while (b)

{

pthread_mutex_lock(&mutex1);

if (mtx1==0) b=0;

pthread_mutex_unlock(&mutex1);

}

pthread_mutex_lock(&mutex1);

mtx1=8;

pthread_mutex_unlock(&mutex1);

break;

case 7:

error_pol_goto(read(des,&hx,sizeof(int)),"Error",the_end);

error_pol_goto(read(des,&hy,sizeof(int)),"Error",the_end);

b=1;

while (b)

{

pthread_mutex_lock(&mutex1);

if (mtx1==0) b=0;

pthread_mutex_unlock(&mutex1);

}

pthread_mutex_lock(&mutex1);

mtx1=3;

pthread_mutex_unlock(&mutex1);

break;

case 8:

b=1;

while (b)

{

pthread_mutex_lock(&mutex1);

if (mtx1==0) b=0;

pthread_mutex_unlock(&mutex1);

}

pthread_mutex_lock(&mutex1);

mtx1=4;

pthread_mutex_unlock(&mutex1);

break;

case 9:

b=1;

while (b)

{

pthread_mutex_lock(&mutex1);

if (mtx1==0) b=0;

pthread_mutex_unlock(&mutex1);

}

pthread_mutex_lock(&mutex1);

mtx1=5;

pthread_mutex_unlock(&mutex1);

break;

case 10:

b=1;

while (b)

{

pthread_mutex_lock(&mutex1);

if (mtx1==0) b=0;

pthread_mutex_unlock(&mutex1);

}

pthread_mutex_lock(&mutex1);

mtx1=6;

pthread_mutex_unlock(&mutex1);

break;

case 11:

b=1;

while (b)

{

pthread_mutex_lock(&mutex1);

if (mtx1==0) b=0;

pthread_mutex_unlock(&mutex1);

}

pthread_mutex_lock(&mutex1);

mtx1=7;

pthread_mutex_unlock(&mutex1);

break;

}

}

pthread_mutex_lock(&mutex2);

switch (mtx2)

{

case 1:

ot=5;

error_pol_goto(write(des,&ot,sizeof(int)),"Error",the_end);

error_pol_goto(write(des,&hx,sizeof(int)),"Error",the_end);

error_pol_goto(write(des,&hy,sizeof(int)),"Error",the_end);

error_pol_goto(read(des,&ot,sizeof(int)),"Error",the_end);

b=1;

while (b)

{

pthread_mutex_lock(&mutex1);

if (mtx1==0) b=0;

pthread_mutex_unlock(&mutex1);

}

if (ot==6)

{

pthread_mutex_lock(&mutex1);

mtx1=1;

pthread_mutex_unlock(&mutex1);

}

mtx2=0;

och=0;

break;

case 2:

ot=6;

write(des,&ot,sizeof(int));

mtx2=0;

pthread_mutex_lock(&mutex1);

mtx1=2;

pthread_mutex_unlock(&mutex1);

break;

case 3:

ot=4;

error_pol_goto(write(des,&ot,sizeof(int)),"Error",the_end);

ot=strlen(buffer)-1;

error_pol_goto(write(des,&ot,sizeof(int)),"Error",the_end);

error_pol_goto(write(des,buffer,ot),"Error",the_end);

mtx2=0;

break;

}

pthread_mutex_unlock(&mutex2);

}

the_end:;

pthread_mutex_lock(&mutex1);

mtx1=4;

pthread_mutex_unlock(&mutex1);

return 0;

}

int main(int argc, char **argv)

{

char ip_serv[15],ch;

int n_port=7777,sockfd,n,k_list,pn,t,b;

struct sockaddr_in servaddr;

struct menu_type *list;

pthread_t tid;

keys k;

if (initic()==-1)

return -1;

getscreensize(&maxy,&maxx);

signal(SIGWINCH,handler);

strcpy(ip_serv,"127.0.0.1\0");

com_str(argc,argv,ip_serv,&n_port);

error_1_return(sockfd = socket(AF_INET, SOCK_STREAM, 0)," ",-1);

bzero(&servaddr, sizeof(servaddr));

servaddr.sin_family = AF_INET;

servaddr.sin_port = htons(n_port);

error_pol_return(inet_pton(AF_INET,ip_serv,&servaddr.sin_addr)," ",-1);

error_1_return(connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr))," ",-1);

read(sockfd,&k_list,sizeof(int));

list=calloc(k_list,sizeof(struct menu_type));

read(sockfd,list,k_list*sizeof(struct menu_type));

strncpy(list[0].ip,"Создать игру\0",MAX_CH_IP);

strcpy(list[k_list-1].ip,"Обновление списка\0");

mytermsave();

mytermregime(0, 0, 1, 0, 1);

setcursor(0);

if (maxy<=32 || maxx<=54)

{

mytermrestore();

setcursor(1);

printf("Недостаточный размер окна\n");

return -1;

}

while (1)

{

pn=menu(list,(int)maxx/2-MAX_CH_IP/2-1,(int)maxy/2-k_list/2-1,k_list,MAX_CH_IP);

if (pn==-1)

{

t=6;

write(sockfd,&t,sizeof(int));

close(sockfd);

clrscr();

mytermrestore();

setcursor(1);

return 0;

}

if (pn==0)

{

t=2;

write(sockfd,&t,sizeof(int));

read(sockfd,&t,sizeof(int));

if (t==2)

{

clrscr();

och=1;

read(sockfd,&t,sizeof(int));

printf("Игра %d созданна, ожидание второго игрока\n",t);

break;

}

else

{

clrscr();

printf("Ошибка, игра не созданна\n");

readkey(&k);

continue;

}

}

if (pn==k_list-1)

{

t=1;

write(sockfd,&t,sizeof(int));

read(sockfd,&k_list,sizeof(int));

list=realloc(list,k_list*sizeof(struct menu_type));

read(sockfd,list,k_list*sizeof(struct menu_type));

strncpy(list[0].ip,"Создать игру\0",MAX_CH_IP);

strcpy(list[k_list-1].ip,"Обновление списка\0");

continue;

}

t=3;

write(sockfd,&t,sizeof(int));

write(sockfd,&list[pn].id,sizeof(int));

n=read(sockfd,&t,sizeof(int));

if (t==3)

{

och=0;

break;

}

else

{

clrscr();

printf("Ошибка присоединения к игре\n");

readkey(&k);

continue;

}

}

mytermrestore();

setcursor(1);

if (och)

{

read(sockfd,&t,sizeof(int));

if (t!=4)

{

clrscr();

printf("Ошибка\n");

mytermrestore();

setcursor(1);

return -1;

}

strcpy(message[0],"ваш ход\0");

sign_cl=CROSS;

}

else

{

sign_cl=ZERO;

strcpy(message[0],"ожидание хода противника\0");

}

clrscr();

mytermsave();

mytermregime(0,5,0,0,1);

setcursor(0);

ris();

pthread_mutex_init(&mutex1,NULL);

pthread_mutex_init(&mutex2,NULL);

error_no0_return(pthread_create(&tid,NULL,con_ser,(void *)sockfd),"Error potok",-1);

while (1)

{

mytermregime(0,5,0,0,1);

n=Readkey(&k,&ch);

if (n==1)

switch (k)

{

case K_UP:

if (y > 0)

{

--y;

printBoard(cletka,x,y);

}

break;

case K_DOWN:

if (y < 2)

{

++y;

printBoard(cletka,x,y);

}

break;

case K_LEFT:

if (x > 0)

{

--x;

printBoard(cletka,x,y);

}

break;

case K_RIGHT:

if (x < 2)

{

++x;

printBoard(cletka,x,y);

}

break;

case K_F6:

reg=0;

ris();

read(INPUT_STREAM,buffer,MAXLINE);

gotoXY(35,31);

mytermregime(1,0,0,1,1);

setcursor(1);

if (read(INPUT_STREAM,buffer,MAXLINE)!=0)

{

b=1;

while (b)

{

pthread_mutex_lock(&mutex2);

if (mtx2==0) b=0;

pthread_mutex_unlock(&mutex2);

}

pthread_mutex_lock(&mutex2);

mtx2=3;

pthread_mutex_unlock(&mutex2);

add_str(buffer,1);

}

mytermregime(0,5,0,0,1);

setcursor(0);

reg=1;

ris();

break;

case K_ESC:

b=1;

while (b)

{

pthread_mutex_lock(&mutex2);

if (mtx2==0) b=0;

pthread_mutex_unlock(&mutex2);

}

pthread_mutex_lock(&mutex2);

mtx2=2;

pthread_mutex_unlock(&mutex2);

break;

case K_ENTER:

getBoardPos(cletka,x,y,&sign);

if (och&&sign==EMPTY)

{

b=1;

while (b)

{

pthread_mutex_lock(&mutex2);

if (mtx2==0) b=0;

pthread_mutex_unlock(&mutex2);

}

pthread_mutex_lock(&mutex2);

mtx2=1;

hx=x;

hy=y;

pthread_mutex_unlock(&mutex2);

}

default: break;

}

pthread_mutex_lock(&mutex1);

switch (mtx1)

{

case 1:

strcpy(message[0],"ожидание хода противника\0");

setBoardPos(cletka,hx,hy,sign_cl);

printBoard(cletka,x,y);

ris();

mtx1=0;

break;

case 2:

mtx1=0;

goto the_end;

break;

case 3:

if (sign_cl==CROSS)

setBoardPos(cletka,hx,hy,ZERO);

else

setBoardPos(cletka,hx,hy,CROSS);

strcpy(message[0],"ваш ход\0");

printBoard(cletka,x,y);

ris();

och=1;

mtx1=0;

break;

case 4:

mtx1=0;

pthread_mutex_unlock(&mutex1);

goto the_end;

break;

case 5:

mtx1=0;

strcpy(message[0],"вы победили\0");

ris();

mytermregime(0,0,1,0,1);

readkey(&k);

clrscr();

break;

case 6:

mtx1=0;

strcpy(message[0],"вы проиграли\0");

ris();

mytermregime(0,0,1,0,1);

readkey(&k);

clrscr();

break;

case 7:

mtx1=0;

strcpy(message[0],"выиграла дружба\0");

ris();

mytermregime(0,0,1,0,1);

readkey(&k);

clrscr();

break;

case 8:

mtx1=0;

add_str(buffer,0);

ris();

break;

}

pthread_mutex_unlock(&mutex1);

}

the_end:;

close(sockfd);

mytermrestore();

setcursor(1);

clrscr();

return 0;

}

Исходный код server.c

#include <stdio.h>

#include <stdlib.h>

#include <errno.h>

#include <getopt.h>

#include <sys/time.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <arpa/inet.h>

#include <errno.h>

#include <string.h>

#include <unistd.h>

#include <fcntl.h>

#include <pthread.h>

#include <time.h>

#include "board.h"

#include "error.h"

struct games_info{

char ch_ip1[MAX_CH_IP],ch_ip2[MAX_CH_IP],bufer[MAXLINE];

int connfd1,connfd2,id,mtx1,mtx2,oc,x,y,b;

pthread_mutex_t mutex1,mutex2;

board cletka;

} *games;

struct client_info

{

char ch_ip[MAX_CH_IP];

int connfd;

};

int listenfd,connfd,max_count_game=1,n_port=7777,ID=1;

static pthread_mutex_t mutex_list_games;

int com_str(int argc, char **argv,int *cg,int *pr)

{

const char* short_options = "g:p:";

const struct option long_options[] =

{

{"count-games",required_argument,NULL,200},

{"game-server-port",required_argument,NULL,201},

{NULL,0,NULL,0}

};

int rez;

int option_index;

while ((rez=getopt_long(argc,argv,short_options,long_options,&option_index))!=-1)

{

switch(rez)

{

case 200:

case 'g':

{

if (optarg!=NULL)

{

*cg=atoi(optarg);

if (*cg<=0)

{

printf("chisl\n");

return -1;

}

}

break;

}

case 201:

case 'p':

{

if (optarg!=NULL)

{

*pr=atoi(optarg);

if (*pr<=0)

{

printf("chisl\n");

return -1;

}

}

break;

}

}

}

return 0;

}

void creat_list(struct menu_type mas[],int *kol)

{

int i=1,k=0;

char pnkt1[]="Создать игру\0",pnkt2[]="Обновление списка\0";

pthread_mutex_lock(&mutex_list_games);

mas[k].id=-1;

strncpy(mas[k].ip,pnkt1,MAX_CH_IP);

k=1;

for (i=0;i<max_count_game;i++)

if (games[i].connfd1!=-1&&games[i].connfd2==-1)

{

strcpy(mas[k].ip,games[i].ch_ip1);

mas[k].id=games[i].id;

k++;

}

mas[k].id=-2;

strncpy(mas[k].ip,pnkt2,MAX_CH_IP);

*kol=k;

pthread_mutex_unlock(&mutex_list_games);

}

void *work_with_client(void *arg)

{

struct client_info *inf=(struct client_info *) arg;

int g,k,n,ot,b=1,t,oc,i,j,hod=0;

struct menu_type *mas;

fd_set readset;

struct timeval timeout;

mas=calloc(max_count_game+2,sizeof(struct menu_type));

creat_list(mas,&k);

k++;

error_pol_return(write(inf->connfd,&k,sizeof(int)),"Error",0);

error_pol_return(write(inf->connfd,mas,sizeof(struct menu_type)*k),"Error",0);

while (b)

{

error_pol_return(read(inf->connfd,&ot,sizeof(ot)),"Error",0);

switch (ot)

{

case 1://zapros

creat_list(mas,&k);

k++;

error_pol_return(write(inf->connfd,&k,sizeof(k)),"Error",0);

error_pol_return(write(inf->connfd,mas,sizeof(struct menu_type)*k),"Error",0);

break;

case 2://creat game

pthread_mutex_lock(&mutex_list_games);

for (i=0;i<max_count_game;i++)

if (games[i].connfd1==-1&&games[i].connfd2==-1)

{

g=i;

pthread_mutex_unlock(&games[g].mutex1);

pthread_mutex_unlock(&games[g].mutex2);

t=2;

error_pol_return(write(inf->connfd,&t,sizeof(int)),"Error",0);

t=g+1;

error_pol_return(write(inf->connfd,&t,sizeof(int)),"Error",0);

b=0;

games[i].id=ID++;

oc=1;

games[i].connfd1=inf->connfd;

games[g].mtx1=games[g].mtx2=0;

strcpy(games[i].ch_ip1,inf->ch_ip);

printf("Клиент %s создал игру\n",inf->ch_ip);

break;

}

pthread_mutex_unlock(&mutex_list_games);

if (i==max_count_game)

{

t=-2;

error_pol_return(write(inf->connfd,&t,sizeof(int)),"Error",0);

}

break;

case 3://connect game

error_pol_return(read(inf->connfd,&ot,sizeof(ot)),"Error",0);

pthread_mutex_lock(&mutex_list_games);

for (i=0;i<max_count_game;i++)

if (games[i].id==ot)

{

if (games[i].connfd2==-1)

{

games[i].connfd2=inf->connfd;

strcpy(games[i].ch_ip2,inf->ch_ip);

b=0;

oc=2;

games[i].oc=2;

g=i;

t=3;

error_pol_return(write(inf->connfd,&t,sizeof(int)),"Error",0);

pthread_mutex_lock(&games[g].mutex1);

games[g].mtx1=1;

pthread_mutex_unlock(&games[g].mutex1);

printf("Клиент %s подключился к игре %s\n",inf->ch_ip,games[i].ch_ip1);

}

else

{

t=-3;

error_pol_return(write(inf->connfd,&t,sizeof(int)),"Error",0);

}

break;

}

pthread_mutex_unlock(&mutex_list_games);

break;

case 6://disconnect

printf("Клиент %s отключился\n",inf->ch_ip);

return 0;

}

}

if (oc==1)

{

while (1)

{

errno=0;

fcntl(inf->connfd, F_SETFL, FNDELAY|fcntl(inf->connfd, F_GETFL, 0));

n=read(inf->connfd,&ot,sizeof(ot));

fcntl(inf->connfd, F_SETFL, ~FNDELAY&fcntl(inf->connfd, F_GETFL, 0));

if (errno!=11) goto the_end;

if (n>0&&ot==6)

{

printf("Клиент %s отключился\n",inf->ch_ip);

pthread_mutex_lock(&mutex_list_games);

games[g].connfd1=-1;

pthread_mutex_unlock(&mutex_list_games);

goto the_end;

}

pthread_mutex_lock(&games[g].mutex1);

if (games[g].mtx1==1)

{

t=4;

error_pol_return(write(inf->connfd,&t,sizeof(int)),"Error",0);

games[g].mtx1=0;

games[g].oc=1;

pthread_mutex_unlock(&games[g].mutex1);

break;

}

pthread_mutex_unlock(&games[g].mutex1);

}

}

for (i=0;i<2;i++)

for (j=0;j<2;j++)

games[g].cletka[i][j]=EMPTY;

games[g].mtx2=0;

while (1)

{

FD_ZERO(&readset);

FD_SET(inf->connfd,&readset);

timeout.tv_sec=0;

timeout.tv_usec=500;

fcntl(inf->connfd, F_SETFL, FNDELAY|fcntl(inf->connfd, F_GETFL, 0));

n=select(inf->connfd+1, &readset, NULL, NULL, &timeout);

fcntl(inf->connfd, F_SETFL, ~FNDELAY&fcntl(inf->connfd, F_GETFL, 0));

if (n>0)

{

read(inf->connfd,&ot,sizeof(ot));

switch (ot)

{

case 4://text

error_1_goto(read(inf->connfd,&t,sizeof(int)),"Error",the_end);

error_1_goto(read(inf->connfd,&games[g].bufer,t),"Error",the_end);

games[g].bufer[t]='\0';

if (oc==1)

{

pthread_mutex_lock(&games[g].mutex2);

games[g].mtx2=2;

pthread_mutex_unlock(&games[g].mutex2);

}

else

{

pthread_mutex_lock(&games[g].mutex1);

games[g].mtx1=2;

pthread_mutex_unlock(&games[g].mutex1);

}

break;

case 5://hod

if (games[g].oc==oc)

{

error_1_goto(read(inf->connfd,&t,sizeof(int)),"Error",the_end);

games[g].x=t;

error_1_goto(read(inf->connfd,&t,sizeof(int)),"Error",the_end);

games[g].y=t;

if (games[g].cletka[games[g].y][games[g].x]==EMPTY)

{

if (games[g].oc==1)

games[g].cletka[games[g].y][games[g].x]=CROSS;

else

games[g].cletka[games[g].y][games[g].x]=ZERO;

t=6;

error_pol_goto(write(inf->connfd,&t,sizeof(int)),"Error",the_end);

if (oc==1)

{

hod++;

pthread_mutex_lock(&games[g].mutex2);

games[g].oc=2;

games[g].mtx2=3;

pthread_mutex_unlock(&games[g].mutex2);

}

else

{

pthread_mutex_lock(&games[g].mutex1);

games[g].oc=1;

games[g].mtx1=3;

pthread_mutex_unlock(&games[g].mutex1);

}

tPosSign sign;

if (victory(games[g].cletka,&sign,&t,&t))

{

if (games[g].oc==2)

printf("Клиент %s победил %s\n",games[g].ch_ip1,games[g].ch_ip2);

else

printf("Клиент %s победил %s\n",games[g].ch_ip2,games[g].ch_ip1);

if (sign==CROSS)

{

t=9;

error_pol_goto(write(inf->connfd,&t,sizeof(int)),"Error",the_end);

pthread_mutex_lock(&games[g].mutex2);

games[g].mtx2=4;

pthread_mutex_unlock(&games[g].mutex2);

goto the_end;

}

else

{

t=9;

error_pol_goto(write(inf->connfd,&t,sizeof(int)),"Error",the_end);

pthread_mutex_lock(&games[g].mutex1);

games[g].mtx1=4;

pthread_mutex_unlock(&games[g].mutex1);

goto the_end;

}

goto the_end;

}

else

if (hod==5)

{

printf("Клиенты %s,%s сыграли вничью\n",games[g].ch_ip1,games[g].ch_ip2);

t=11;

error_pol_goto(write(inf->connfd,&t,sizeof(int)),"Error",the_end);

pthread_mutex_lock(&games[g].mutex2);

games[g].mtx2=6;

pthread_mutex_unlock(&games[g].mutex2);

goto the_end;

}

}

else

{

t=-6;

error_pol_goto(write(inf->connfd,&t,sizeof(int)),"Error",the_end);

}

}

break;

case 6://disconnect

if (oc==1)

{

pthread_mutex_lock(&games[g].mutex2);

games[g].mtx2=5;

pthread_mutex_unlock(&games[g].mutex2);

}

else

{

pthread_mutex_lock(&games[g].mutex1);

games[g].mtx1=5;

pthread_mutex_unlock(&games[g].mutex1);

}

goto the_end;

break;

}

}

if (oc==1)

{

pthread_mutex_lock(&games[g].mutex1);

if (games[g].mtx1!=0)

{

switch (games[g].mtx1)

{

case 2://text

t=5;

error_pol_goto(write(inf->connfd,&t,sizeof(int)),"Error",the_end);

t=strlen(games[g].bufer);

error_pol_goto(write(inf->connfd,&t,sizeof(int)),"Error",the_end);

error_pol_goto(write(inf->connfd,&games[g].bufer,t),"Error",the_end);

break;

case 3://hod prot

t=7;

error_pol_goto(write(inf->connfd,&t,sizeof(int)),"Error",the_end);

error_pol_goto(write(inf->connfd,&games[g].x,sizeof(int)),"Error",the_end);

error_pol_goto(write(inf->connfd,&games[g].y,sizeof(int)),"Error",the_end);

break;

case 4://fail

t=10;

error_pol_goto(write(inf->connfd,&t,sizeof(int)),"Error",the_end);

goto the_end;

break;

case 5://disconnect

t=8;

error_pol_goto(write(inf->connfd,&t,sizeof(int)),"Error",the_end);

goto the_end;

break;

case 6://nichia

t=11;

error_pol_goto(write(inf->connfd,&t,sizeof(int)),"Error",the_end);

goto the_end;

break;

}

}

games[g].mtx1=0;

pthread_mutex_unlock(&games[g].mutex1);

}

else

{

pthread_mutex_lock(&games[g].mutex2);

if (games[g].mtx2!=0)

{

switch (games[g].mtx2)

{

case 2://text

t=5;

error_pol_goto(write(inf->connfd,&t,sizeof(int)),"Error1",the_end);

t=strlen(games[g].bufer);

games[g].bufer[t]='\0';

error_pol_goto(write(inf->connfd,&t,sizeof(int)),"Error2",the_end);

error_pol_goto(write(inf->connfd,&games[g].bufer,t),"Error3",the_end);

break;

case 3://hod prot

t=7;

error_pol_goto(write(inf->connfd,&t,sizeof(int)),"Error",the_end);

error_pol_goto(write(inf->connfd,&games[g].x,sizeof(int)),"Error",the_end);

error_pol_goto(write(inf->connfd,&games[g].y,sizeof(int)),"Error",the_end);

break;

case 4://fail

t=10;

error_pol_goto(write(inf->connfd,&t,sizeof(int)),"Error",the_end);

goto the_end;

break;

case 5://fail

t=8;

error_pol_goto(write(inf->connfd,&t,sizeof(int)),"Error",the_end);

goto the_end;

break;

case 6://nichia

t=11;

error_pol_goto(write(inf->connfd,&t,sizeof(int)),"Error",the_end);

goto the_end;

break;

}

}

games[g].mtx2=0;

pthread_mutex_unlock(&games[g].mutex2);

}

}

the_end:;

if (oc==1)

{

t=8;

printf("Клиент %s отключился\n",games[g].ch_ip1);

write(games[g].connfd1,&t,sizeof(int));

if (games[g].connfd1!=-1)

close(games[g].connfd1);

pthread_mutex_lock(&mutex_list_games);

games[g].connfd1=-1;

pthread_mutex_unlock(&mutex_list_games);

games[g].mtx1=0;

b=1;

while (b)

{

pthread_mutex_lock(&games[g].mutex2);

if (games[g].mtx2==0) b=0;

pthread_mutex_unlock(&games[g].mutex2);

}

pthread_mutex_lock(&games[g].mutex2);

games[g].mtx2=5;

pthread_mutex_unlock(&games[g].mutex2);

return 0;

}

else

{

t=8;

printf("Клиент %s отключился\n",games[g].ch_ip2);

write(games[g].connfd2,&t,sizeof(int));

if (games[g].connfd2!=-1)

close(games[g].connfd2);

pthread_mutex_lock(&mutex_list_games);

games[g].connfd2=-1;

pthread_mutex_unlock(&mutex_list_games);

games[g].mtx2=0;

b=1;

while (b)

{

pthread_mutex_lock(&games[g].mutex1);

if (games[g].mtx1==0) b=0;

pthread_mutex_unlock(&games[g].mutex1);

}

pthread_mutex_lock(&games[g].mutex1);

games[g].mtx1=5;

pthread_mutex_unlock(&games[g].mutex1);

return 0;

}

}

int main(int argc, char **argv)

{

unsigned int len;

struct client_info *temp;

struct sockaddr_in servaddr,clnaddr;

char adr[15]/*,port[5]*/;

pthread_t tid;

int i;

com_str(argc,argv,&max_count_game,&n_port);

if (max_count_game<1)

{

printf("Error count game\n");

return -1;

}

error_0_return(games=calloc(max_count_game,sizeof(struct games_info)),"Memory",-1);

for (i=0;i<max_count_game;i++)

{

pthread_mutex_init(&games[i].mutex1,NULL);

pthread_mutex_init(&games[i].mutex2,NULL);

games[i].connfd1=games[i].connfd2=-1;

games[i].mtx1=games[i].mtx2=0;

}

listenfd=socket(AF_INET,SOCK_STREAM,0);

bzero(&servaddr,sizeof(servaddr));

servaddr.sin_family=AF_INET;

servaddr.sin_addr.s_addr=htonl(INADDR_ANY);

servaddr.sin_port=htons(n_port);

error_1_return(bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr))," ",-1);

error_1_return(listen(listenfd, 1)," ",-1);

len=sizeof(clnaddr);

pthread_mutex_init(&mutex_list_games,NULL);

while (1)

{

error_1_continue(connfd=accept(listenfd,(struct sockaddr *) &clnaddr,&len)," ");

temp=malloc(sizeof(struct client_info));

inet_ntop(AF_INET,(struct sockaddr *) &clnaddr.sin_addr.s_addr, adr, 15);

snprintf(temp->ch_ip,MAX_CH_IP,"%s:%d",adr,ntohs(clnaddr.sin_port));

printf("Клиент %s присоединился\n",temp->ch_ip);

temp->connfd=connfd;

error_no0_continue(pthread_create(&tid,NULL,work_with_client,(void *)temp),"Error potok");

}

close(connfd);

return 0;

}

Наши рекомендации