0

我正在使用 java 服务器连接到具有安全 websockets 的浏览器。连接一切正常,但很多时候我从 socket.in.read(buffer,off,len) 得到一个意外的-1结果,这也发生在帧的中间。通常我在收到 -1 时直接关闭一个套接字,因为它是流的结尾。但是我注意到它也可能发生在连接重置时。我遇到过很多情况,在我的测试中,套接字在读取返回 -1 后会返回有价值的数据。我什至觉得这种情况经常发生。我的问题出现了,有时我只是在这种情况下从套接字中取出一些乱码数据。另一个问题是,当帧无法投递时,没有通知对方…… 那么 TCP/SSL 有什么好处呢?如果您需要将其视为在 java 中传输 websocket 帧的不可靠连接?

我有一些方案可以用来处理不可靠的连接,以确保数据包到达。但我希望有人知道在读取返回-1 后该做什么。

抱歉,这个描述有点模糊......我已经厌倦了解决这个问题。

只是一些垃圾进入的示例(仅提交包含 JSON 数据的文本框架):

16-06-13 22:43:13.918;WebSocket;7: Read frame from websocket: 377, opcode:UNKNOWN
data: null
16-06-13 22:43:13.918;WebSocket;7: Read frame from websocket: 377, opcode:PONG_FRAME
data: null
16-06-13 22:43:13.918;WebSocket;7: Read frame from websocket: 377, opcode:TEXT_FRAME
data: =,6GiGGV7C6_TfPHg\~\c

这是接收到的帧的另一个例子,它只是有点畸形!?这怎么可能通过 TCP/TLS 连接???:

17-06-13 09:42:37.510;WebSocket;7: Read frame from websocket: 15, opcode:TEXT_FRAME
data: "kep-aiveY:"d613Nb2-N24eV463K-808-fJb30I9e3M02

它应该是 {"keep-alive":"[UUID]"}

同时,我做了更多的测试,发现如果您在收到 -1 后继续阅读,则 10 次中有 9 次有效。因此,即使您正在读取帧的一半并收到 -1,那么您应该以某种方式测试套接字是否关闭,我现在使用:socket.isInputShutdown()。如果不是这种情况,则继续填充缓冲区。为此,我现在使用以下代码,其中套接字是 SSLSocket:

public static int readFully(Socket socket, InputStream is, byte[] buffer, int off, int len) throws IOException
{
    int read = 0;
    while(read < len)
    {
        int b = is.read();
        if(b < 0)
        {
            Logger.log(TAG, "readFully read returned: " + b + " testing if connection is reset or closed.", Logger.WARNING);
            if(socket.isInputShutdown())
            {
                throw new IOException("InputStream closed before data could be fully read! (readFully read returned -1 and socket.isInputShutdown() is true");
            }
        }
        else
        {
            buffer[off + (read++)] = (byte) b;
        }
    }
    return read;
}

它仍然不是百分百正确,但至少我得到了比以前更可靠的结果。

4

1 回答 1

0

我从 socket.in.read(buffer,off,len) 得到一个意外的 -1 结果

在调用此方法之前,您已经到达 EOS(流结束)。

这也发生在帧的中间。

TCP 中没有“帧”之类的东西。如果您的意思是它发生在应用程序消息的中间,那么您有一个应用程序协议错误。

通常我在收到 -1 时直接关闭一个套接字,因为它是流的结尾。

正确的。

但是我注意到它也可能发生在连接重置时

不,它没有。如果是这样,您就不可能检测到重置。这种说法是自相矛盾的。

我遇到过很多情况,在我的测试中,套接字在读取返回 -1 后会返回有价值的数据。

不,你没有。套接字在第一次返回 -1 后不能返回任何内容。除非您在某处忽略 -1,否则您根本无法获得任何数据,更不用说“有价值的”数据了。

我的问题出现了,有时我只是在这种情况下从套接字中取出一些乱码数据。

只有当你像你一样忽略-1时。

另一个问题是当帧不能被传递时,对方没有得到通知。

当然不是。如果您可以向另一方传递通知,则可以传递数据包。这也没有道理。如果您的意思是对方在无法传递数据包时没有收到通知那么您就面临 TCP 发送是异步的事实,因此您通常不会在导致它的发送时收到发送错误。您将在稍后发送时收到它。如果您需要每次发送确认,则需要将它们构建到您的应用程序协议中。

那么 TCP/SSL 有什么好处呢?

TCP 是一种可靠的数据流协议,而 SSL 是一种安全可靠的数据流协议。这就是它们的用途。

如果您需要将其视为在 java 中传输 websocket 帧的不可靠连接?

它们都不是不可靠的。

我希望有人知道读取返回-1后该怎么做。

关闭插座。

同时,我做了更多的测试,发现如果您在收到 -1 后继续阅读,则 10 次中有 9 次有效。

不,它没有。1000 的 1000 次它继续返回 -1。您在这里看到的只是代码中其他错误的影响。

因此,即使您正在读取帧的一半并收到 -1,那么您应该以某种方式测试套接字是否关闭

你不能。套接字关闭。证明:您只是从中读取,没有出现异常。除了返回-1之外,您也无法测试连接是否关闭。read()

我现在使用:socket.isInputShutdown()。

无意义。这告诉您是否调用Socket.shutdownInput()自己的套接字。它不会告诉你连接的状态。除了读取或写入之外,没有任何 TCP API 可以做到这一点。

如果不是这种情况,则继续填充缓冲区。

即通过忽略返回的 -1 来读取 gargabe read()

为此,我现在使用以下代码,其中套接字是 SSLSocket:

为什么?DataInputStream.readFully()已经存在。重新实现它不会有帮助。

if(b < 0)
{
    Logger.log(TAG, "readFully read returned: " + b + " testing if connection is reset or closed.", Logger.WARNING);
    if(socket.isInputShutdown())

此时,您Socket是否因输入而关闭是 100% 无关紧要的。read()已返回-1,表示对方已关闭连接。时期。

    {
        throw new IOException("InputStream closed before data could be fully read! (readFully read returned -1 and socket.isInputShutdown() is true");
    }

这都是胡说八道。

}
else
{
    buffer[off + (read++)] = (byte) b;
}

在这里,您将其低字节添加-1,0xff,缓冲区中。这也是无稽之谈。

于 2013-08-14T10:06:07.003 回答