2014-03-12 53 views
2

我想要简单的脚本客户端套接字。我的代码如下:为什么我的客户端套接字在首次发送后死亡?

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次,所以它应该发送所有的([“邮件”,“防火墙”,“弗里亚”))。这里是服务器的输出:

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() 
+0

您的1个send()调用很可能仅由1个recv()调用读取。请记住,TCP是一个流协议,它不知道或保留任何消息边界。 – nos

+0

永远不要在网络协议中使用泡菜。阅读http://docs.python.org/2/library/pickle.html上的大红色框。 –

回答

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元件是在该串 - 这意味着客户端发送所有数据的连接关闭,服务器从客户端接收的所有数据之前。

解决方案是框架(设置消息的边界)消息。这个问题比较广泛(谷歌搜索结果为tcp message boundarytcp message framing)。

我觉得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增长预期。

+0

感谢您的建议,但我的意思是第二次while循环,它应该运行三次。第一个循环只建立连接。如果c为真,则意味着连接被接受。然后客户端可以发送数据.. – Joffo

+0

@Joffo更新了一些细节 – vaultah

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

+1

这没有回答这个问题。如果您需要共享其他信息,请编辑您的问题。 –

2

我认为所有三个转储发送的第一次,只有一个被加载。

我在while循环之外移动了服务器accept(),并在客户端的发送循环中放置了一个睡眠(0.01)。 updated_data按预期增长。

这是一次性解决方案,因为服务器只接受一个连接。

相关问题