繁体   English   中英

Java SocketChannel吃我的字节

[英]Java SocketChannel Eating my bytes

我创建了一个到远程服务器的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读取。

您的括号已关闭,代码为:

(0xFF & ((int)header[1] << 8))

始终为0(与<< 16和<< 24相同),我的猜测是您的意思是:

((0xFF & ((int)header[1])) << 8)

这将导致读取的消息字节不足,也导致同步不匹配(而不是读取太多)。

编辑 :现在您已解决上述问题,我看不到任何错误。 您能告诉我们第一条消息的长度与被吃掉的确切字节数之间的关系吗?

根据显示的代码,我唯一的猜测是您从显示的示例中编辑了一些可能会影响schannel的行为,该schannel是否在其他地方引用?

如果行:

ByteBuffer buf = ByteBuffer.allocate(4);

将是外while这将导致您所描述的行为,但在你的示例代码并非如此。

我猜想,当您说要以非阻塞模式轮询套接字时,意味着要使用“标准” Selector.select()方法?

当select返回并指示有可从套接字读取的数据时,应仅在重新进入对select()的调用之前读取可用的字节。 如果read()返回-1,则表明缓冲区中没有更多字节可立即读取-这并不意味着套接字已关闭。 因此,我怀疑您尝试在返回之前完全填充缓冲区是不正确的。 即使工作正常,在数据到达时,您的I / O线程也会不断旋转。 特别是,看起来您只是在忽略返回值-1。

考虑重新构造代码以使用有限状态机方法。 例如,我过去使用3状态模型来实现此功能:IDLE,READ_MESSAGE_LENGTH和READ_MESSAGE。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM