- •Задание на курсовую работу.
- •Правила игры.
- •Описание протокола.
- •Общая схема работы клиента.
- •Общая схема работы сервера.
- •Разбор опций командной строки.
- •Описание реализации протокола на сервере.
- •Описание реализации протокола на клиенте.
- •Описание пользовательского интерфейса клиента.
- •Исходный код board.H
- •Исходный код board.C
- •Исходный код client.C
- •Исходный код server.C
Исходный код 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;
}