【发布时间】:2009-11-16 16:01:15
【问题描述】:
我为远程服务器创建了一个 SocketChannel,以便在 Tomcat 上发送和接收消息。为了从远程计算机接收消息,我使用了一个专用于任务的线程(只有这个线程会从套接字读取,没有别的)。
当 SocketChannel 接收到一些字节时(我一直在非阻塞模式下轮询 SocketChannel 以获取新数据),我首先读取 4 个字节以获取下一条消息的长度,然后从 SocketChannel 分配并读取 x 个字节,然后将其解码并重构为消息。
下面是我的接收线程代码:
@Override
public void run() {
while (true) { //Don't exit thread
//Attempt to read the size of the incoming message
ByteBuffer buf = ByteBuffer.allocate(4);
int bytesread = 0;
try {
while (buf.remaining() > 0) {
bytesread = schannel.read(buf);
if (bytesread == -1) { //Socket was terminated
}
if (quitthread) break;
}
} catch (IOException ex) {
}
if (buf.remaining() == 0) {
//Read the header
byte[] header = buf.array();
int msgsize = (0xFF & (int)header[0]) + ((0xFF & (int)header[1]) << 8)
+ ((0xFF & (int)header[2]) << 16) + ((0xFF & (int)header[3]) << 24);
//Read the message coming from the pipeline
buf = ByteBuffer.allocate(msgsize);
try {
while (buf.remaining() > 0) {
bytesread = schannel.read(buf);
if (bytesread == -1) { //Socket was terminated
}
if (quitthread) break;
}
} catch (IOException ex) {
}
parent.recvMessage(buf.array());
}
if (quitthread) {
break;
}
}
}
我从 SocketChannel 收到的第一个字节很好,我成功解码了消息。但是,下次我从 SocketChannel 读取时,套接字向前跳过了大约 100 个字节,这导致读取错误的字节并将其解释为长度,从而导致所有内容都损坏。
代码有什么问题?没有其他线程正在从 SocketChannel 读取数据。
【问题讨论】:
-
您可以简单地调用 getInt() 来读取长度,而不是将您的标头缓冲区转换为 4 个字节的数组。如果您想将其视为无符号整数,您始终可以使用 0xFFFFFFFF 转换为长按位与。还有,
-
我可能可以,但我不确定 java 是否会将 byte[] 的 arr[4] 读取为 little endian。无论如何,我怀疑这是问题的原因。第一条消息长度是正确的,我读取了那个字节数。检查读取的消息也表明没有错误。只有当我尝试读取标题的下 4 个字节时才会出现问题。
标签: java sockets nio tcpclient socketchannel