从 TCP 连接读取字节数组时服务器抛出 OutOfMemory 异常

Posted

技术标签:

【中文标题】从 TCP 连接读取字节数组时服务器抛出 OutOfMemory 异常【英文标题】:Server throwing OutOfMemory Exception when reading byte array from TCP connection 【发布时间】:2013-01-19 23:19:10 【问题描述】:

我仍在处理我的推送服务器!我已经使用 javax.crypto.cipher 成功实现了加密。这需要我读/写字节到套接字的流。我可以发送和接收就好了。加密有效。但是,当无线传输没有任何内容时,服务器会抛出 OutOfMemoryException。 readBytes 函数是:

public static byte[] readBytes() throws IOException 
    int len = dis.readInt();
    byte[] data = new byte[len];
    if (len > 0) 
        dis.readFully(data);
    
    return data;

调用它的代码是:

 public String read() 
            byte[] encrypted,decrypted = null;
            try 
                    encrypted = readBytes();
                    if (encrypted.equals(new Byte[] 0)) return "";
                    if (encrypted.equals(null)) return null;
                    cipher.init(Cipher.DECRYPT_MODE, key);
                    decrypted = cipher.doFinal(encrypted);
             catch (Exception e) 
                    // TODO Auto-generated catch block
                    e.printStackTrace();
            
            String afterEncryption = new String(decrypted);
            return afterEncryption;
    

并且 read() 在 while 循环中被调用:

while (true&loggedin&((inputLine=read())!=null)) 

而抛出的异常是:

Exception in thread "ServerThread" java.lang.OutOfMemoryError: Java heap space
    at ServerThread.readBytes(ServerThread.java:277)
    at ServerThread.read(ServerThread.java:245)
    at ServerThread.run(ServerThread.java:108)

第 277 行是声明字节数组的行。发送字节数组的函数是:

    public static void sendBytes(byte[] myByteArray, int start, int len) throws IOException 
    if (len < 0)
        throw new IllegalArgumentException("Negative length not allowed");
    if (start < 0 || start >= myByteArray.length)
        throw new IndexOutOfBoundsException("Out of bounds: " + start);
    if (len > 0) 
        dos.writeInt(len);
        dos.write(myByteArray, start, len);
    

sendBytes 仅在 read() 停止阻塞时运行。这就是循环的设计方式。

如果这段代码看起来很眼熟,那是因为我在堆栈溢出时发现了它!

握手完美无缺,但一旦停止发送,我会在大约五秒后收到异常。

感谢您能给我的任何帮助。

【问题讨论】:

能否打印len 的值或在声明byte[] data 之前设置断点?显然它真的很大(以亿计)。 你能提供更多代码吗?我认为发生的事情是 readBytes 被调用太多了。 所有其他代码都无关紧要。这是所有事情发生的地方。问题不在于 while 循环封装的代码,我认为 readInt 没有像它应该的那样阻塞? len 似乎在某一时刻设置为 218762506,这让我想知道 readBytes 是否被过早调用,导致它在响应中间读取? 【参考方案1】:

您几乎肯定会在您的协议中失去同步并且读取数据,就好像它是一个长度字一样。在发送和接收它们并匹配它们时跟踪您的长度字和字节数组长度。

您真的应该考虑为此使用 CipherInputStream 和 CipherOutputStream:它们为您做了很多繁重的工作。甚至是 SSL。

【讨论】:

你是对的,但我说readShort() 怎么会起作用? @OsmiumUSA 这表明 sent 是一个短的,而不是一个整数。你不觉得吗? 对,但 sendBytes() 正在执行 writeInt(),因此另一侧的适当检索是 readInt()。此函数是否写入前面的零?逻辑表明它必须,但我不确定了。 @OsmiumUSA 问题不在于您自己的代码做了什么,而在于对方向您发送了什么? writeInt() 写入 32 位; writeShort() 写入 16。如果您的代码与 readShort() 一起使用,显然发送方正在使用 writeShort(),或者其他以网络字节顺序写入 16 位的东西。 连接两端的读取和发送功能完全相同。两者都(应该)将整数写入流。我同时维护服务器和客户端,所以我知道这是事实。

以上是关于从 TCP 连接读取字节数组时服务器抛出 OutOfMemory 异常的主要内容,如果未能解决你的问题,请参考以下文章

从字节数组中读取字段

从字节数组中获取正确格式的字符串

如何以字节数组从服务器中的文件中读取数据

Lumen Redis 队列连接错误。从服务器读取行时出错。 [tcp://xxxxxx:25061]

Java TCP Socket 发送字节数组

Mono 在 Ubuntu 上抛出 OutOfMemoryException 而不是 OSX 或 Windows