关于socket判断连接断开并重连

nq19860409 2009-03-11 03:19:34

以下是个线程函数

UINT CMonitorDlg::ThreadFunction(LPVOID pParam)
{ WSADATA wsaData;
SOCKET s; //创建套接字
int port=PORT;
int iLen; //从服务器接收的数据长度
TCHAR recvbuf[BufferLen]; //接受数据的缓冲器

struct sockaddr_in serv1; //服务器端地址
serv1.sin_family=AF_INET; //需要连接的服务器地址信息
serv1.sin_port=htons(port); //需要连接的服务器地址信息
serv1.sin_addr.s_addr=inet_addr(p->Ip); //将命令行的IP地址转化为二进制表示的网络字节顺序IP地址
s=socket(AF_INET,SOCK_STREAM,0);

if(s==INVALID_SOCKET)
{
AfxMessageBox("socket()failed");//套接字失败
return 0;
}


if(connect(s,(struct sockaddr*)&serv1,sizeof(serv1))==INVALID_SOCKET)
{
int b=WSAGetLastError();
//连接失败
}
else
{ //连接成功

p->connectstate=true;


do{

在此循环体中我接收数据并对数据做处理(省略部分代码)
iLen=recv(s,recvbuf,sizeof(recvbuf),0); //接收套接字中的数据放入recvbuf1缓冲区

if(iLen==0)
{

strtempMsg.Format(_T("局 %s 数据传送结束"),p->Name);

return 0;
}

else if(iLen==SOCKET_ERROR)
{
int err=WSAGetLastError();
if (err==WSAECONNRESET ||err==WSAECONNABORTED)
strtempMsg.Format(_T("%s连接中断"),p->Name);

p->connectstate=false;

return -2; //连接异常中断
}

......
.....省略代码

}while//do-while
} //else

closesocket(s); //关闭套接字
WSACleanup();
return 0;

}

因为这个线程创建以后一直在运行,里面的循环体不停地从套接字中取数据并处理数据,但要是我所连接的服务端断开了我如何判断,并自动重新连接(而不用关程序重新开)。请高手在我代码基础上添加所需修改的地方,谢谢。
...全文
1699 21 打赏 收藏 转发到动态 举报
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
tujunf 2009-03-18
  • 打赏
  • 举报
回复
不论哪一方关闭连接,对方都能够得到通知。如果正在接收数据,则最后的read操作返回 0 表示对方已关闭。

if(iLen==0)
{

strtempMsg.Format(_T("局 %s 数据传送结束"),p->Name);

return 0;
}

上面的代码实际已经执行,只是看不到输出效果而已。

nq19860409 2009-03-13
  • 打赏
  • 举报
回复
请问大伙们,为啥我在原代码基础上怎加了把套接字转为非阻塞模式后,一开始就连不上服务端了?
unsigned long ul=1;
int nRet;
nRet=ioctlsocket(s,FIONBIO,(unsigned long*)&ul);
if(SOCKET_ERROR==nRet)
return FALSE;
nq19860409 2009-03-13
  • 打赏
  • 举报
回复
谁能解答17楼的问题呀
  • 打赏
  • 举报
回复
closesocket(s); //关闭套接字
关闭后,重新连接啊,你第一次会连,第2次不会连?
nq19860409 2009-03-12
  • 打赏
  • 举报
回复
就是在do while不停地循环,就是if(iLen==SOCKET_ERROR)判断为假
topwork 2009-03-12
  • 打赏
  • 举报
回复
没走到这句,走到哪里了?你能跟一下代码吗?
nq19860409 2009-03-12
  • 打赏
  • 举报
回复
不行啊,
我在运行时,把其中一个服务端关了,但我的程序并没有走到iLen==SOCKET_ERROR或这iLen==0中;
如果在运行时,我把自己电脑上网线拔了,就会走到iLen==SOCKET_ERROR
topwork 2009-03-12
  • 打赏
  • 举报
回复
无论是
iLen == SOCKET_ERROR
还是
iLen == 0
你都可以试着重连。
nq19860409 2009-03-12
  • 打赏
  • 举报
回复
iLen=recv(s,recvbuf,sizeof(recvbuf),0);

当我把自己电脑上的网线拔了会产生
iLen==SOCKET_ERROR

但如果服务端网络断了,是从哪里判断呢
nq19860409 2009-03-12
  • 打赏
  • 举报
回复
我想问个问题,为什么我再关闭服务端后,程序好像停在do-while循环中哪一地方不走了,本来我在线程外面做了个定时器,每隔1秒,count+1,然后在do-while里做了个判断count>10,如果大于10就代表服务器连接中断,然后我要重新连接,但是,我在关闭服务端后,do-while中的count就不+1了,好像程序在哪个位置停住了,会不会是在 recv那里停住了?,但我拔掉自己的网线,count又开始+1了,这是为啥呢以下是个线程函数

UINT CMonitorDlg::ThreadFunction(LPVOID pParam)
{ WSADATA wsaData;
SOCKET s; //创建套接字
int port=PORT;
int iLen; //从服务器接收的数据长度
TCHAR recvbuf[BufferLen]; //接受数据的缓冲器

struct sockaddr_in serv1; //服务器端地址
serv1.sin_family=AF_INET; //需要连接的服务器地址信息
serv1.sin_port=htons(port); //需要连接的服务器地址信息
serv1.sin_addr.s_addr=inet_addr(p->Ip); //将命令行的IP地址转化为二进制表示的网络字节顺序IP地址
s=socket(AF_INET,SOCK_STREAM,0);

if(s==INVALID_SOCKET)
{
AfxMessageBox("socket()failed");//套接字失败
return 0;
}


if(connect(s,(struct sockaddr*)&serv1,sizeof(serv1))==INVALID_SOCKET)
{
int b=WSAGetLastError();
//连接失败
}
else
{ //连接成功

p->connectstate=true;


do{

在此循环体中我接收数据并对数据做处理(省略部分代码)
iLen=recv(s,recvbuf,sizeof(recvbuf),0); //接收套接字中的数据放入recvbuf1缓冲区

if(iLen==0)
{

strtempMsg.Format(_T("局 %s 数据传送结束"),p->Name);

return 0;
}

else if(iLen==SOCKET_ERROR)
{
int err=WSAGetLastError();
if (err==WSAECONNRESET ||err==WSAECONNABORTED)
strtempMsg.Format(_T("%s连接中断"),p->Name);

p->connectstate=false;

return -2; //连接异常中断
}

if(count>10)
{
connect(s,(struct sockaddr*)&serv1,sizeof(serv1));
}

(外面有个定时器使count每秒+1。)
......
.....省略代码

}while//do-while
} //else

closesocket(s); //关闭套接字
WSACleanup();
return 0;

}

yqfu 2009-03-12
  • 打赏
  • 举报
回复
UINT CMonitorDlg::ThreadFunction(LPVOID pParam)
{
WSADATA wsaData;
WSAStartup(...);

while(1)
{
if (WaitSingleObject(hEventKill, 0) == WAIT_OBJECT_0) // 这个hEventKill到主线程里创建,用于控制线程退出
{
break;
}

SOCKET s; //创建套接字
int port=PORT;
int iLen; //从服务器接收的数据长度
TCHAR recvbuf[BufferLen]; //接受数据的缓冲器

struct sockaddr_in serv1; //服务器端地址
serv1.sin_family=AF_INET; //需要连接的服务器地址信息
serv1.sin_port=htons(port); //需要连接的服务器地址信息
serv1.sin_addr.s_addr=inet_addr(p->Ip); //将命令行的IP地址转化为二进制表示的网络字节顺序IP地址
s=socket(AF_INET,SOCK_STREAM,0);

if(s==INVALID_SOCKET)
{
AfxMessageBox("socket()failed");//套接字失败
return 0;
}


if(connect(s,(struct sockaddr*)&serv1,sizeof(serv1))==INVALID_SOCKET)
{
int b=WSAGetLastError();
//连接失败
}
else
{ //连接成功

p->connectstate=true;


do{

在此循环体中我接收数据并对数据做处理(省略部分代码)
iLen=recv(s,recvbuf,sizeof(recvbuf),0); //接收套接字中的数据放入recvbuf1缓冲区

if(iLen==0) // server调用了close
{
strtempMsg.Format(_T("局 %s 数据传送结束"),p->Name);
break;
//return 0;
}
else if(iLen==SOCKET_ERROR) // 网络错误
{
int err=WSAGetLastError();
if (err==WSAECONNRESET ||err==WSAECONNABORTED)
strtempMsg.Format(_T("%s连接中断"),p->Name);

p->connectstate=false;

break; // 退出do-while循环准备重连
// return -2; //连接异常中断
}

......
.....省略代码

}while//do-while
} //else

closesocket(s); //关闭套接字
} // end of while(1)

WSACleanup();

return 0;

}

这么详细了,再不明白就不对了
yqfu 2009-03-12
  • 打赏
  • 举报
回复
你现在用的是阻塞模式的套接字。recv返回有几种情况,一种是收到数据返回,这时的返回值是>0的;一种是对方调用了close,这时recv会立即返回0;还有一种是返回-1(SOCKET_ERROR),这是由于网络出现了某种故障。如果出现网络故障,比如网络断了或者你拔了网线,大多数情况下recv不会立即返回,而是要等到套接字超时才返回-1(超时时间长度与具体系统有关,一般要几分钟)。

针对你的代码,要实现重连最简单的改进就是在函数里加一个循环,把你现在函数中全部代码放到这个循环内。

由于当网络出现故障时,recv要很长时间才能返回,如果你觉得这种方式不能接受,可以考虑select或者其他模型。
nq19860409 2009-03-12
  • 打赏
  • 举报
回复
我客户端连接多个远程服务端,它们当中有一个断了,我判不了,上面说的iLen==SOCKET_ERROR好像只针对我自己客户端机器网络断开。远程的服务端关不关我怎么知道
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 biosli 的回复:]
和服务器做个心跳检测,如果几次信息发出去没回来就说明断了,重新连
[/Quote]
TCP本身就有keepalive
LZ写的是客户端吧?断开后你可以判断到recv到数据并且返回0,在这个点上可以再去调用connect啊,而且最好设置异步套接字,connect后用select判断超时便于进一步处理。。。
nq19860409 2009-03-11
  • 打赏
  • 举报
回复
请高手们能不能在小弟的代码上补充下,我新手,光说文字不太懂
biosli 2009-03-11
  • 打赏
  • 举报
回复
和服务器做个心跳检测,如果几次信息发出去没回来就说明断了,重新连
topwork 2009-03-11
  • 打赏
  • 举报
回复
自动重新连接?你就把当前的socket销毁,然后从新来过。
nq19860409 2009-03-11
  • 打赏
  • 举报
回复
我要自动重新连接怎么做呢
topwork 2009-03-11
  • 打赏
  • 举报
回复
recv函数返回0说明Socket断开了。

65,210

社区成员

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

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