引用此示例(以及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
:
导入套接字
s = socket.create_connection((args.ip, args.port))
try:
s.sendall('hello server')
print recvall(s)
finally:
s.close()
答案 0 :(得分:1)
根据我的理解(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
现在双向通信正常工作,唯一的问题是客户端和服务器必须知道他们将收到的消息的长度,在我的情况下,这不是问题。这对我来说是全新的,所以有人请在术语和概念上纠正我。