为什么我的客户端插座在第一次发送后死

时间:2014-03-12 18:08:06

标签: python sockets networking tcp

我正在尝试简单的脚本客户端套接字。我的代码如下:

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"])。这是服务器输出:

enter image description here

然后客户端结束了。为什么?客户端应在发送所有数据后结束。为什么一个发送连接关闭后?

感谢您的帮助

已编辑---> 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()

3 个答案:

答案 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 boundarytcp 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连接。有没有办法只建立一个,并发送所有数据?