技术专栏
tcp多人聊 天 室(支持断网重连)
先上代码:
客户端:
void thread1(void arg);
void thread2(void arg);
pthread_mutex_t lock;
typedef struct sockaddr_in SAI;
typedef struct sockaddr SA;
SAI ser_addr;
int socfd;
char clientname[20]={0};
unsigned char rbuff[1024]={0};
char wbuff[1024]={0};
int main(int argc,char argv[])
{
pthread_t tid1;
pthread_t tid2;
int connect_flag;
int w_len;
char buf[1024]={0};
pthread_mutex_init(&lock,NULL);
//create socket file
socfd=socket(AF_INET,SOCK_STREAM,0);
bzero(&ser_addr,sizeof(ser_addr));
//configure serve address infomation
ser_addr.sin_family = AF_INET;
ser_addr.sin_port = htons(SERVER_PORT);
ser_addr.sin_addr.s_addr = inet_addr(SERVER_IPADDR);
//set username
printf(“set username:”);
scanf(“%s”,clientname);
//connect to server
if(connect(socfd,(SA)&ser_addr,sizeof(ser_addr))==-1)
{
printf(“connect fail\n”);
return -1;
}
else{printf(“connect success\n”);}
write(socfd,clientname,sizeof(clientname));
//bzero(clientname,sizeof(clientname));
//create a thread
pthread_create(&tid1,NULL,thread1,NULL);
pthread_create(&tid2,NULL,thread2,NULL);
//send data
while(1)
{
scanf(“%s”,wbuff);
if(strncmp(wbuff,”quit”,4)==0)
{
close(socfd);
exit(0);
}
w_len=write(socfd,wbuff,sizeof(wbuff));
if(w_len<0)
{
printf(“%s write fail”,clientname);
}
bzero(wbuff,sizeof(wbuff));
}
close(socfd);
}
void thread1(void arg)
{
int r_len;
int w_len;
int tm=0;
int flag=0;
int jkl=0;
while(1)
{
//r_len=read(socfd,rbuff,sizeof(rbuff));
r_len=recv(socfd,rbuff,sizeof(rbuff),MSG_DONTWAIT);
if(r_len == 0)
{
//printf(“无数据\n”);
//perror(“recv data”);
//( “%s\n”, strerror( errno ));
}
if(r_len<0) { //perror("recv data"); } if(rbuff[0]==0x86&&rbuff[1]==0x06&&rbuff[2]==0x00&&rbuff[3]==0x86&&rbuff[4]==0x01&&rbuff[5]==0x12) { w_len=write(socfd,"alive",5); if(w_len<0) { printf("write fail"); } goto AA; } if(strncmp(rbuff,"salive",6)==0) { flag=0; goto AA; } else { flag++; if(flag>(10+3))
{
printf(“网络断开超一次心跳,准备重连\n”);
close(socfd);
socfd=socket(AF_INET,SOCK_STREAM,0);
jkl=connect(socfd,(SA*)&ser_addr,sizeof(ser_addr));
if(jkl==-1)
{
printf(“reconnect fail\n”);
close(socfd);
goto AA;
}
else
{
printf(“%s reconnect success\n”,clientname);
write(socfd,clientname,sizeof(clientname));
write(socfd,”alive(reconnect)”,16);
flag=0;
goto AA;
}
}
}
if(strlen(rbuff)==0)
{
goto AA;
}
printf(“%s\n”,rbuff);
AA://避免打印心跳包
bzero(rbuff,sizeof(rbuff));
sleep(1);
}
}
void thread2(void arg)
{
int w_len;
int jkl;
int tm=0;
char buf[1024]={0};
while(1)
{
//sleep(1);
w_len=write(socfd,”testonline”,10);
if(w_len<0)
{
printf(“write fail 188\n”);
}
bzero(buf,sizeof(buf));
sleep(10);
}
}
服务端:
void thread1(void arg);
void thread2(void arg);
void heartbeat(void arg);
pthread_mutex_t lock;
typedef struct sockaddr_in SAI;
typedef struct sockaddr SA;
SAI ser_addr,cli_addr;
int socfd;
int clifd_max = 0;
int clifd_min = 4;
pthread_t tid1[100]={0};
pthread_t tid2;
pthread_t tid3;
static int client_amount;
int main(int argc,char* argv[])
{
int r_len;
int on = 1;
int cliaddr_len;
int clifd;
cliaddr_len=sizeof(cli_addr);
pthread_mutex_init(&lock,NULL);
//create socket file
socfd=socket(AF_INET,SOCK_STREAM,0);
printf(“socfd:%d\n”,socfd);
bzero(&ser_addr,sizeof(ser_addr));
bzero(&cli_addr,sizeof(cli_addr));
//configure serve address infomation
ser_addr.sin_family = AF_INET;
ser_addr.sin_port = htons(SERVER_PORT);
ser_addr.sin_addr.s_addr = inet_addr(SERVER_IPADDR);
setsockopt(socfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
//bind address infomation with socket
if(bind(socfd,(SA*)&ser_addr,sizeof(ser_addr))==-1)
{
printf("bind fail\n");
return -1;
}
else{printf("bind success\n");}
//set listen queue
if(listen(socfd,LISTEN_Q_MAX)==-1)
{
printf("set listen queue fail\n");
return -1;
}
else{printf("set listen queue success\n");}
pthread_create(&tid2,NULL,thread2,(void*)clifd);
pthread_create(&tid3,NULL,heartbeat,(void*)clifd);
while(1)
{
//wait connecting
clifd=accept(socfd,(SA*)&cli_addr,&cliaddr_len);
pthread_mutex_lock(&lock);
if(clifd > clifd_max)
{
clifd_max = clifd;
}
pthread_mutex_unlock(&lock);
pthread_create(&tid1[client_amount],NULL,thread1,(void*)clifd);
if(clifd==-1)
{
printf("%d accept fail\n",clifd);
}
else{printf("%d (tid=%ld) accept success\n",clifd,tid1[client_amount]);}
client_amount++;
printf("已有%d个客户端连接上\n",client_amount);
}
pthread_mutex_destroy(&lock);
close(socfd);
}
void thread1(void arg)
{
int r_len;
int clifd =(int)arg;
char rbuff[1024]={0};
char wbuff[1024]={0};
char clientname[20]={0};
int flag=0;
read(clifd,clientname,sizeof(clientname));
printf(“clifd:%d=%s\n”,clifd,clientname);
while(1)
{
r_len=recv(clifd,rbuff,sizeof(rbuff),MSG_DONTWAIT);
//r_len=read(clifd,rbuff,sizeof(rbuff));//MSG_DONTWAIT,MSG_WAITALL
if(r_len == 0)
{
//printf(“无数据\n”);
}
if(r_len<0) { //perror("recv data"); } if(strncmp(rbuff,"testonline",10)==0) { printf("recvfrom %s:tsetonline\n",clientname); int w_len=write(clifd,"salive",6); if(w_len<0) { printf("write fail 122"); } goto BB; } if(strncmp(rbuff,"alive",5)==0) { printf("recvfrom %s:alive\n",clientname); flag=0; goto BB; } else { flag++; if(flag>(10+1))
{
printf(“网络断开超过一次心跳,关闭fd\n”);
printf(“%s has disconnected\r\n”,clientname);
client_amount—;
printf(“还有%d个客户端连接着\n”,client_amount);
close(clifd);
pthread_exit(NULL);
}
}
if(strlen(rbuff)==0)
{
goto BB;
}
printf(“recvfrom %s:%s\n”,clientname,rbuff);
sprintf(wbuff,”%s:%s”,clientname,rbuff);
pthread_mutex_lock(&lock);
for(int j=clifd_min;j<=clifd_max;j++)
{
write(j,wbuff,sizeof(wbuff));
}
pthread_mutex_unlock(&lock);
BB:
bzero(wbuff,sizeof(wbuff));
bzero(rbuff,sizeof(rbuff));
sleep(1);
}
}
void thread2(void arg)
{
int w_len;
int clifd =(int)arg;
char buff[1024]={0};
char wbuff[1024]={0};
while(1)
{
scanf(“%s”,buff);
if(strncmp(buff,”quit”,4)==0)
{
close(clifd);
exit(0);
}
sprintf(wbuff,”server:%s”,buff);
pthread_mutex_lock(&lock);
for(int j=clifd_min;j<=clifd_max;j++)
{
write(j,wbuff,sizeof(wbuff));
}
pthread_mutex_unlock(&lock);
bzero(wbuff,sizeof(wbuff));
}
}
void heartbeat(void arg)
{
int w_len;
int clifd =(int)arg;
char buff[1024]={0};
char wbuff[1024]={0x86,0x06,0x00,0x86,0x01,0x12};
//int n=0;
while(1)
{
pthread_mutex_lock(&lock);
for(int j=clifd_min;j<=clifd_max;j++)
{
w_len=write(j,wbuff,sizeof(wbuff));
}
pthread_mutex_unlock(&lock);
sleep(10);
}
}
主要功能:各个客户端发送消息给服务器,然后服务器统一将这些消息发给其他客户端,从而达到聊 天 室的效果.支持断网重连.
断线重连:
服务器发送心跳包给客户端,如果失败,则提示断线,并且删除与客户端通信的会话
30秒发送一次心跳包。 发送数据段”0x86”给客户端,客户端接受后,返回“alive”,
同时客户端也会每30s向服务器发送”testonline”,服务器收到后会回复”salive”,如果没收到就会开始重连,知道连上为止.
中间主要有两个问题,一个是换成非阻塞接收数据后,返回值为0时有两个意思,一个是socket连接断开了,一个是对方发送空数据了,怎么处理这个空数据?我是默认返回值为0时不做处理,跳过buff内容为0的打印步骤,而确认断开连接我放在超时处理中了,这个虽然降低了实时性但基本能把这个问题处理掉.
第二个问题是断网重连后,用户名会丢失,这个主要是因为重连后的是新建了一个socket,然后再连上服务器的,在重连之前服务器把第一次接收到的数据作为用户名,所以就造成了用户名错乱的问题,解决方法是在新建socket之后将用户名发给服务器就好了.
以上都是我个人的理解,还有很多不到位的地方,希望各位大佬理解一下作为菜鸟的无奈L
声明:本文内容由易百纳平台入驻作者撰写,文章观点仅代表作者本人,不代表易百纳立场。如有内容侵权或者其他问题,请联系本站进行删除。
红包
点赞
收藏
评论
打赏
- 分享
- 举报
评论
0个
手气红包
暂无数据
相关专栏
-
浏览量:3684次2020-06-29 11:06:04
-
浏览量:1374次2019-09-17 17:55:55
-
浏览量:2450次2017-12-13 15:52:24
-
浏览量:1798次2019-07-16 09:50:57
-
浏览量:3212次2020-08-07 17:39:59
-
浏览量:3079次2020-09-15 11:13:11
-
浏览量:1951次2020-07-29 09:26:12
-
浏览量:1625次2020-06-11 15:30:54
-
浏览量:3179次2020-11-09 19:56:03
-
浏览量:2451次2020-07-31 18:12:31
-
浏览量:4304次2022-02-18 09:00:35
-
浏览量:5768次2021-04-26 17:27:59
-
2020-06-08 11:00:12
-
浏览量:1812次2020-09-09 19:02:25
-
浏览量:3471次2019-11-19 08:57:44
-
浏览量:2455次2020-10-28 13:43:30
-
2021-04-06 16:22:40
-
2021-04-06 16:21:26
-
浏览量:1837次2018-02-23 20:43:11
置顶时间设置
结束时间
删除原因
-
广告/SPAM
-
恶意灌水
-
违规内容
-
文不对题
-
重复发帖
打赏作者
miko
您的支持将鼓励我继续创作!
打赏金额:
¥1
¥5
¥10
¥50
¥100
支付方式:
微信支付
打赏成功!
感谢您的打赏,如若您也想被打赏,可前往 发表专栏 哦~
举报反馈
举报类型
- 内容涉黄/赌/毒
- 内容侵权/抄袭
- 政治相关
- 涉嫌广告
- 侮辱谩骂
- 其他
详细说明
审核成功
发布时间设置
发布时间:
请选择发布时间设置
是否关联周任务-专栏模块
审核失败
失败原因
请选择失败原因
备注
请输入备注