参考此示例(和文档): 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()
根据我的理解(这里的顿悟),主要问题是recvall
内部的recv
只关心检索流(就像send
只关心发送流一样),它没有"消息"的概念,因此不知道何时完成阅读。它读取了所有字节并且没有返回任何其他字节,但这不是消息完成发送的信号,可能还有更多字节等待发送,否则假设是不安全的。
这要求我们有一个明确的指标来指示何时停止阅读。recv
和send
只关心管理流,因此没有消息的概念(我们的"单元")。本文对此问题有一些很好的解决方案。由于我发送的是固定长度的消息,因此我选择在完成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
双向通信现在可以工作了,唯一的问题是客户端和服务器必须知道他们将收到的消息的长度,这在我的情况下也不是问题。这对我来说是全新的,所以有人请纠正我的术语和概念。