想拿走即可运行的同学请严格按照我的目录结构准备好文件夹和文件
拷贝完成后将wuziqi.h文件中的IP地址改为自己linux的IP
ifconfig // Linux终端下查看本机IP地址
suto spt install net-tools // 上面不行的话先执行这条命令,再执行ifconfig
上述都完成后在linux终端在wuziqi目录下make即可启动服务端,这个时候bin目录下会有客户端的可执行文件,将其发给局域网内的其他电脑,添加可执行权限执行,就可以对战了
chmod 0777 wzq_client // 该命令加可执行权限
./wzq_client //执行
若是报thread的错误请执行下面的两条命令,make不报错的略过
sudo apt-get install glibc-doc
#man手册
sudo apt-get install manpages-posix manpages-posix-dev
下面按文件夹发代码,一共7个文件注意别粘贴错了!!!
首先是wuziqi目录下的Makefile文件
OBJS:=net.o server.o client.o
OBJSSER:=net.o server.o
OBJSCLI:=net.o client.o
APP:=wzq_server wzq_client
FLAGS:=-g -c
CC:=gcc
export OBJS APP FLAGS CC OBJSSER OBJSCLI
ALL:
make -C ./src
make -C ./obj
./bin/wzq_server
.PHONY:clean
clean:
$(RM) ./obj/*.o
$(RM) ./bin/*
其次是src目录下的Makefile
ALL:$(OBJS)
mv $^ ../obj
net.o:net.c
$(CC) $(FLAGS) $< -o $@ -lpthread
server.o:server.c
$(CC) $(FLAGS) $< -o $@ -lpthread
client.o:client.c
$(CC) $(FLAGS) $< -o $@ -lpthread
login.o:login.c
$(CC) $(FLAGS) $< -o $@ -lpthread
obj目录下的Makefile
ALL:$(APP)
mv $^ ../bin
wzq_server:$(OBJSSER)
$(CC) $^ -o $@ -lpthread
wzq_client:$(OBJSCLI)
$(CC) $^ -o $@ -lpthread
include目录下的wuziqi.h文件
#ifndef _WUZIQI_H
#define _WUZIQI_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define DEFAULT_PORT 12345 // 端口号
#define DEFAULT_IP "192.168.0.103" // 服务器IP地址
#define MAXSIZE 128 // 缓冲区默认大小
#define MAXLISTEN 50 // 默认最大监听数
#define MAXTHREADCOUNT 20 // 最大线程数
#define INIT_BLOAD 15 // 默认15×15的棋盘
#define MAXFILECOUNT 1024 // 最大监听数
// 设置结构体
void fun_sockaddr(struct sockaddr_in * addr);
// 初始化棋盘
void bload_Init(char key[][INIT_BLOAD]);
// 展示棋盘
void show(char key[][INIT_BLOAD], int key_x, int key_y, char ch);
// 判断坐标是否有效,并解析坐标
int isExists(char buf[], int xy[3], char key[][INIT_BLOAD], char ch);
// 判断是否胜利
int isWin(char key[][INIT_BLOAD], int x, int y);
int direction(char key[][INIT_BLOAD], int x, int y, int dire);
// 获取棋子
char getButtn();
// 先手
void firstBload(int *sockfd, struct sockaddr_in *cliaddr, char ch);
// 后手
void secondBload(int* sockfd, struct sockaddr_in* cliaddr, char ch);
// 服务器中介两客户端交互
int response(int conn[]);
//void* response_chilrd(void* conn);
// 服务器socket
void fun_serversock(int *listenfd, struct sockaddr_in *servaddr);
// 客户端socket
void fun_sock(struct sockaddr_in * cliaddr, int *sockfd);
// 封装
void send_buf(int *butn, char id[], char pass[], char buff[]);
// 拆箱
void recv_buf(int *butn, char id[], char pass[], char buff[]);
#endif
src目录下的net.c文件
#include "../include/wuziqi.h"
// 客户端socket
void fun_sock(struct sockaddr_in * cliaddr, int *sockfd)
{
*sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(*sockfd < 0){
printf("socket error! \n");
exit(-1);
}
fun_sockaddr(cliaddr);
}
// 服务器socket
void fun_serversock(int *listenfd, struct sockaddr_in *servaddr)
{
// 建立socket链接
*listenfd = socket(AF_INET, SOCK_STREAM, 0);
if(listenfd < 0){
printf("socket error!\n");
exit(0);
}
printf("listenfd = %d\n", listenfd);
fun_sockaddr(servaddr);
if(bind(*listenfd, (struct sockaddr*)servaddr, sizeof(struct sockaddr_in))<0){
perror("bind error");
exit(0);
}
printf("bind successful!\n");
if(listen(*listenfd, MAXLISTEN) < 0){
perror("listen error");
exit(0);
}
printf("listening...\n");
}
// 设置结构体参数
void fun_sockaddr(struct sockaddr_in * servaddr){
servaddr->sin_family = AF_INET;
servaddr->sin_port = htons(DEFAULT_PORT);
servaddr->sin_addr.s_addr = inet_addr(DEFAULT_IP);
}
// 初始化棋盘
void bload_Init(char key[][INIT_BLOAD])
{
if(key == NULL) return;
for(int i = 0; i < INIT_BLOAD; ++i){
for(int j = 0; j < INIT_BLOAD; ++j){
key[i][j] = '*';
}
}
printf("\n |");
printf("ˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉ");
printf("|\n");
printf(" |0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 |\n");
for(int i = 0; i < INIT_BLOAD; ++i){
printf("%-2d|", i);
for(int j = 0; j < INIT_BLOAD; ++j){
printf("%c ", key[i][j]);
}
printf("|%-2d\n", i);
}
printf(" |0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 |\n");
printf(" |______________________________|\n");
}
// 展示棋盘
void show(char key[][INIT_BLOAD], int key_x, int key_y, char ch)
{
if(key_x == -1 && key_y == -1){
return;
}
key[key_x][key_y] = ch;
printf("\n |");
printf("ˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉ");
printf("|\n");
printf(" |0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 |\n");
for(int i = 0; i < INIT_BLOAD; ++i){
printf("%-2d|", i);
for(int j = 0; j < INIT_BLOAD; ++j){
printf("%c ", key[i][j]);
}
printf("|%-2d\n", i);
}
printf(" |0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 |\n");
printf(" |______________________________|\n");
}
// 判断坐标, -1坐标有误,1落子成功,2胜利,-3该位置有棋子
int isExists(char buf[], int dire[3], char key[][INIT_BLOAD], char ch)
{
if(buf == NULL || key == NULL) return -1;
buf[strlen(buf)-1] = ';'int
[ xy2]= - {1,- 1};int
= pos 0 ;for
(int= i 0 ;< i ; MAXSIZE++ )iif{
([buf]i== ')' || [ buf]i== '||' [ ] buf==i'-' ) break;{
}if
(
[]buf'0'i&& >= [ ] buf<=i'9' ) if({
[+buf1i]<'0' || [ + buf1i]'9') > []{
xy=pos[ ] buf-i'0' ; }else
[
]{
xy=pos[ ] buf-i'0' ; []
xy=pos[ ] xy*pos10+( [ +buf1i]-'0' ) ;++;
}i++
;
}pos}
if
(
([0xy]<0 || [ 0 xy])|| >= INIT_BLOAD(
[ 1xy]<0 || [ 1 xy])) >= INIT_BLOADreturn-{
1 ;}else
if
( [[key0xy]][[1xy]]!='*' ) return-{
3 ;}else
[
0{
dire]=[ 0 xy];[1
dire]=[ 1 xy];[2
dire]=; [ ch[
key0dire]][[1dire]]=[ 2 dire];}if
(
isWin(,[key0 xy],[1 xy])==1 ) return2{
; }else
return
1{
; }}
// 判断是否胜利
int
isWin
( char[] key[],INIT_BLOADint, int x) if y(
{
1==direction ( ,,key, x1 y) )return1{
; }if
(
1==direction ( ,,key, x2 y) )return1{
; }if
(
1==direction ( ,,key, x3 y) )return1{
; }if
(
1==direction ( ,,key, x4 y) )return1{
; }return
0
; }// dire = 1左斜,2右斜,3横,4纵
int
direction
( char[] key[],INIT_BLOADint, int x, int y) char dire=
{
[ ch ] key[x];yint=
, i = x; j int y=
1 count ; switch(
)casedire1{
: while(
1)++,{
++i;ifj(
<0i || || < i > INIT_BLOAD 0 j || ) break j > INIT_BLOAD;{
}if
(
==[ch ] key[i])j++;{
}countelse
break;{
}}
=
,
i = x; j while x(
1)--,{
--i; ifj(
<0i || || < i > INIT_BLOAD 0 j || ) break j > INIT_BLOAD;{
}if
(
==[ch ] key[i])j++;{
}countelse
break;{
}}
break
;
case2
: while(
1)--,{
++i;ifj(
<0i || || < i >= INIT_BLOAD 0 j || ) break j >= INIT_BLOAD;{
}if
(
==[ch ] key[i])j++;{
}countelse
break;{
}}
=
,
i = x; j while y(
1)++,{
--i; ifj(
<0i || || < i >= INIT_BLOAD 0 j || ) break j >= INIT_BLOAD;{
}if
(
==[ch ] key[i])j++;{
}countelse
break;{
}}
break
;
case3
: while(
1)++;{
ifi(
<0i || ) break i >= INIT_BLOAD;{
}if
(
==[ch ] key[i])y++;{
}countelse
break;{
}}
=
;
i while x(
1)--;{
ifi(
<0i || ) break i >= INIT_BLOAD;{
}if
(
==[ch ] key[i])y++;{
}countelse
break;{
}}
break
;
case4
: while(
1)++;{
ifj(
<0j || ) break j >= INIT_BLOAD;{
}if
(
==[ch ] key[x])j++;{
}countelse
break;{
}}
=
;
j while y(
1)--;{
ifj(
<0j || ) break j >= INIT_BLOAD;{
}if
(
==[ch ] key[x])j++;{
}countelse
break;{
}}
break
;
default:
break; }if
(
5)count >= return1{
; }return
0
; }// 先手
void
firstBload
( int*, structsockfdsockaddr_in * , charcliaddr) printf ch(
{
"等待对手选择棋子...\n");recv(
*,&sockfd, 1ch, 0) ;char=
- temp_ch 2 ;printf(
"对方选择了 %c \n",); ch// 获取棋子while
(
1 )=getButtn{
temp_ch ( );if(
==)temp_ch printf ch({
"该棋子已被对手选定,请您重新挑选棋子...\n");}else
break;{
}}
=
;
ch send temp_ch(
*,&sockfd, 1ch, 0) ;printf(
"已选中 %C \n",); chchar[
] buff=MAXSIZE0 } {;char[
] key[INIT_BLOAD]=INIT_BLOAD0 } {;system(
"clear");bload_Init(
);key// 初始化棋盘int[
3 xy]=- 1 {,-1 ,-1 };// 存放坐标和棋子printf (
"您是先手,请您先落子...\n");// 业务处理while
(
1)[0{
xy]=- 1 ,[1 xy]=- 1 ,[2 xy]=- 1 ;bzero(
,)buff; MAXSIZEfgets(
,,buffstdin MAXSIZE) ;// 获取坐标int=
isExists flag ( ,,buff, xy) key; chif(
==1flag ) // 落子成功}{
else
if( ==-flag 1 )printf({
"坐标有误!\n");continue;
}else
if( ==2flag ) printf({
"```恭喜您胜出!\n");[0
xy]=- 1 ,[1 xy]=- 1 ,[2 xy]=- 8 ;send(
*,,sockfdsizeof xy( ),xy0) ;break;
}else
if( ==-flag 3 )printf({
"当前位置已有棋子...\n");continue;
}system
(
"clear");if(
send(*,,sockfdsizeof xy( ),xy0) ==- 1 )// 发送坐标printf(
{
"落子失败,请重新落子!\n");continue;
}show
(
,[key0 xy],[1 xy],); chprintf(
"等待对方落子...\n");if(
recv(*,,sockfdsizeof xy( ),xy0) ==- 1 )perror({
"recv error");break;
}if
(
[2xy]==- 9 )printf({
"对放已逃跑\n```恭喜您胜出!```\n");break;
}else
if( [2xy]==- 8 )printf({
"```你输了```\n");break;
}system
(
"clear");show(
,[key0 xy],[1 xy],(char )[2xy]);printf(
"轮到您落子...\n");}}
// 后手
void
secondBload
( int*,struct sockfdsockaddr_in * ,char cliaddr) = chgetButtn
{
ch ( );send(
*,&sockfd, 1ch, 0) ;char[
] buff=MAXSIZE0 } { ; char[
] key[INIT_BLOAD]=INIT_BLOAD0 } { ; system(
"clear");bload_Init(
);key// 初始化棋盘int[
3 xy]=- 1 { ,-1 ,-1 }; // 存放坐标和棋子printf (
"您是后手,请等待对手落子...\n");// 业务处理while
(
1 )[0 {
xy]=- 1 ,[1 xy]=- 1 ,[2 xy]=- 1 ;bzero(
,)buff; MAXSIZEif(
recv (*,,sockfdsizeof xy( ),xy0) ==- 1 )perror( {
"recv error");continue;
}if
(
[ 2xy]==- 9 )printf( {
"对放已逃跑\n```恭喜您胜出!```\n");break;
}else
if
( [ 2xy]==- 8 )printf( {
"```你输了```\n");break;
}:
system
lp(
"clear");show(
,[key0 xy],[1 xy],[2 xy]);printf(
"轮到您落子...\n");fgets(
,,buffstdin MAXSIZE) ;// 获取坐标int=
isExists flag ( ,,buff, xy) key; chif(
== 1flag ) // 落子成功} {
else
if
( == -flag 1 )printf( {
"坐标有误!\n");goto;
} lpelse
if
( == 2flag ) printf( {
"```恭喜您胜出!\n");[0
xy]=- 1 ,[1 xy]=- 1 ,[2 xy]=- 8 ;send(
*,,sockfdsizeof xy( ),xy0) ;break;
}else
if
( == -flag 3 )printf( {
"当前位置已有棋子...\n");goto;
} lpsystem
(
"clear");if(
send (*,,sockfdsizeof xy( ),xy0) ==- 1 )// 发送坐标printf(
{
"落子失败,请重新落子!\n");goto;
} lpshow
(
,[key0 xy],[1 xy],); chprintf(
"等待对方落子...\n");}}
// 获取棋子
char
getButtn
( )int=
{
- flag 1 ;:printf
lp(
"1:@;2:#;3:A;4:B;5:X;6:Q;7:$;8:&\n");printf(
"请选择棋子皮肤\n");scanf(
"%d",&) ;flagswitch(
) caseflag1 {
: return'@' ; case2
: return'#' ; case3
: return'A' ; case4
: return'B' ; case5
: return'X' ; case6
: return'Q' ; case7
: return'$' ; case8
: return'&' ; default:
printf( "对不起,没有这个棋子!请重新选择...\n");goto;
} lp}
// 简易线程池
// int response(int conn[])
// pthread_t pits[10];
// //pthread_create(&pits[i], );
// {
// }
// for(int i = 0; i < 10; ++i){
// }
// 服务器中介两客户端交互
int
response
( int[] conns)int=
{
0 flag ; // 0先手,1后手int=
- dire 1 ;// 标记先手 0表示conns[0]先手 1表示conns[1]先手char [
] buf=MAXSIZE0 } {;int=
rand ran ( )%10;// 随机获取一个0-9的数字if (
%2ran == 0 ) // conns[0] 先手send{(
[0conns],&, 4flag, 0) ;++;
sendflag(
[1conns],&, 4flag, 0) ;=0
dire ; }else
// conns[1] 先手
send{(
[1conns],&, 4flag, 0) ;++;
sendflag(
[0conns],&, 4flag, 0) ;=1
dire ; }if
(
==1dire ) // 始终保证conns[0]是先手int{ =
[ temp 0 conns];[0
conns]=[ 1 conns];[1
conns]=; } tempchar
[
2 piece]=- 1 {,-1 };// 存放双方棋子recv (
[1conns],&[ 1piece],1, 0) ;// 后手先选send(
[0conns],&[ 1piece],1, 0) ;// 将棋子发送给先手,告诉先手不要重复选择recv(
[0conns],&[ 0piece],1, 0) ;// 先手选棋子int[
3 xy]=- 1 {,-1 ,-1 };// 对战开始while
(
1)[0{
xy]=- 1 ,[1 xy]=- 1 ,[2 xy]=- 1 ;if(
recv ([0conns],,sizeof xy( ),xy0) ==- 1 )perror( {
"recv error");continue;
}if
(
[ 2xy]==- 9 )send( {
[1conns],,sizeof xy( ),xy0) ;break;
}else
if
( [ 2xy]==- 8 )send( {
[1conns],,sizeof xy( ),xy0) ;break;
}send
(
[1conns],,sizeof xy( ),xy0) ;[0
xy]=- 1 ,[1 xy]=- 1 ,[2 xy]=- 1 ;:if
recv(
recv ([1conns],,sizeof xy( ),xy0) ==- 1 )perror( {
"recv error");goto;
} recvif
(
[ 2xy]==- 9 )send( {
[0conns],,sizeof xy( ),xy0) ;break;
}else
if
( [ 2xy]==- 8 )send( {
[0conns],,sizeof xy( ),xy0) ;break;
}send
(
[0conns],,sizeof xy( ),xy0) ;}return
-
1 ;}#
include
src目录下的server.c文件
"../include/wuziqi.h"/*int llogin(int *fd)
{
int i = *fd;
int butn = -1;
char id[128] = {0};
char pass[16] = {0};
char temp[128] = {0};
recv(i, &butn, 4, 0);
if (butn == 1)
{ // 登录
recv(i, id, 128, 0);
recv(i, pass, 16, 0);
int ll = login_db(id, temp);
if (strcmp(temp, pass) == 0)
{ // 登录成功
send(i, &butn, 4, 0);
return 1;
}
else if (ll == -2)
{
butn = -2;
send(i, &butn, 4, 0);
}
else
{
butn = -1;
send(i, &butn, 4, 0);
}
}
else if (butn == 2)
{ // 注册
recv(i, id, 128, 0);
recv(i, pass, 16, 0);
int ff = insert_db(id, pass);
if (ff == 1)
{
send(i, &butn, 4, 0);
}
else
{
butn = -1;
send(i, &butn, 4, 0);
}
}
}*/ int
main
( )int,
{
; listenfdstruct connfdsockaddr_in
, ; servaddrsocklen_t cliaddr=
sizeof perrlen ( );cliaddrfun_serversock(
&,&listenfd) ;servaddrint=
0 sum_thread ; // 创建线程数,全局监控// 创建监听队列 ,
,
fd_set readfds; temp// 清空监听队列 loginningFD_ZERO
(
&);readfdsFD_ZERO(
&);tempFD_ZERO(
&);loginning// 将监听文件描述符加入到监听队列中FD_SET
(
,&listenfd) ;readfdschar[
] buff=MAXSIZE0 } {;int[
2 conns]=- 1 {,-1 };int=
0 pos ; while(
1 )=;
{
temp int readfds=
select ret ( ,&MAXFILECOUNT, NULLtemp, NULL, NULL) ;if(
< 0ret ) perror(
{
"select error");return-
1 ;}// 遍历监听队列
for
(
int =0 i ; <; i ++ MAXFILECOUNT) inti=
{
- flag 1 ;// 判断文件描述符是否在监听队列中if
(
FD_ISSET (,&i) )tempif(
{
== )i // 监听到新的连接 listenfd=
{ accept
connfd ( ,NULLlistenfd, NULL) ;//FD_SET(i, &readfds);[
++
conns]pos=; if connfd(
[ 1conns]!=- 1 )int[
{
2 temp_conns]=[ 0 {conns],[1 conns]};[0
conns]=- 1 ,[1 conns]=- 1 ;// 可以配对=
0
pos ; printf(
"配对成功\n");pid_t=
fork pid ( );if(
0 ==) int pid=
{
response n ( );temp_connsif(
< 0n ) //FD_CLR(temp_conns[0], &readfds); // 从消息队列中删除//FD_CLR(temp_conns[1], &readfds);
{
close
(
[0temp_conns]);close(
[1temp_conns]);}}
else
if
( 0 )pid > //wait(NULL);}
{
else
printf
(
{
"创建失败!\n");}}
}
else
}
}
{
}
}
close
(
);listenfdreturn0
; }#
include
src目录下的client.c文件
"../include/wuziqi.h"int main
( )structsockaddr_in
{
; int cliaddr;
fun_sock sockfd(
&,&cliaddr) ;sockfdif(
connect (,(sockfdstruct sockaddr* )&,sizeofcliaddr( ))cliaddr<0 ) perror( {
"connect error");return-
1 ;}printf
(
"connect successful!\n");int=
- flag 1 ;// 接收先后判断位printf (
"匹配中...\n");recv(
,&sockfd, 4flag, 0) ;printf(
"--匹配成功!%d\n",); flagif(
==0flag ) // 先手firstBload{
(
&,&sockfd, -cliaddr1 );}else
// 后手secondBload{
(
&,&sockfd, -cliaddr1 );}printf
(
"再次运行即可继续游戏!\n");close(
);sockfdreturn0
; }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)