Описание реализации протокола на сервере.
После создания прослушивающего сокета, сервер входит в цикл приёма соединения:
В случае если происходит подключение нового клиента, выполняется тело цикла, в котором необходимо записать информацию о клиенте (дескриптор и 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;
}