【问题标题】:How to receive the same messages sent via TCP socket?如何接收通过 TCP 套接字发送的相同消息?
【发布时间】:2012-09-14 15:04:38
【问题描述】:

我有一个 Java 中的 TCP 套接字客户端-服务器程序。

从客户端,我每秒钟发送几次二进制消息(来自字节 [] 的二进制数据)。

从服务器,我想以相同的顺序和大小读取这些消息。

问题在于服务器显然并不总是以相同大小读取消息。它似乎将它们“分组”。例如:

客户端发送: 12字节 - 12字节 - 12字节 - 12字节 - 15字节 - 15字节

服务器接收: 12 字节 - 48 字节 - 15 字节 - 15 字节

如何防止这种情况发生?

现在,我的代码是:

客户:

(initialization)
mySocket = new Socket(direccion, puerto);
mySocket.setTcpNoDelay(true);
BufferedOutputStream os = new BufferedOutputStream( mySocket.getOutputStream() );

(sending)
os.write( bytes );
os.flush();

服务器

(initialization)
serverSocket = new ServerSocket(12321);
Socket con = serverSocket.accept();
reader = new BufferedReader(new InputStreamReader(con.getInputStream()));

(receiving)
char[] msg = new char[1024];
String mensaje;
int nbytes;
nbytes = reader.read(msg);

我无法手动分离分组的消息,因为它们是二进制消息,并且此模块无法“理解”它们。

那么,问题是:如何确保读者单独收到消息?

谢谢。

【问题讨论】:

    标签: java sockets tcp client-server


    【解决方案1】:

    您正在使用 Stream 数据来传输您的消息。流在概念上只是一个字节序列——没有消息。您需要自己负责将流拆分为消息/数据包。 您甚至可以在当前代码中通过一次读取调用接收消息的一部分,并通过下一次调用接收下一部分消息。就像现在一样,您的代码存在根本缺陷。

    引入一种机制,可以清楚地检测消息的开始/结束位置。一种简单的方法是将每个数据包的长度编码到每个数据包的第一个字节中。然后接收方可以先读取长度,然后知道后面有多少字节属于该数据包。

    另一种方法是使用消息分隔符来表示当前数据包的结束。由于您正在发送二进制数据,这将要求数据包不包含所有可能的字节值,或者您需要以不使用所有可能的字节值的方式对数据包进行编码。

    具有长度的方法实现起来要简单得多,而 end symbol 方法对于您可以轻松引入新符号的方案很有用(例如,如果整个数据包都经过霍夫曼编码)。

    【讨论】:

    • 谢谢,我认为你是对的。我将采用长方法。顺便说一句,你知道任何其他通过 TCP 工作的“高级”通信协议,我可以安全地发送分隔消息吗?再次感谢。
    【解决方案2】:

    传输流是 TCP 连接的本质。

    你的选择是

    1. 手动分隔消息,例如通过在每条消息前面添加一个长度字段。这需要更改协议。

    2. 使用不同于 TCP 的协议。 UDP(但你会失去可靠性)或 STCP(我不确定 Java 是否能够做到这一点)。

    【讨论】:

      猜你喜欢
      • 2019-03-31
      • 1970-01-01
      • 2016-07-16
      • 2021-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-04
      • 1970-01-01
      相关资源
      最近更新 更多