【问题标题】:Receiving end of socket splits data when printed打印时套接字的接收端拆分数据
【发布时间】:2014-10-30 16:48:06
【问题描述】:

所以在使用 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();
    }
};

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

【问题讨论】:

  • Java 发送“Test1Test1Test1”,在两者之间刷新。 awrecvstring.split("|") 是否在以某种方式寻找 | 字符?没有发送此类字符。也看看stackoverflow.com/a/20352105/995891 DataOutputStream#writeBytes(String) 很少是个好主意
  • @zapl 我打算用“|”发送一个字符串char 在我需要知道的值之间。这样我就可以拆分字符串并将所有值放入recvstring数组中。

标签: java python sockets


【解决方案1】:

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

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

如果您想单独处理整个消息,则由您来构建一个描述消息的协议——这是否意味着使用一些不能出现在实际数据中的分隔符(可能是因为,如果它确实出现在实际数据中)数据,您将其转义),或为每条消息添加长度前缀,或使用某种自我描述的格式,如 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:。)

【讨论】:

  • 感谢您提供信息并举例说明!我打算用“|”在 1 个字符串中发送多个值它们之间的字符以分隔这些值并将它们放入 recvstring 数组中。我现在要睡觉了,但明天我会试一试。再次感谢您的宝贵时间,不胜感激!
  • 我刚刚尝试了您的代码,它在我的本地网络上完美运行。谢谢!
  • @RanoV:太好了!那么,您了解使用“两级分隔符”分隔记录和分隔记录中的字段的部分吗? (如果不是,考虑 CSV 文件可能会有所帮助:行之间的换行符,列之间的逗号。)
  • 我了解该方法,但我真的不知道您为什么需要它。您不能在每个循环中使用 .split("|") 拆分缓冲区。使用“两级分隔符”在性能上是否更好?我将在本地网络上运行应用程序,因此我知道字节流将在几毫秒内到达目的地。仍然非常感谢您的宝贵时间,谢谢!
  • @RanoV:这不是性能问题,而是简单性(以及稳健性和面向未来)的问题。假设每条消息都是超级英雄的名字、秘密身份和原色。如果您将每个超级英雄作为单独的行发送,例如Superman|Clark Kent|blue\nIron Man|Tony Stark|gold\n,则每行都是一个完整的超级英雄来处理。如果您重复使用相同的分隔符,例如Superman|Clark Kent|blue|Iron Man|Tony Stark|gold|,则每个字段都是超级英雄的一部分;然后你必须跟踪你所处的状态,并在你前进的过程中以某种方式积累价值。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多