引用此示例(和docs):https://pymotw.com/2/socket/tcp.html我正在尝试通过使用TCP阻塞客户端和服务器之间的套接字来实现双向通信。
我可以从client->server
或server->client
进行单向通信,但是尝试在服务器和客户端上接收消息时,套接字仍然处于阻塞或“挂起”状态。我正在使用一种简单的算法(recvall
),该算法使用recv
将数据包合并为完整的消息。
我知道套接字在设计上一直保持阻塞状态,直到所有数据发送或读取(对吗?),但这不是sendall
和recvall
处理的吗?在客户端或服务器上禁用recv
怎么会“解除阻止”并使其起作用?最终,我在做什么错而导致套接字保持阻塞状态?
这是我的代码,唯一的根本区别实际上是发送的消息:recvall(socket)
(在客户端和服务器之间共享):
def recvall(socket):
data = ''
while True:
packet = socket.recv(16)
if not packet: break
data += packet
return data
server.py
(先运行):import socket
host = 'localhost'
port = 8080
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((host, port))
s.listen(5)
while True:
(client, address) = s.accept()
print 'client connected'
try:
print recvall(client)
client.sendall('hello client')
finally:
client.close()
client.py
:进口 socket
s = socket.create_connection((args.ip, args.port))
try:
s.sendall('hello server')
print recvall(s)
finally:
s.close()
最佳答案
根据我的理解(epiphany here),主要问题是recv
中的recvall
仅与检索流有关(以send
仅与发送流相同的方式),它没有“消息”的概念,因此无法知道什么时候完成阅读。它读取了所有字节,并且没有返回任何其他字节,但这并不是该消息已完成发送的信号,可能有更多的字节等待发送,否则就不安全了。
这就要求我们有一个明确的指标来指示何时停止阅读。 recv
和send
仅与流管理有关,因此没有消息的概念(我们的“单元”)。 This article对这个问题有一些很好的解决方案。由于我正在发送固定长度的消息,因此我选择在完成recv
之前检查该长度是否符合预期。这是recvall
的更新版本,请注意,必须定义并强制执行MSG_LENGTH
,以便recvall
不阻塞套接字。
def recvall(socket):
data = ''
while len(data) < MSG_LENGTH:
packet = socket.recv(BUFFER_SIZE)
if not packet: break
data += packet
return data
双向通信现在可以正常工作,唯一的问题是客户端和服务器必须知道它们将接收的消息的长度,对我而言,这也不是问题。这对我来说是全新的,因此请有人纠正我的术语和概念。