Java文件传输中接收文件的While循环无法退出问题求助
问题分析:客户端接收服务器文件时While循环无法退出
嘿,我瞅了你的代码,这个循环卡着不退出的问题其实很常见——服务器发送完文件后,没有给客户端一个明确的“传输结束”信号,导致客户端的d.read(buffer)一直阻塞在那里,永远等不到返回-1的时刻。
具体原因拆解
当你用BufferedInputStream.read()读取Socket输入流时,这个方法会一直阻塞,直到有数据可读或者流被关闭。你的服务器在发送完文件后,只关闭了自己的文件输入流d.close(),但Socket的输出流还处于打开状态,客户端根本不知道文件已经传完了,还在傻等更多数据,循环自然退不出来。
另外代码里还有几个小问题也顺手提一下:
- 客户端重复创建
InputStreamReader(比如get2、get3),完全没必要,复用一开始的get就好; - 路径拼接用了硬编码的
"\\",换成File.separator能适配不同操作系统; - 流的关闭不规范,最好用try-with-resources语法自动关闭,避免资源泄漏。
解决方案:给传输加上结束标记
我们需要让服务器在发送完文件后,明确告诉客户端“我发完了”,最直接的方式就是调用Socket的shutdownOutput()方法,关闭输出流的写入端,这样客户端的read方法就会收到-1,循环正常退出。
修改后的Server.java关键部分
case 2: System.out.println("The client has requested to download a file"); BufferedReader st = new BufferedReader(new InputStreamReader(cs.getInputStream())); String s = st.readLine(); System.out.println("The requested file is : " + s); File f = new File(s); if(f.exists()) { // 用try-with-resources自动关闭流 try (BufferedInputStream d = new BufferedInputStream(new FileInputStream(s)); BufferedOutputStream outStream = new BufferedOutputStream(cs.getOutputStream())) { byte buffer[] = new byte[1024]; int read; while((read = d.read(buffer)) != -1) { outStream.write(buffer, 0, read); outStream.flush(); } System.out.println("File transferred"); // 关键:发送完文件后,关闭Socket的输出流,告知客户端传输结束 cs.shutdownOutput(); } catch (IOException e) { e.printStackTrace(); } } break;
修改后的Client.java关键部分
case 2: System.out.println("Enter the file name to transfer from server:"); BufferedReader dis = new BufferedReader(new InputStreamReader(System.in)); String f = dis.readLine(); put.println(f); String savePath = cwd + File.separator + f; // 用try-with-resources自动关闭流 try (BufferedInputStream d = new BufferedInputStream(s.getInputStream()); BufferedOutputStream outStream = new BufferedOutputStream(new FileOutputStream(savePath))) { byte buffer[] = new byte[1024]; int read; // 现在这个循环会在服务器关闭输出流后正常退出 while((read = d.read(buffer)) > 0) { outStream.write(buffer, 0, read); outStream.flush(); } System.out.println("File received"); } catch (IOException e) { e.printStackTrace(); } break;
额外优化思路
如果以后需要传输大文件或者更复杂的场景,还可以先在服务器端把文件长度发送给客户端,客户端根据长度来判断接收了多少数据,达到长度就主动退出循环,这种方式不需要关闭Socket流,还能继续复用连接做其他操作。
内容的提问来源于stack exchange,提问作者Stormy
相关产品推荐
相关产品推荐

