C++ 检测 TCP 客户端断开连接
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/283375/
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
Detecting TCP Client Disconnect
提问by Zxaos
Let's say I'm running a simple server and have accept()
ed a connection from a client.
假设我正在运行一个简单的服务器并accept()
从客户端建立了一个连接。
What is the best way to tell when the client has disconnected? Normally, a client is supposed to send a close command, but what if it disconnects manually or loses network connection altogether? How can the server detect or handle this?
判断客户端何时断开连接的最佳方法是什么?通常,客户端应该发送关闭命令,但是如果它手动断开连接或完全失去网络连接怎么办?服务器如何检测或处理这个?
采纳答案by sep
select (with the read mask set) will return with the handle signalled, but when you use ioctl* to check the number of bytes pending to be read, it will be zero. This is a sign that the socket has been disconnected.
select(设置了读取掩码)将返回并发出句柄信号,但是当您使用 ioctl* 检查待读取的字节数时,它将为零。这是套接字已断开连接的标志。
This is a great discussion on the various methods of checking that the client has disconnected: Stephen Cleary, Detection of Half-Open (Dropped) Connections.
这是关于检查客户端是否断开连接的各种方法的精彩讨论:Stephen Cleary,检测半开(丢弃)连接。
* for Windows use ioctlsocket.
* 对于 Windows,使用 ioctlsocket。
回答by user207421
In TCP there is only one way to detect an orderly disconnect, and that is by getting zero as a return value from read()/recv()/recvXXX()
when reading.
在 TCP 中,只有一种方法可以检测有序断开连接,那就是read()/recv()/recvXXX()
在读取时获取零作为返回值。
There is also only one reliable way to detect a broken connection: by writing to it. After enough writes to a broken connection, TCP will have done enough retries and timeouts to know that it's broken and will eventually cause write()/send()/sendXXX()
to return -1 with an errno/WSAGetLastError()
value of ECONNRESET,
or in some cases 'connection timed out'. Note that the latter is different from 'connect timeout', which can occur in the connect phase.
只有一种可靠的方法可以检测断开的连接:通过写入连接。在对断开的连接进行足够多的写入后,TCP 将进行足够的重试和超时以知道它已断开并最终导致write()/send()/sendXXX()
返回 -1 的errno/WSAGetLastError()
值ECONNRESET,
或在某些情况下“连接超时”。请注意,后者与“连接超时”不同,后者可能发生在连接阶段。
You should also set a reasonable read timeout, and drop connections that fail it.
您还应该设置合理的读取超时,并删除失败的连接。
The answer here about ioctl()
and FIONREAD
is compete nonsense. All that does is tell you how many bytes are presently in the socket receive buffer, available to be read without blocking. If a client doesn't send you anything for five minutes that doesn't constitute a disconnect, but it does cause FIONREAD
to be zero. Not the same thing: not even close.
这里的答案是关于ioctl()
和FIONREAD
竞争的废话。所做的只是告诉您套接字接收缓冲区中目前有多少字节,可以在不阻塞的情况下读取。如果客户在五分钟内没有向您发送任何内容,这并不构成断开连接,但确实会导致FIONREAD
为零。不一样的东西:甚至不接近。
回答by Peter Jeffery
To expand on this a bit more:
对此进行更多扩展:
If you are running a server you either need to use TCP_KEEPALIVE to monitor the client connections, or do something similar yourself, or have knowledge about the data/protocol that you are running over the connection.
如果您正在运行服务器,您需要使用 TCP_KEEPALIVE 来监视客户端连接,或者自己做类似的事情,或者了解您通过连接运行的数据/协议。
Basically, if the connection gets killed (i.e. not properly closed) then the server won't notice until it tries to write something to the client, which is what the keepalive achieves for you. Alternatively, if you know the protocol better, you could just disconnect on an inactivity timeout anyway.
基本上,如果连接被终止(即没有正确关闭),那么服务器不会注意到,直到它尝试向客户端写入一些内容,这就是 keepalive 为您实现的。或者,如果您更了解协议,则无论如何都可以在不活动超时时断开连接。
回答by Graeme Perrow
If you're using overlapped (i.e. asynchronous) I/O with completion routines or completion ports, you will be notified immediately (assuming you have an outstanding read) when the client side closes the connection.
如果您使用具有完成例程或完成端口的重叠(即异步)I/O,当客户端关闭连接时,您将立即收到通知(假设您有未完成的读取)。
回答by Graeme Perrow
"""
tcp_disconnect.py
Echo network data test program in python. This easily translates to C & Java.
A server program might want to confirm that a tcp client is still connected
before it sends a data. That is, detect if its connected without reading from socket.
This will demonstrate how to detect a TCP client disconnect without reading data.
The method to do this:
1) select on socket as poll (no wait)
2) if no recv data waiting, then client still connected
3) if recv data waiting, the read one char using PEEK flag
4) if PEEK data len=0, then client has disconnected, otherwise its connected.
Note, the peek flag will read data without removing it from tcp queue.
To see it in action: 0) run this program on one computer 1) from another computer,
connect via telnet port 12345, 2) type a line of data 3) wait to see it echo,
4) type another line, 5) disconnect quickly, 6) watch the program will detect the
disconnect and exit.
John Masinter, 17-Dec-2008
"""
import socket
import time
import select
HOST = '' # all local interfaces
PORT = 12345 # port to listen
# listen for new TCP connections
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((HOST, PORT))
s.listen(1)
# accept new conneciton
conn, addr = s.accept()
print 'Connected by', addr
# loop reading/echoing, until client disconnects
try:
conn.send("Send me data, and I will echo it back after a short delay.\n")
while 1:
data = conn.recv(1024) # recv all data queued
if not data: break # client disconnected
time.sleep(3) # simulate time consuming work
# below will detect if client disconnects during sleep
r, w, e = select.select([conn], [], [], 0) # more data waiting?
print "select: r=%s w=%s e=%s" % (r,w,e) # debug output to command line
if r: # yes, data avail to read.
t = conn.recv(1024, socket.MSG_PEEK) # read without remove from queue
print "peek: len=%d, data=%s" % (len(t),t) # debug output
if len(t)==0: # length of data peeked 0?
print "Client disconnected." # client disconnected
break # quit program
conn.send("-->"+data) # echo only if still connected
finally:
conn.close()
回答by Trade-Ideas Philip
Try looking for EPOLLHUP or EPOLLERR. How do I check client connection is still alive
尝试寻找 EPOLLHUP 或 EPOLLERR。 如何检查客户端连接是否还活着
Reading and looking for 0 will work in some cases, but not all.
读取和查找 0 在某些情况下会起作用,但不是全部。
回答by jlpayton
TCP has "open" and a "close" procedures in the protocol. Once "opened", a connection is held until "closed". But there are lots of things that can stop the data flow abnormally. That being said, the techniques to determine if it is possible to use a link are highly dependent on the layers of software between the protocol and the application program. The ones mentioned above focus on a programmer attempting to use a socket in a non-invasive way (read or write 0 bytes) are perhaps the most common. Some layers in libraries will supply the "polling" for a programmer. For example Win32 asych (delayed) calls can Start a read that will return with no errors and 0 bytes to signal a socket that cannot be read any more (presumably a TCP FIN procedure). Other environments might use "events" as defined in their wrapping layers. There is no single answer to this question. The mechanism to detect when a socket cannot be used and should be closed depends on the wrappers supplied in the libraries. It is also worthy to note that sockets themselves can be reused by layers below an application library so it is wise to figure out how your environment deals with the Berkley Sockets interface.
TCP 在协议中有“打开”和“关闭”程序。一旦“打开”,连接将保持直到“关闭”。但是有很多事情可以异常停止数据流。也就是说,确定是否可以使用链接的技术高度依赖于协议和应用程序之间的软件层。上面提到的那些侧重于试图以非侵入性方式(读取或写入 0 字节)使用套接字的程序员可能是最常见的。库中的某些层将为程序员提供“轮询”。例如,Win32 异步(延迟)调用可以启动读取,该读取将无错误地返回,并返回 0 字节以向无法再读取的套接字发出信号(大概是 TCP FIN 过程)。其他环境可能会使用“事件” 如其包装层中所定义。这个问题没有唯一的答案。检测套接字何时不能使用并应关闭的机制取决于库中提供的包装器。还值得注意的是,套接字本身可以被应用程序库下面的层重用,因此弄清楚您的环境如何处理 Berkley Sockets 接口是明智的。
回答by d19mc
In python you can do a try-except statement like this:
在 python 中,你可以像这样执行 try-except 语句:
try:
conn.send("{you can send anything to check connection}")
except BrokenPipeError:
print("Client has Disconnected")
This works because when the client/server closes the program, python returns broken pip error to the server or client depending on who it was that disconnected.
这是有效的,因为当客户端/服务器关闭程序时,python 将断开的 pip 错误返回给服务器或客户端,具体取决于断开连接的是谁。
回答by Galleon
I toyed with a few solutions but this one seems to work best for detecting host and/or client disconnection in Windows. It is for non-blocking sockets, and derived from IBM's example.
我尝试了一些解决方案,但这个解决方案似乎最适合检测 Windows 中的主机和/或客户端断开连接。它用于非阻塞套接字,源自IBM 的示例。
char buf;
int length=recv(socket, &buf, 0, 0);
int nError=WSAGetLastError();
if(nError!=WSAEWOULDBLOCK&&nError!=0){
return 0;
}
if (nError==0){
if (length==0) return 0;
}
回答by Galleon
It's really easy to do: reliable and not messy:
这真的很容易做到:可靠而不凌乱:
Try Clients.Client.Send(BufferByte) Catch verror As Exception BufferString = verror.ToString End Try If BufferString <> "" Then EventLog.Text &= "User disconnected: " + vbNewLine Clients.Close() End If
Try Clients.Client.Send(BufferByte) Catch verror As Exception BufferString = verror.ToString End Try If BufferString <> "" Then EventLog.Text &= "User disconnected: " + vbNewLine Clients.Close() End If