我正在尝试简单的脚本客户端套接字。我的代码如下:
import pickle
import socket
pole = ["mail","firewall","fria"]
c=False
while c==False:
try:
client = socket.socket ( socket.AF_INET, socket.SOCK_STREAM )
client.connect ( ( 'localhost', 1234 ) )
print("established")
c=True
except:
print(".")
i = (len(pole)-1)
while i>=0:
client.send(pickle.dumps(pole[i]))
pole.remove(pole[i])
i-=1
client.close()
另一方面是"永远"服务器。但是服务器只接收一个数据。为什么没有全场?客户"而"循环应该运行3次,所以它应该发送所有这些(["邮件","防火墙"," fria"])。这是服务器输出:
然后客户端结束了。为什么?客户端应在发送所有数据后结束。为什么一个发送连接关闭后?
感谢您的帮助
已编辑---> server.py:
import pickle
import socket
updated_data = []
server = socket.socket ( socket.AF_INET, socket.SOCK_STREAM )
server.bind ( ( '', 1234 ) )
server.listen ( 5 )
while 1:
channel, details = server.accept()
print ('Received connection:', details [ 0 ])
updated_data.append(pickle.loads(channel.recv(1024)))
print (updated_data)
channel.close()
答案 0 :(得分:4)
我刚测试了您的代码,它显示您从循环中send()
收到的所有邮件都被服务器作为单个邮件接收,而pickle
只加载其中的第一条。基本上,收到的消息是
b'\x80\x03X\x04\x00\x00\x00friaq\x00.\x80\x03X\x08\x00\x00\x00firewallq\x00.\x80\x03X\x04\x00\x00\x00mailq\x00.'
如您所见,所有pole
元素都在此字符串中 - 这意味着客户端在连接关闭之前发送所有数据,并且服务器从客户端接收所有数据。
解决方案是 frame (设置消息的边界)消息。此问题相对广为人知(tcp message boundary和tcp message framing的Google搜索结果。)
我发现this blog post非常有帮助。它说:
消息框架通常使用两种方法:长度 前缀和分隔符。
长度前缀以每个消息的长度为前缀 信息。长度前缀的格式(和长度)必须是 明确说明; “4字节有符号的小端”(即C#中的“int”) 是一种常见的选择。要发送消息,发送方首先转换 消息到字节数组然后发送字节的长度 数组后跟字节数组本身。
接收长度前缀的消息更难,因为 部分接收的可能性。首先,必须阅读长度 将消息放入缓冲区直到缓冲区已满(例如,如果使用的话) “4字节有符号的小端”,这个缓冲区是4个字节)。然后一个 分配第二个缓冲区并将数据读入该缓冲区。什么时候 第二个缓冲区已满,然后单个消息到达,一个 回到阅读下一条消息的长度。
分隔符更难以正确使用。发送时,任何分隔符 必须替换数据中的字符,通常使用转义 功能。接收代码无法预测传入的邮件大小, 所以它必须将所有收到的数据附加到接收结束 缓冲区,根据需要增长缓冲区。找到分隔符后, 接收方可以对接收应用非转义功能 缓冲区来获取消息。如果消息永远不会包含 分隔符,然后可以跳过转义/取消转义函数。
在您的特定情况下,我会使用Python的list
(将充当“自动分隔的容器”),使用pickle
序列化,因此我将不得不稍微更改您的代码。
<强>客户端强>
import pickle
import socket
pole = ["mail","firewall","fria"]
c = False
while not c:
try:
client = socket.socket ( socket.AF_INET, socket.SOCK_STREAM )
client.connect ( ( 'localhost', 1234 ) )
print("established")
c = True
except:
print(".")
# - i = (len(pole)-1)
# - import time
# - while i>=0:
# - client.send(pickle.dumps(pole[i]))
# - pole.remove(pole[i])
# - i-=1
# +
client.send(pickle.dumps(pole))
client.close()
服务器强>
import pickle
import socket
updated_data = []
server = socket.socket ( socket.AF_INET, socket.SOCK_STREAM )
server.bind ( ( '', 1234 ) )
server.listen ( 5 )
while 1:
channel, details = server.accept()
print ('Received connection:', details[0])
data = channel.recv(1024)
if data:
# Deserialize
data = pickle.loads(data)
# We're able to extend the list with another list:
# [1, 2, 3].extend([4, 5, 6]) is [1, 2, 3, 4, 5, 6]
updated_data.extend(data)
print(updated_data)
channel.close()
现在代码正常,服务器打印
Received connection: 127.0.0.1
['mail', 'firewall', 'fria']
和updated_data
按预期增长。
答案 1 :(得分:2)
我认为所有三个转储都是第一次发送,只有一个被加载。
我将服务器accept()移到了while循环之外,并在客户端的send循环中放入了sleep(0.01)。 updated_data按预期增长。
这是一次性解决方案,因为服务器只接受一个连接。
答案 2 :(得分:0)
我只对客户进行了以下更改:
i = (len(pole)-1)
while i>=0:
c=False
while c==False:
try:
client = socket.socket ( socket.AF_INET, socket.SOCK_STREAM )
client.connect ( ( 'localhost', 1234 ) )
print("established")
c=True
except:
print(".")
client.send(pickle.dumps(pole[i]))
pole.remove(pole[i])
i-=1
但是在这个解决方案中,我需要三次esteblish连接。有没有办法只建立一个,并发送所有数据?