java - 为什么我的客户端在使用 SSL 套接字和 Java 7 时无法读取服务器发送的第二条消息?

标签 java sockets ssl bufferedinputstream

我在使用 Java 7 和 SSL 套接字时遇到了一个令人费解的问题。

我有一个客户端/服务器包。两者都使用非常简单的协议(protocol)相互发送 XML 数据。每条消息的前 4 个字节始终包含整个消息的长度。也就是说,它是 XML 数据的长度加上 4 个字节。

首先,客户端向服务器发送问候消息。接下来,服务器解释问候语并发送响应。然后,客户端自己解释该消息并发送其登录信息。服务器检查该信息并发回响应。但这一次,客户端没有收到任何东西,尽管它使用与从服务器获取问候响应时完全相同的方法。

这是客户端的简化读取方法:

private String readResponse() throws Exception
{
    BufferedInputStream inputBuffer = new BufferedInputStream(sslSocket.getInputStream());

    // Read and interprete the first 4 bytes to get the length of the XML-data
    int messageLength = readMessageLength(inputBuffer) - 4;

    // PROBLEM OCCURS HERE!

    // Read bufferSize bytes from stream
        byte[] byteArray = new byte[messageLength];
    inputBuffer.read(byteArray);

    // Return the XML-data
    return new String(byteArray);
}

这里是从前 4 个字节检索长度的方法...

private int readMessageLength(BufferedInputStream in) throws IOException {
    byte[] b = new byte[4];
    in.read(b, 0, 4);

    return (((b[0] & 0xff) << 24) | ((b[1] & 0xff) << 16) | ((b[2] & 0xff) << 8) | (b[3] & 0xff));
}

当客户端读取第二个响应时,inputBuffer仅包含零 ( [0, 0, 0, 0, 0, 0, ...] )。因此,当尝试使用 readMessageLength() 计算消息长度时, 它返回 -4 .当然,这会导致异常。

很明显,服务器发送的数据还没有准备好被客户端读取。因此,我做了一些修改:

int messageLength;
do {
    messageLength = readMessageLength(inputBuffer) - 4;
} while(messageLength <= 0);

然而,这也没有用。现在令人费解的部分来了:这个循环执行了两次!分配给 messageLength 的值现在来自 XML 数据的前 4 个字节。读取方法返回的字符串现在以 ?xml 开头, 其中<不见了!

因此,我尝试标记并重置第一个字节: inputBuffer.mark(4);

int messageLength;
do {
    inputBuffer.reset();
    messageLength = readMessageLength(inputBuffer) - 4;
} while(messageLength <= 0);

但这实际上是一个无限循环。由于 inputBuffer 的内容永不改变,messageLength永远不会变成-4以外的任何东西.

我什么时候可以确定发送给客户端的数据是可用的?我怎么检查呢? 什么可能是更好的方法?

问候, 沃尔特

附言available() 方法没有用,因为它在使用 SSL 套接字时似乎总是返回零。

最佳答案

您绝对必须始终检查从通信 channel 读取的字节数。它有时可以而且将会是零,在这种情况下您必须继续阅读。仅以负返回值到达流末尾。

具体来说,in.read(new byte[100]) 不一定读取 100 个字节。

如果你想保证你得到了一切,你需要使用 readFully。

关于java - 为什么我的客户端在使用 SSL 套接字和 Java 7 时无法读取服务器发送的第二条消息?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11884404/

相关文章:

java - 在可序列化对象上获取 NotSerializableException

PHP 如何发送原始 HTTP 数据包

c# - 寻找自由港

ssl - 在 Websphere Liberty 中配置多个出站 SSL 设置?

ssl - meteor / Apollo : SSL Access for HTTPS and WS?

android - HTTPS 证书有时会在 Android WebView 中失败

java - 如何使 eclipse 引用与 exe 文件相同的文件夹中的工作区?

java - 了解 Java 的 protected 修饰符

php - 在PHP中进行进程间通信的最简单方法是什么?

java - 类似于 Elasticsearch 的最多 1000 个 json 文件的解决方案