接收结束时,套接字在打印时分割数据

时间:2014-10-29 22:36:01

标签: java python sockets

因此,在使用Java和Python编程套接字时,我偶然发现了一些奇怪的东西。

当使用Java将消息发送到Python套接字的接收端时,它会将消息分成两部分,即使这不是预期的。

我可能在某处导致了这个问题,但我真的不知道它是什么。

你可以看到Java发送" Test1"在一个命令中,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();
    }
};

有关邮件分割原因的任何想法?

1 个答案:

答案 0 :(得分:1)

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

就TCP而言,s.send("abd"); s.send("def");s.send("abcdef")完全相同。在套接字的另一端,当您开始接收时,它可能会在第一次发送到达后立即返回并提供"abc",但它可以轻松返回"abcdef"或{{1 },或"a"。它们都是完全合法的,你的代码必须能够处理所有这些。

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

看起来你是建立这样一个东西的一部分,因为你出于某种原因得到了"abcd"。但是你仍然需要添加其余部分 - 循环接收字节,将它们添加到缓冲区,将任何完整的消息从缓冲区中分离出来以处理它们,并在最后保留任何不完整的消息以用于下一个循环。当然,在另一边发送split('|')分隔符。

例如,您的Java代码可以执行此操作:

|

然后,在Python方面:

out.writeBytes(s + "|");

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来分隔每封邮件中的字段,而不是分隔邮件。如果是这样,请选择另一个永远不会出现在您的数据中的字符,并使用该字符代替上面的|(然后在|内执行msg.split('|'))。一个非常好的选择是process_message,因为那时(在Python方面)你可以使用\n,它为你提供了一个类似文件的对象,它为你做缓冲并且只是逐个产生行。你可以迭代它(或者在它上面调用socket.makefile)。

有关详细信息,请参阅Sockets are byte streams, not message streams

作为旁注,我还删除了readline标记,因为你唯一一次设置它,你也会去running,所以它没有任何好处。 (但如果您 要测试一个标记,请使用break,而不是while running:。)