简体   繁体   English

如何检查客户端是否通过C ++中的Winsock断开连接?

[英]How can I check if a client disconnected through Winsock in C++?

如何检查客户端是否通过C ++中的Winsock断开连接?

Beej's Network Programming Guide Beej的网络编程指南

if you call recv in blocking mode and it returns with 0 bytes read, the socket has disconnected, else it wait for bytes to be received. 如果你在阻塞模式下调用recv并且它返回0字节读取,则套接字已断开连接,否则它等待接收字节。

Look in this FAQ 2.12 请看这个FAQ 2.12

example from select on this page. 示例来自页面上的选择。

int nRet;

if(( nRet = select( 0, &fdread, NULL, NULL, NULL )) == SOCKET_ERROR )
{
    // Error condition
    // Check WSAGetLastError
}

if( nRet > 0 )
{
    // select() will return value 1 because i m using only one socket
    // At this point, it should be checked whether the
    // socket is part of a set.

    if( FD_ISSET( s, &fdread ))
    {
        // A read event has occurred on socket s
    }
}

You can only tell if a TCP socket is 'disconnected' by attempting to send data. 您只能通过尝试发送数据来判断TCP套接字是否“已断开连接”。 This is because the design of the protocol is such that it's supposed to allow for temporary outages between peers. 这是因为协议的设计应该允许在对等体之间暂时中断。 So, if you connect from A via R1 via R2 via R3 to B and send data for a while and then stop sending you could unplug R2->R3 (for example) and neither A nor B would notice (or care). 因此,如果您从A通过R1经过R2连接到B并发送数据一段时间然后停止发送,您可以拔掉R2-> R3(例如),A和B都不会注意到(或小心)。 If you then plugged R2->R4 and R4->R3 and then tried to send data between A and B then things would 'just work' and you'd never know. 如果您然后插入R2-> R4和R4-> R3,然后尝试在A和B之间发送数据,那么事情就会“正常工作”而您永远不会知道。 If, however, you tried to send data when R2->R3 was disconnected then you'd (eventually, after all the TCP level retries) get an error back. 但是,如果您在R2-> R3断开连接时尝试发送数据,那么您(最终在所有TCP级别重试之后)会收到错误。

Now, some operating systems may be able to alert you to the fact that your local network adapter isn't currently connected and you could use that to say "I'm no longer connected to my peers" but I wouldn't advise it. 现在,某些操作系统可能会提醒您当前网络适配器当前未连接的事实,您可以使用它来说“我不再与我的同行连接”,但我不建议。

If having your peers know when connections are 'broken' is important then either use an application level 'ping' message to occasionally send data between the peers or use TCP keep-alive. 如果让对等方知道什么时候连接被“断开”很重要,那么要么使用应用程序级别的“ping”消息来偶尔在对等体之间发送数据,要么使用TCP keep-alive。 Personally I'd go for the ping messages... 就个人而言,我会去ping消息......

Edit: Of course all that is assuming that you want to know if you can still send data on a connection, after all, you're TOLD when the client is no longer sending because your reads will return 0 bytes and you KNOW when it disconnects its send side because your writes will fail; 编辑:当然所有这一切都假设您想知道您是否仍然可以在连接上发送数据,毕竟,当客户端不再发送时,您已经完成了因为您的读取将返回0字节并且您知道何时断开连接它的发送方是因为你的写入会失败; you also KNOW when you shutdown either the send or recv side of your own end of the connection... 你也知道什么时候关闭你自己的连接端的发送或接收端...

I guess I should have stuck with initial gut reaction response of "define disconnected" ;) 我想我应该坚持使用“define disconnected”的初始肠道反应响应;)

There are a few different ways, but the most common is to check the result of a send or receive command: 有几种不同的方法,但最常见的是检查发送或接收命令的结果:

 nReadBytes = recv(sd, ReadBuffer, BufferSize, 0);
 if (nReadBytes == SOCKET_ERROR)
 {
     //error
 }
 nSendBytes = send(sd, WriteBuffer, BufferSize, 0);
 if (nSendBytes == SOCKET_ERROR)
 {
     //error
 }

More examples (complete with error checking, both client and server) here: 更多示例(完成错误检查,包括客户端和服务器):

http://tangentsoft.net/wskfaq/examples/basics/ http://tangentsoft.net/wskfaq/examples/basics/

If the result of send() or recv() is SOCKET_ERROR and WSAGetLastError() returns WSAECONNRESET the client has disconnected. 如果send()或recv()的结果是SOCKET_ERROR并且WSAGetLastError()返回WSAECONNRESET,则客户端已断开连接。
From MSDN: 来自MSDN:

WSAECONNRESET WSAECONNRESET

Connection reset by peer. 连接由同行重置。

An existing connection was forcibly closed by the remote host. 远程主机强制关闭现有连接。 This normally results if the peer application on the remote host is suddenly stopped, the host is rebooted, the host or remote network interface is disabled, or the remote host uses a hard close (see setsockopt for more information on the SO_LINGER option on the remote socket). 如果远程主机上的对等应用程序突然停止,主机重新启动,主机或远程网络接口被禁用,或者远程主机使用硬关闭,则通常会产生这种情况(有关远程主机上SO_LINGER选项的更多信息,请参阅setsockopt)插座)。 This error may also result if a connection was broken due to keep-alive activity detecting a failure while one or more operations are in progress. 如果由于保持活动活动在一个或多个操作正在进行时检测到故障而导致连接中断,则也可能导致此错误。 Operations that were in progress fail with WSAENETRESET. 正在进行的操作因WSAENETRESET而失败。 Subsequent operations fail with WSAECONNRESET. 后续操作因WSAECONNRESET而失败。

This also works with non blocking sockets. 这也适用于非阻塞套接字。

int r = recv(sock, NULL, 0, 0);
if(r == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET){
    //client has disconnected!
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM