求一对多服务端的客户端非法下线处理办法(加分修正版)

kkkgho 2008-11-12 11:13:37
我写了一个实时聊天程序,这个程序分服务端和客户端
服务端记录在线人员和人数,中转聊天消息
客户端请求并显示在线列表,接收其他客户端的消息,向其他客户端发起对话

现在按照正常的退出,需要发送一个退出消息给服务端,服务端在线人数-1,并且将此客户端从在线列表除名

现在的问题是:当用户直接结束进程或断电时,会导致退出消息无法正常发出,这个客户就永远挂在了在线列表

我考虑过超时的解决办法,但是在效率上有很大的问题:
你得为每一个客户机对应一个超时累计时间,每一秒累计时间+1,这样假设如果有500个用户,CPU 1秒要做500次加运算
而且客户端需要5秒发送一个表示在线的包给服务端,服务端再把该客户端的超时累计时间清0
而且每1秒要判断500次累计超时时间是否大于60秒,如果大于再从在线列表除名
这样明显不可行,大家有什么更好的办法吗?

注:程序基于控制台+多线程
...全文
162 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
herman~~ 2008-11-15
  • 打赏
  • 举报
回复
客户端或者服务端发送心跳都可以
但要控制心跳的频率 例如:客户C1,C2每隔3分钟需要心跳到服务端,服务端对于超时未发送心跳包的客户做清理下线

由于心跳包一般比较小,只要频率控制合理 一般不会造成过大的负载
kkkgho 2008-11-13
  • 打赏
  • 举报
回复
准备采用心跳包,正在设计中……
xhs_lh04 2008-11-13
  • 打赏
  • 举报
回复
如果是长连接可采用心跳包机制

另外你的所有send,recv函数加上判断返回码
如果对端关闭,recv接收到的返回是0,判断返回为0,即作为客户端下线处理,关闭连接
帅得不敢出门 2008-11-13
  • 打赏
  • 举报
回复
用select来查询是否超时
引用一段

//如果是发送者,则不发送数据
fd_set fdsetWrite;
FD_ZERO(&fdsetWrite);
FD_SET(hSocket,&fdsetWrite);
TIMEVAL tv;
tv.tv_sec=0; tv.tv_usec=0;
int nNum=select(0,NULL,&fdsetWrite,NULL,&tv);
if(nNum == SOCKET_ERROR || 0 == nNum)
//已经退出
else
//socket好使;

Winsock貌似也有类似的功能 你没用就另当别论了.
having_hr 2008-11-13
  • 打赏
  • 举报
回复
拼音命名不很清晰
kkkgho 2008-11-13
  • 打赏
  • 举报
回复
还在调查。。。。很复杂搞不清楚
xhs_lh04 2008-11-13
  • 打赏
  • 举报
回复
为什么会丢包?
这不可能

如果丢包还是你程序的问题,TCP是可靠连接
kkkgho 2008-11-13
  • 打赏
  • 举报
回复
现在整个程序基本好了。。。但是就是丢包很严重,经常收不到数据
星羽 2008-11-12
  • 打赏
  • 举报
回复
可以通过发送心跳包确认某client是否掉线
kkkgho 2008-11-12
  • 打赏
  • 举报
回复
客户端代码

// 客户端.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <Winsock2.h>
#include <stdio.h>
#include <iostream.h>
#include <process.h>
SOCKET sockClient;

void zikehu(void* para)
{
char neirong[1020];
while(1)
{
unsigned long ul = 1;
int iResult = ioctlsocket(sockClient,FIONBIO, (unsigned long *)&ul);
recv(sockClient,neirong,1020,0);
if(neirong[0]=='c'&&neirong[1]=='h'&&neirong[2]=='a'&&neirong[3]=='t')
{
neirong[0]=' ';
int tmp=0;
for(int i=4;neirong[i]!='\0';i++)
{
if(neirong[i]=='v'&&neirong[i+1]=='k'&&neirong[i+2]=='-')
{
if(tmp==0)
{
cout<<" 对你说:";
i=i+3;
tmp=1;
}
cout<<neirong[i];
}
else
{
cout<<neirong[i];
}
tmp=0;
}
cout<<endl;
}
Sleep(200);
}
}
void main()
{
char ip[50];
cout<<"请输入服务器的IP地址"<<endl;
cin>>ip;
WSADATA wsaData;
WORD banben;
banben=MAKEWORD(1,1);
WSAStartup(banben,&wsaData);
sockClient=socket(AF_INET,SOCK_STREAM,0);//创建套接字(socket)。

SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr=inet_addr(ip);
addrSrv.sin_family=AF_INET;
addrSrv.sin_port=htons(5043);
connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));//向服务器发出连接请求(connect)。

char recvBuf[100];//和服务器端进行通信(send/recv)。
recvBuf[0]='\0';
recv(sockClient,recvBuf,100,0);
if(recvBuf[0]=='\0')
{
printf("连接服务器失败!\n",NULL);
return;
}
printf("%s\n",recvBuf);
printf("请设定你的昵称\n",NULL);
char nicheng[100];
cin>>nicheng;
send(sockClient,nicheng,strlen(nicheng)+1,0);
int caozuo;
_beginthread(zikehu,0,NULL);
menu:
cout<<"----------请选择操作----------"<<endl;
cout<<"1.看看谁在线上"<<endl;
cout<<"2.开始对话"<<endl;
cout<<"3.退出"<<endl;
cin>>caozuo;
if(caozuo==1)
{
send(sockClient,"0",strlen("0")+1,0);
char tmp[2000];
tmp[0]='\0';
jieshou:
recv(sockClient,tmp,2000,0);
if(tmp[0]=='\0')
{
goto jieshou;
}
for(int i=0;i!=2000;i++)
{
if(tmp[i]==',')
{
cout<<endl;
}
else if(tmp[i]=='\0')
{
break;
}
else
{
cout<<tmp[i];
}
}
}
if(caozuo==2)
{
char name[100],name1[101],x[10];
cout<<"请输入你要对话的人的昵称"<<endl;
cin>>name;
name1[0]='1';
name1[1]='\0';
strcat(name1,name);
send(sockClient,name1,strlen(name1)+1,0);
recv(sockClient,x,10,0);
if(x[0]=='0')
{
cout<<"你输入的用户不存在,对话被拒绝"<<endl;
goto menu;
}
else
{
char chat[1000];
cout<<"你对 "<<name<<" 说:";
cin>>chat;
send(sockClient,chat,strlen(chat)+1,0);
}
}
if(caozuo==3)
{
send(sockClient,"exit",strlen("exit")+1,0);
cout<<"退出成功!"<<endl;
goto exit;
}
goto menu;
exit:
closesocket(sockClient);//关闭套接字。
WSACleanup();//必须调用这个函数清除参数
}
kkkgho 2008-11-12
  • 打赏
  • 举报
回复
服务端代码


#include "stdafx.h"

#include <Winsock2.h>//加裁头文件
#include <stdio.h>//加载标准输入输出头文件
#include <iostream.h>
#include <process.h>


struct LIST
{
char name[50];
SOCKET lianjie;
};

SOCKADDR_IN duihua[2000];
int biaoji,renshu=0;
LIST list[500];

void zikehu(void* para)
{
int biaozhi=biaoji;

char buf[100];
sprintf(buf,"%s 已经成功连接服务器",inet_ntoa(duihua[biaozhi].sin_addr));
send(list[biaozhi].lianjie,buf,strlen(buf)+1,0);

char buf2[100];
recv(list[biaozhi].lianjie,buf2,100,0);
printf("用户 %s 已经成功连接服务器\n",buf2);

strcat(list[renshu-1].name,buf2);

char buf3[100];
buf3[0]='\0';

while(1)
{
send(list[biaozhi].lianjie,"-",strlen("-")+1,0);
recv(list[biaozhi].lianjie,buf3,100,0);
if(buf3[0]=='0')
{
printf("用户 %s 请求在线用户列表\n",buf2);
buf3[0]='\0';
char zaixian[2000];
zaixian[0]='\0';
for(int i=0;i<renshu;i++)
{
if(list[i].name[0]=='\0')
continue;
strcat(zaixian,list[i].name);
strcat(zaixian,",");
}
cout<<"发送在线列表源数据:"<<zaixian<<endl;
send(list[biaozhi].lianjie,zaixian,strlen(zaixian)+1,0);
}
else if(buf3[0]=='1')
{
int x=0;
SOCKET tmp1;
buf3[0]=' ';
cout<<"用户 "<<buf2<<" 向"<<buf3<<" 发起对话"<<endl;
for(int j=0;j<=strlen(buf3);j++)
{
buf3[j]=buf3[j+1];
}
buf3[strlen(buf3)]='\0';

for(int i=0;i<=renshu;i++)
{
if(!strcmp(list[i].name,buf3))
{
x=1;
tmp1=list[i].lianjie;
}
}
if(x==0)
{
cout<<"警告:用户 "<<buf3<<" 不存在!"<<endl;
send(list[biaozhi].lianjie,"0",strlen("0")+1,0);
}
else
{
char fasong[1010];
char sed[1020];
send(list[biaozhi].lianjie,"1",strlen("0")+1,0);
recv(list[biaozhi].lianjie,fasong,1010,0);
sed[0]='\0';
strcat(sed,"chat");
strcat(sed,list[biaozhi].name);
strcat(sed,"vk-");
strcat(sed,fasong);
send(tmp1,sed,strlen(sed)+1,0);
cout<<"发送聊天源数据:"<<sed<<endl;
}
}
else if(buf3[0]=='e'&&buf3[1]=='x'&&buf3[2]=='i'&&buf3[3]=='t')
{
cout<<"用户 "<<list[biaozhi].name<<" 已经退出服务器!"<<endl;
list[biaozhi].name[0]='\0';
list[biaozhi].lianjie=0;
return;
}
buf3[0]='\0';
Sleep(300);
}
}

void main()
{
WSADATA wsaData;
WORD banben;
banben=MAKEWORD(1,1);

WSAStartup(banben,&wsaData);

SOCKET taolian;
taolian=socket(AF_INET,SOCK_STREAM,0);

SOCKADDR_IN dizhi;
dizhi.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
dizhi.sin_family=AF_INET;
dizhi.sin_port=htons(5043);

bind(taolian,(SOCKADDR*)&dizhi,sizeof(SOCKADDR));
listen(taolian,5);

int len=sizeof(SOCKADDR);

cout<<"服务器成功启动!"<<endl;

while(1)
{
biaoji=renshu;
list[renshu].lianjie=accept(taolian,(SOCKADDR*)&duihua[renshu],&len);//程序会暂停在此直到接收到客户端链接
_beginthread(zikehu,0,NULL);
Sleep(50);
renshu++;
}
}


内容概要:本文围绕“空地多无人平台协同路径规划技术”的论文复现展开,重点介绍了基于Matlab的多无人机与地面无人平台协同路径规划的算法实现与仿真研究。研究系统性地整合了无人机三维路径规划、动态避障、多机协同、任务分配及防撞机制等核心技术,结合智能优化算法(如遗传算法、粒子群算法、灰狼优化算法等)与经典路径规划模型(如Dubins路径、A*、RRT等),在复杂威胁环境下实现了高效、安全的协同路径规划。文中提供了完整的Matlab代码支持,便于科研人员进行算法验证、性能对比与二次开发,并强调通过复现高水平学术论文(如EI、SCI期刊及硕博论文)深入掌握该领域的前沿方法与技术路线。; 适合人群:具备一定Matlab编程基础,从事无人机系统、自动化控制、人工智能、路径规划等相关领域研究的研究生、科研人员及工程技术人员,尤其适用于正在开展科研项目、撰写学位论文或希望提升算法实践能力的研究者。; 使用场景及目标:① 复现并深入理解空地协同路径规划领域的高水平论文算法;② 掌握Matlab在多智能体路径规划中的建模、仿真与可视化方法;③ 应用于科研课题、毕业设计、项目申报及算法创新实践中,提升研究的技术深度与工程可行性。; 阅读建议:建议结合文中提供的网盘资源(含完整代码、仿真模型及参考文献资料)同步学习,优先选择与自身研究方向契合的案例进行复现,注重算法原理与代码实现之间的映射关系,并在掌握基础方案后尝试进行参数调优、算法融合或引入新约束条件以实现改进与创新。

65,211

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧