- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我正在编写一个 TCP 服务器,它可能需要 15 秒或更长时间才能开始生成对某些请求的响应正文。如果响应需要超过几秒钟才能完成,一些客户端喜欢在其结束时关闭连接。
由于生成响应会占用大量 CPU,因此我希望在客户端关闭连接时立即停止任务。目前,直到我发送第一个有效载荷并收到各种挂断错误时,我才发现这一点。
如何检测到对端已关闭连接而没有发送或接收任何数据?这意味着对于 recv
所有数据都保留在内核中,或者对于 send
实际上没有数据传输。
最佳答案
select模块包含您需要的内容。如果您只需要 Linux 支持并且拥有足够新的内核,select.epoll()
应该会为您提供所需的信息。大多数 Unix 系统将支持 select.poll()
。
如果您需要跨平台支持,标准方法是使用 select.select()
来检查套接字是否被标记为有数据可供读取。如果是,但是recv()
返回零字节,说明另一端挂断了。
我总能找到 Beej's Guide to Network Programming好(注意它是为 C 编写的,但通常适用于标准套接字操作),而 Socket Programming How-To有一个不错的 Python 概述。
编辑:下面是一个示例,说明如何编写一个简单的服务器来排队传入命令,但一旦发现远程端的连接已关闭,就立即退出处理。
import select
import socket
import time
# Create the server.
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversocket.bind((socket.gethostname(), 7557))
serversocket.listen(1)
# Wait for an incoming connection.
clientsocket, address = serversocket.accept()
print 'Connection from', address[0]
# Control variables.
queue = []
cancelled = False
while True:
# If nothing queued, wait for incoming request.
if not queue:
queue.append(clientsocket.recv(1024))
# Receive data of length zero ==> connection closed.
if len(queue[0]) == 0:
break
# Get the next request and remove the trailing newline.
request = queue.pop(0)[:-1]
print 'Starting request', request
# Main processing loop.
for i in xrange(15):
# Do some of the processing.
time.sleep(1.0)
# See if the socket is marked as having data ready.
r, w, e = select.select((clientsocket,), (), (), 0)
if r:
data = clientsocket.recv(1024)
# Length of zero ==> connection closed.
if len(data) == 0:
cancelled = True
break
# Add this request to the queue.
queue.append(data)
print 'Queueing request', data[:-1]
# Request was cancelled.
if cancelled:
print 'Request cancelled.'
break
# Done with this request.
print 'Request finished.'
# If we got here, the connection was closed.
print 'Connection closed.'
serversocket.close()
要使用它,请运行脚本并在另一个终端 telnet 到 localhost,端口 7557。我执行的示例运行的输出,将三个请求排队,但在处理第三个请求期间关闭了连接:
Connection from 127.0.0.1
Starting request 1
Queueing request 2
Queueing request 3
Request finished.
Starting request 2
Request finished.
Starting request 3
Request cancelled.
Connection closed.
另一个编辑:我已经设计了另一个例子,使用 select.epoll
来监控事件。我不认为它提供了比原始示例更多的功能,因为当远程端挂断时我看不到接收事件的方法。您仍然必须监视数据接收事件并检查零长度消息(再次,我很乐意在此声明中被证明是错误的)。
import select
import socket
import time
port = 7557
# Create the server.
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversocket.bind((socket.gethostname(), port))
serversocket.listen(1)
serverfd = serversocket.fileno()
print "Listening on", socket.gethostname(), "port", port
# Make the socket non-blocking.
serversocket.setblocking(0)
# Initialise the list of clients.
clients = {}
# Create an epoll object and register our interest in read events on the server
# socket.
ep = select.epoll()
ep.register(serverfd, select.EPOLLIN)
while True:
# Check for events.
events = ep.poll(0)
for fd, event in events:
# New connection to server.
if fd == serverfd and event & select.EPOLLIN:
# Accept the connection.
connection, address = serversocket.accept()
connection.setblocking(0)
# We want input notifications.
ep.register(connection.fileno(), select.EPOLLIN)
# Store some information about this client.
clients[connection.fileno()] = {
'delay': 0.0,
'input': "",
'response': "",
'connection': connection,
'address': address,
}
# Done.
print "Accepted connection from", address
# A socket was closed on our end.
elif event & select.EPOLLHUP:
print "Closed connection to", clients[fd]['address']
ep.unregister(fd)
del clients[fd]
# Error on a connection.
elif event & select.EPOLLERR:
print "Error on connection to", clients[fd]['address']
ep.modify(fd, 0)
clients[fd]['connection'].shutdown(socket.SHUT_RDWR)
# Incoming data.
elif event & select.EPOLLIN:
print "Incoming data from", clients[fd]['address']
data = clients[fd]['connection'].recv(1024)
# Zero length = remote closure.
if not data:
print "Remote close on ", clients[fd]['address']
ep.modify(fd, 0)
clients[fd]['connection'].shutdown(socket.SHUT_RDWR)
# Store the input.
else:
print data
clients[fd]['input'] += data
# Run when the client is ready to accept some output. The processing
# loop registers for this event when the response is complete.
elif event & select.EPOLLOUT:
print "Sending output to", clients[fd]['address']
# Write as much as we can.
written = clients[fd]['connection'].send(clients[fd]['response'])
# Delete what we have already written from the complete response.
clients[fd]['response'] = clients[fd]['response'][written:]
# When all the the response is written, shut the connection.
if not clients[fd]['response']:
ep.modify(fd, 0)
clients[fd]['connection'].shutdown(socket.SHUT_RDWR)
# Processing loop.
for client in clients.keys():
clients[client]['delay'] += 0.1
# When the 'processing' has finished.
if clients[client]['delay'] >= 15.0:
# Reverse the input to form the response.
clients[client]['response'] = clients[client]['input'][::-1]
# Register for the ready-to-send event. The network loop uses this
# as the signal to send the response.
ep.modify(client, select.EPOLLOUT)
# Processing delay.
time.sleep(0.1)
注意:这只检测正确的关机。如果远程端只是停止监听而没有发送正确的消息,那么在您尝试写入并收到错误之前您不会知道。检查这一点留给读者作为练习。此外,您可能希望对整个循环执行一些错误检查,以便服务器本身在内部出现问题时正常关闭。
关于python - 检测套接字挂断而不发送或接收?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5686490/
这个问题已经有答案了: Can the HWND from CreateWindow/CreateDialog be GetMessage'd from another thread? (7 个回答)
作为我的应用程序的一部分,我需要阻止来电。也就是说,当我的应用程序正在运行时,我将挂断所有调用并简单地通知调用者用户正忙或类似的事情。 我想用android SDK做这个,希望能支持Android 2
我正在尝试在 Android 上使用 Asmack API 实现一个简单的 XMPP 信使。这是代码: private final String XMPP_SERVER = "jabber.o
我刚刚安装了 watir,在 exec 之后 require 'watir-webdriver' browser = Watir::Browser.new :firefox 它只是打开浏览器,但一直挂
我有一个简单的问题,我需要找到波形的峰值。现在,我在使用 scipy 库中的 find_peaks_cwt 方法之前已经完成了此操作。然而,在这种情况下,我的程序在尝试找到峰值时只是挂起。我认为这与波
我不确定我的程序在哪里/如何挂起。我非常有信心它是在发送或接收链接中......但即使在互联网上搜索一些帮助并从我的教授那里获得帮助后,我仍然迷失,至于为什么这不起作用。 #include #inc
我正在尝试通过 appcelerator studio 为 android 应用程序商店打包我的应用程序,但在处理 javascript 文件后,控制台显示此错误 2017-04-17T22:47:3
const https = require("https"); const fs = require("fs"); const options = { hostname: "en.wikipedi
我有一个使用 Twilio 运行的应用程序。这个想法是你将调用一个电话号码,twilio 会接听并为你提供菜单选项。一旦你按下一个数字,它就会提交发布数据然后挂断(这部分工作正常)答案...我在他们的
Java 解决方案不是问题: public boolean killCall(Context context) { try { // Get the boring old Te
我试图在我的服务器上运行 jenkins,但我总是收到相同的消息,然后等待,等待,什么也没有。在官方网站上他们报告了这个问题,但我想问问是否有人知道如何解决这个问题,知道吗? 最佳答案 因为对我来说采
您好,在给定大量 json 对象的情况下,我在 NodeJS 上执行 HTTP 请求时遇到问题。给定小的 json 对象数组,请求工作正常。但是,如果我尝试增加 json 数组的大小,我会收到错误:套
我真的不知道发生了什么,直到今天早上我才检查这一切是否正常。我在 IDE 中看到的唯一异常(exception)是这个 IndexNotReadyException: Please change ca
我正在制作一个 ASP.NET (C#) 应用程序,它基本上是运行 Powershell 脚本以执行日常管理任务的网关。其中一些脚本使用 ActiveDirectory RSAT 模块,我发现其中一些
我是一名优秀的程序员,十分优秀!