2014-10-29 36 views
0

所以,在使用Java和Python编程套接字时,我偶然发现了一些奇怪的东西。接收端的套接字在打印时分割数据

使用Java将消息发送到Python套接字的接收端时,它会将消息拆分为两部分,即使这并非意图。

我可能犯了一个错误,导致这个问题,但我真的不知道它是什么。

你可以看到,Java的发送 “测试1” 中的一个命令和Python只收到部分消息:

http://i.imgur.com/tbwa7C5.png

Pyhton服务器套接字来源:

''' 
Created on 23 okt. 2014 

@author: Rano 
''' 

#import serial 
import socket 

HOST = '' 
PORT = 1234 
running = True; 

skt = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
skt.bind((HOST, PORT)) 
skt.listen(1) 
conne, addr = skt.accept() 

#ser = serial.Serial('/dev/tty.usbmodem411', 9600) 

while running == True: 
    data = conne.recvall(1024) 

    if(data == "quit"): 
     running = False 
     break 

    rawrecvstring = data + "" 
    recvstring = rawrecvstring.split("|") 
    print(recvstring[0]) 

#_______________________ABOVE IS RECEIVE_______________UNDER IS SEND_______________________#  

# sendstring = ser.readline() 
# if sendstring != "": 
#  conne.sendall(sendstring) 


conne.close() 
#ser.close() 

和Java的Socket发送功能:

private String message; 
private DataOutputStream out; 
private BufferedReader in; 
private Socket socket; 
private boolean socketOnline; 

public SocketModule(String IP, int Port){ 
    try { 
     socket = new Socket(IP, Port); 
     out = new DataOutputStream(socket.getOutputStream()); 
     in = new BufferedReader(new InputStreamReader(socket.getInputStream())); 
    } catch (UnknownHostException e) { 
     e.printStackTrace(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
}; 

void setMessage(String s){ 
    try { 
     out.writeBytes(s); 
     out.flush(); 
     System.out.println("message '" + s + "' sent!\n"); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
}; 

任何想法为什么消息被拆分?

+0

的Java发送“Test1Test1Test1”之间冲厕。 'awrecvstring.split(“|”)'不知何故寻找一个'|'字符?没有发送这样的字符。也看看http://stackoverflow.com/a/20352105/995891'DataOutputStream#writeBytes(String)'很少是一个好主意 – zapl 2014-10-29 22:46:55

+0

@zapl我打算发送一个字符串“|”我需要知道的值之间的字符。这样我就可以分割字符串并将所有的值都存入recvstring数组中。 – 2014-10-29 22:50:15

回答

1

TCP是一个流协议,而不是消息协议。

就TCP而言,s.send("abd"); s.send("def");s.send("abcdef")完全一样。在套接字的另一端,当您接收邮件时,它可能会在第一次发送到达时立即返回,并给您​​,但它可以简单地返回"abcdef""a""abcd"。他们都完全合法,你的代码必须能够处理所有这些。

如果你想分开处理整个消息,建立一个描述消息的协议,这是否意味着使用一些不能出现在实际数据中的分隔符(可能是因为,如果它出现在实际的数据,你逃避它),或者每个消息的长度前缀,或者使用一些自我描述的格式,如JSON。

它看起来像你是建立这样一个事情的一部分,因为你有一些原因split('|')。但是你仍然需要添加剩下的部分 - 循环接收字节,将它们添加到缓冲区,将所有完整的消息从缓冲区中分离出来处理它们,并在最后为下一个循环保留任何不完整的消息。当然,在另一边发送|分隔符。

例如,你的Java代码可以做到这一点:

out.writeBytes(s + "|"); 

然后,在Python的一面:

buf = "" 
while True: 
    data = conne.recvall(1024) 
    if not data: 
     # socket closed 
     if buf: 
      # but we still had a leftover message 
      process_message(buf) 
     break 
    buf += data 
    pieces = buf.split("|") 
    buf = pieces.pop() 
    for piece in pieces: 
     process_message(piece) 

process_message功能可以处理特殊的 “跳槽” 的消息,打印出任何东西别的,无论你想要什么。 (如果它足够简单,你可以将它内联到它被称为的两个地方。)

从一条评论,它听起来像你想要使用该|来分隔每个消息内的字段,而不是单独的消息。如果是这样,只需选择另一个永远不会出现在您的数据中的字符,并使用该字符代替上面的|(然后在process_message内执行msg.split('|'))。一个非常好的选择是\n,因为那么(在Python端)可以使用socket.makefile,它为您提供了一个类似文件的对象,为您执行缓冲操作,并且在迭代它时只是逐一产生行(或者调用readline它,如果你喜欢)。请参阅Sockets are byte streams, not message streams

作为一个附注,我也删除了running的标志,因为只有一次你要设置它,你也会去break,所以它没有任何好处。 (但如果你要测试标志,只是用while running:,不while running == True:。)

+0

感谢您的信息和举例!我打算发送1个字符串中的多个值与“|”字符介于它们之间来分离这些值并将它们放入recvstring数组中。我现在要去睡觉,但明天我会试一试。再次感谢您的时间,感谢它! – 2014-10-29 22:56:23

+0

我只是试过你的代码,它在我的本地网络上完美地工作。谢谢! – 2014-10-30 12:03:01

+0

@RanoV:太好了!那么,您是否理解使用“两级分隔线”分隔记录并分隔记录中的字段的部分? (如果没有,可能会帮助您考虑CSV文件:行之间的换行符,列之间的逗号) – abarnert 2014-10-30 18:24:48