tcp多人聊 天 室(支持断网重连)

tcp多人聊 天 室(支持断网重连) miko 2022-10-11 14:43:12 1113

先上代码:
客户端:

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

声明:本文内容由易百纳平台入驻作者撰写,文章观点仅代表作者本人,不代表易百纳立场。如有内容侵权或者其他问题,请联系本站进行删除。
miko
红包 点赞 收藏 评论 打赏
评论
0个
内容存在敏感词
手气红包
    易百纳技术社区暂无数据
相关专栏
置顶时间设置
结束时间
删除原因
  • 广告/SPAM
  • 恶意灌水
  • 违规内容
  • 文不对题
  • 重复发帖
打赏作者
易百纳技术社区
miko
您的支持将鼓励我继续创作!
打赏金额:
¥1易百纳技术社区
¥5易百纳技术社区
¥10易百纳技术社区
¥50易百纳技术社区
¥100易百纳技术社区
支付方式:
微信支付
支付宝支付
易百纳技术社区微信支付
易百纳技术社区
打赏成功!

感谢您的打赏,如若您也想被打赏,可前往 发表专栏 哦~

举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

审核成功

发布时间设置
发布时间:
是否关联周任务-专栏模块

审核失败

失败原因
备注
拼手气红包 红包规则
祝福语
恭喜发财,大吉大利!
红包金额
红包最小金额不能低于5元
红包数量
红包数量范围10~50个
余额支付
当前余额:
可前往问答、专栏板块获取收益 去获取
取 消 确 定

小包子的红包

恭喜发财,大吉大利

已领取20/40,共1.6元 红包规则

    易百纳技术社区