如何接收通过TCP套接字发送的相同消息?

时间:2012-09-14 15:04:38

标签: java sockets tcp client-server

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

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

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

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

客户发送: 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);

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

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

感谢名单。

2 个答案:

答案 0 :(得分:2)

您正在使用 Stream 数据来传输邮件。流在概念上只是一个字节序列 - 没有消息。您需要自己将流拆分为消息/数据包。 您甚至可以通过一个读取呼叫接收部分消息,然后使用当前代码中的下一个呼叫接收下一部分消息。因为现在你的代码存在根本缺陷。

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

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

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

答案 1 :(得分:1)

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

您的选择

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

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