我试图编写我自己的 TCP非阻塞服务器来处理多个持久的套接字连接,而不是打开许多线程来处理它们。
我已经编写了过于复杂,难以使用的语法,但是当我尝试检测关闭的套接字时遇到了问题。
在普通的线程化TCP套接字服务器中,我将使用从b''
函数中检测到的socket.read(size)
,但是对于无阻塞套接字,这是不可能的,因为它将始终返回BlockingIOError
< / p>
我还尝试在事件发生后捕捉泰斯语
except BrokenPipeError:
conn.abort()
except ConnectionResetError:
conn.abort()
except ConnectionAbortedError:
conn.abort()
except socket.error:
conn.abort()
(conn
是容纳socket.accept()
中客户端套接字和地址的类
我不确定该怎么做,但这是我的代码中的一个大大简化的摘录:
def loop_listen(self):
while self.running == True:
cr, addr = self.server.accept()
crs = SocketHandler(self, cr, addr)
self.client_handler(crs)
self.connections.append(crs)
crs.events["open"]()
crs.cr.setblocking(0)
def loop_recv(self):
while self.running == True:
time.sleep(self.poll_time)
for conn in self.connections:
try:
data = conn.cr.recv(self.poll_size)
print(data)
if (data == b''):
conn.abort()
except BlockingIOError:
data = None
except BrokenPipeError:
conn.abort()
except ConnectionResetError:
conn.abort()
except ConnectionAbortedError:
conn.abort()
except socket.error:
conn.abort()
if (data != None):
conn.events["msg"](data)
(两个循环都是单独的线程)
如果您需要它,这里是conn
类
class SocketHandler:
def __init__(self, server, cr, addr):
self.server = server
self.cr = cr
self.addr = addr
self.events = {"msg": emptyCallback, "close": "emptyCallback","open":emptyCallback}
self.cache = b""
def message(self, func):
self.events["msg"] = func
def close(self, func):
self.events["close"] = func
def open(self, func):
self.events["open"] = func
def send(self, data):
self.cr.send(data)
def abort(self):
self.cr.close()
self.events["close"]()
self.server.connections.remove(conn)
这在Windows上可以正常使用,但在Ubuntu上不会调用conn.abort()
。
任何帮助将不胜感激。
谢谢,山姆。
答案 0 :(得分:1)
检测非阻塞套接字上的关闭连接的官方方法与阻塞套接字完全相同。它们从recv()
返回空数据。
示例:
# Server
import socket
import time
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('localhost', 12345))
s.listen(1)
while True:
conn, addr = s.accept()
conn.setblocking(0)
print("New connection from " + str(addr) + ".")
while True:
try:
data = conn.recv(1024)
if not data:
break
print("Received:", data)
except BlockingIOError:
time.sleep(0.001)
print("Closed.")
# Client
import socket
import time
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('localhost', 12345))
for i in range(5):
time.sleep(0.3)
s.send(str(i).encode('utf-8'))
s.close()
在一种特殊情况下,如官方文档第When Sockets Die节中所述,这种方法将不起作用。当套接字无法正常关闭时,就会发生这种情况。如果没有正常关机,recv()
基本上无法检测套接字何时死亡。可能就是您所看到的。
有多种解决方法。首先,创建某种超时,如果在合理的时间内未收到消息,则该超时将关闭并丢弃套接字。其次,您可以主动发送消息。与send()
相比,recv()
检测死套接字要容易得多。
此外,这在Linux上有效。我没有在Windows上测试过。套接字类的内部实现非常依赖于平台,因此可能是Windows错误。