引用此示例(和docs):https://pymotw.com/2/socket/tcp.html我正在尝试通过使用TCP阻塞客户端和服务器之间的套接字来实现双向通信。

我可以从client->serverserver->client进行单向通信,但是尝试在服务器和客户端上接收消息时,套接字仍然处于阻塞或“挂起”状态。我正在使用一种简单的算法(recvall),该算法使用recv将数据包合并为完整的消息。

我知道套接字在设计上一直保持阻塞状态,直到所有数据发送或读取(对吗?),但这不是sendallrecvall处理的吗?在客户端或服务器上禁用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仅与发送流相同的方式),它没有“消息”的概念,因此无法知道什么时候完成阅读。它读取了所有字节,并且没有返回任何其他字节,但这并不是该消息已完成发送的信号,可能有更多的字节等待发送,否则就不安全了。

这就要求我们有一个明确的指标来指示何时停止阅读。 recvsend仅与流管理有关,因此没有消息的概念(我们的“单元”)。 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

双向通信现在可以正常工作,唯一的问题是客户端和服务器必须知道它们将接收的消息的长度,对我而言,这也不是问题。这对我来说是全新的,因此请有人纠正我的术语和概念。

10-06 02:17