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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/685951/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 16:44:17  来源:igfitidea点击:

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

c++winsock

提问by

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

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

采纳答案by sfossen

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

查看此常见问题解答 2.12

example from select on thispage.

示例来自页面上的选择。

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
    }
}

回答by Len Holgate

You can only tell if a TCP socket is 'disconnected' by attempting to send data. 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). 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. 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.

您只能通过尝试发送数据来判断 TCP 套接字是否“断开连接”。这是因为协议的设计应该允许对等点之间的临时中断。因此,如果您从 A 通过 R1 通过 R2 通过 R3 连接到 B 并发送数据一段时间然后停止发送,您可以拔掉 R2->R3(例如),A 和 B 都不会注意到(或关心)。如果您随后插入 R2->R4 和 R4->R3,然后尝试在 A 和 B 之间发送数据,那么事情就会“正常工作”,而您永远不会知道。但是,如果您在 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. Personally I'd go for the ping messages...

如果让您的对等方知道连接何时“中断”很重要,那么要么使用应用程序级别的“ping”消息在对等方之间偶尔发送数据,要么使用 TCP 保持连接。就个人而言,我会去寻找 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; you also KNOW when you shutdown either the send or recv side of your own end of the connection...

编辑:当然,所有这些都是假设您想知道您是否仍然可以在连接上发送数据,毕竟,当客户端不再发送时,您会被告知,因为您的读取将返回 0 字节,并且您知道何时断开连接它的发送方,因为您的写入将失败;您也知道何时关闭您自己的连接端的发送或接收端...

I guess I should have stuck with initial gut reaction response of "define disconnected" ;)

我想我应该坚持“定义断开连接”的初始直觉反应;)

回答by Adam Davis

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/

回答by slaviber

If the result of send() or recv() is SOCKET_ERROR and WSAGetLastError() returns WSAECONNRESET the client has disconnected.
From MSDN:

如果 send() 或 recv() 的结果是 SOCKET_ERROR 并且 WSAGetLastError() 返回 WSAECONNRESET,则客户端已断开连接。
来自 MSDN:

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). 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. Subsequent operations fail with WSAECONNRESET.

WSAECONNRESET

对等方重置连接。

远程主机强行关闭了现有连接。如果远程主机上的对等应用程序突然停止、主机重新启动、主机或远程网络接口被禁用,或者远程主机使用硬关闭(有关远程上的 SO_LINGER 选项的更多信息,请参阅 setsockopt),这通常会导致插座)。如果在一个或多个操作正在进行时由于保持活动活动检测到故障而导致连接中断,也可能导致此错误。正在进行的操作因 WSAENETRESET 而失败。后续操作因 WSAECONNRESET 而失败。

This also works with non blocking sockets.

这也适用于非阻塞套接字。

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