Java Socket双向文件传输后添加读写操作阻塞问题求助
解决Java Socket双向文件传输后的阻塞问题
兄弟,我太懂你踩的这个坑了!你遇到的问题核心在于文件接收循环没有正确终止,导致后续的Socket读写代码根本没机会执行,两边都卡在read()调用上死等。
问题根源分析
先看你服务器端的接收代码:
byte[] bytes = new byte[length]; while ((count = in.read(bytes)) > 0) { fout.write(bytes, 0, count); }
DataInputStream.read()是阻塞式调用:当没有数据可读时,它会一直挂起等待,直到有新数据到来或者底层Socket流被关闭。你以为传输完文件就结束了,但客户端只是关闭了FileInputStream,并没有关闭Socket的OutputStream——服务器端的read()会一直等啊等,永远不会返回-1,自然就卡在这个循环里出不来,更别说执行后面的状态标志校验和新的Socket操作了。
你说加了状态标志但没用?那是因为服务器端根本没机会去读这个标志——它还卡在文件接收的循环里呢!
解决方案:用预先约定的文件长度控制接收循环
既然你已经提前发送了文件长度,那完全可以用这个长度来精确控制接收的字节数,而不是依赖流的结束信号。修改服务器端的接收代码如下:
fout = new FileOutputStream(filename); // 用固定大小的缓冲区(比如4096),避免length太大导致内存溢出 byte[] bytes = new byte[4096]; System.out.println("receiving file..."); long remainingBytes = length; // 剩余需要接收的字节数 int count; while (remainingBytes > 0) { // 每次最多读取剩余字节数和缓冲区大小的较小值,避免读多了 count = in.read(bytes, 0, (int) Math.min(bytes.length, remainingBytes)); if (count == -1) { // 意外情况:对方提前关闭了流,直接终止 break; } fout.write(bytes, 0, count); remainingBytes -= count; } fout.flush(); fout.close();
这样一来,当接收的字节总数达到你预先发送的length时,循环会自动终止,服务器端就能顺利执行后面的状态标志校验和新的Socket操作了。
额外注意事项
- 客户端发送完文件后及时发送状态标志:在客户端关闭
FileInputStream后,立刻向服务器端发送一个约定好的完成标志(比如out.writeUTF("FILE_TRANSFER_DONE")),服务器端在文件接收循环结束后,马上读取这个标志确认传输完成。 - 不要随意关闭Socket流:如果还要进行后续的双向通信,只需要关闭文件相关的流(
FileInputStream/FileOutputStream),保持Socket的InputStream/OutputStream打开即可。 - 缓冲区大小别用文件长度:你原来用
new byte[length]会导致如果文件很大,直接在内存中开辟超大缓冲区,容易引发OOM,换成固定大小的小缓冲区更稳妥。
总结
你的问题本质是误解了Socket流的阻塞特性——read()不会自动知道“文件传输完了”,必须用你预先约定的长度来主动终止循环,这样后续的Socket操作才能正常执行。修改接收循环的逻辑后,阻塞问题应该就能解决了!
内容的提问来源于stack exchange,提问作者Ryoidenshi Aokigahara
相关产品推荐
相关产品推荐

