0

我有一个 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);

我不能手动分离分组的消息,因为它们是二进制消息,这个模块不能“理解”它们。

所以,问题是:我如何确保读者单独收到消息?

谢谢。

4

2 回答 2

2

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

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

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

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

于 2012-09-14T15:53:22.670 回答
1

它们传输流是 TCP 连接的本质。

你的选择是

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

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

于 2012-09-14T15:13:02.143 回答