复用Socket时抛出java.net.SocketException: Socket is closed问题求助
Socket复用失败问题解决
问题场景
尝试复用同一个Socket向WHOIS服务多次发送查询请求,但第一次请求后抛出java.net.SocketException: Socket is closed异常。
原测试代码
private final static String WHOIS_HOST = "whois.verisign-grs.com"; private final static int WHOIS_PORT = 43; @Test void justAnExample() { try { Socket socket = new Socket(WHOIS_HOST, WHOIS_PORT); socket.setSoTimeout(5000); sendRequest(socket, "cnn.com"); Thread.sleep(2000); sendRequest(socket, "youtube.com"); Thread.sleep(2000); sendRequest(socket, "toyota.com"); socket.close(); } catch (Exception e) { e.printStackTrace(); } } private void sendRequest(Socket socket, String domain) throws IOException { OutputStream out = socket.getOutputStream(); out.write((domain + "\r\n").getBytes()); try (BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()))) { String line; while ((line = input.readLine()) != null) { if (line.contains("Registry Expiry Date")) { line = line.substring(line.indexOf(':') + 1).trim(); System.out.println("---> " + line); break; // don't need to read any more input } } final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'"); if(line != null){ final LocalDateTime dt = LocalDateTime.parse(line, formatter); System.out.println("---> " + dt); System.out.println("---> Not available " + domain); } else { System.out.println("---> Available " + domain); } } out.flush(); out.close(); }
运行异常
---> 2026-09-21T04:00:00Z ---> 2026-09-21T04:00 ---> Not available cnn.com java.net.SocketException: Socket is closed at java.base/java.net.Socket.getOutputStream(Socket.java:998)
问题原因及解决方案
1. 核心问题:过早关闭Socket输出流
在sendRequest方法最后调用了out.close(),关闭输出流时会直接关闭底层的Socket连接,导致后续无法再复用该Socket。
2. 修改步骤
步骤一:移除out.close()调用
保留out.flush()确保数据发送,但不要关闭输出流,Socket的关闭统一放到所有请求完成后执行。
步骤二:读取完整响应,避免残留数据
第一次请求时只读取到目标行就终止,WHOIS服务返回的剩余响应数据会留在输入流中,导致后续请求解析异常。需要读取完整响应内容,清空输入流。
修改后的sendRequest方法
private void sendRequest(Socket socket, String domain) throws IOException { OutputStream out = socket.getOutputStream(); out.write((domain + "\r\n").getBytes()); out.flush(); // 立即发送请求数据 try (BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()))) { String line; String expiryLine = null; // 读取完整响应,筛选目标信息 while ((line = input.readLine()) != null) { if (line.contains("Registry Expiry Date")) { expiryLine = line.substring(line.indexOf(':') + 1).trim(); System.out.println("---> " + expiryLine); } } final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'"); if(expiryLine != null){ final LocalDateTime dt = LocalDateTime.parse(expiryLine, formatter); System.out.println("---> " + dt); System.out.println("---> Not available " + domain); } else { System.out.println("---> Available " + domain); } } // 不关闭OutputStream,Socket统一在所有请求完成后关闭 }
3. 额外注意事项
- 部分WHOIS服务可能在一段时间无操作后主动断开持久连接,建议添加异常捕获逻辑,在连接断开时重新创建Socket。
- 可以在初始化Socket时一次性获取
OutputStream并复用,减少重复获取的资源开销。
内容的提问来源于stack exchange,提问作者Peter Penzov
相关产品推荐
相关产品推荐

