与服务器收发数据需每次新建Socket吗?复用Socket是否可行?
Socket复用与性能问题解答
嘿,咱们逐个拆解你的问题,讲得明明白白:
1. 每次收发数据都需要新建Socket吗?
当然不需要!Socket的设计初衷就是在客户端和服务器之间建立持久的双向通信通道,只要连接没断开,完全可以复用同一个Socket来多次收发数据——这才是更合理、更高效的用法。
2. 示例代码的实现是否正确?
先看看你贴的这段代码:
package test; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; public class TestClientSocket { public static void main(String args[]) throws IOException { final String host = "localhost"; final int portNumber = 81; System.out.println("Creating socket to '" + host + "' on port " + portNumber); while (true) { Socket socket = new Socket(host, portNumber); //THIS HERE ISN'T GOING TO BE SLOW ?? BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintWriter out = new PrintWriter(socket.getOutputStream(), true); System.out.println("server says:" + br.readLine()); BufferedReader userInputBR = new BufferedReader(new InputStreamReader(System.in)); String userInput = userInputBR.readLine(); out.println(userInput); System.out.println("server says:" + br.readLine()); if ("exit".equalsIgnoreCase(userInput)) { socket.close(); break; } } } }
这种实现算不上正确的实践——它在每次循环里都新建Socket,完成一次交互后,除了最后一次,其余循环里的Socket都会因为变量失去引用被GC回收(没有显式关闭),完全浪费了Socket维持持久连接的设计目的。
3. 能不能复用同一个Socket?
绝对可以!正确的做法是把Socket的创建移到while循环外面,只建立一次连接,然后在循环里重复使用它的输入输出流来收发数据。下面是修改后的示例代码:
package test; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; public class TestClientSocket { public static void main(String args[]) throws IOException { final String host = "localhost"; final int portNumber = 81; System.out.println("Creating socket to '" + host + "' on port " + portNumber); // 只创建一次Socket,用try-with-resources自动管理资源关闭 try (Socket socket = new Socket(host, portNumber); BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintWriter out = new PrintWriter(socket.getOutputStream(), true); BufferedReader userInputBR = new BufferedReader(new InputStreamReader(System.in))) { while (true) { System.out.println("server says:" + br.readLine()); String userInput = userInputBR.readLine(); out.println(userInput); System.out.println("server says:" + br.readLine()); if ("exit".equalsIgnoreCase(userInput)) { break; } } } // try-with-resources会自动关闭Socket和所有流 } }
这里用了Java的try-with-resources语法,能自动帮我们关闭Socket和相关流,避免资源泄漏。只要服务器端也保持连接不关闭,这个Socket就能一直复用下去。
4. 每次新建Socket会不会导致性能变慢?
肯定会!因为每次创建Socket都要经历TCP三次握手的过程:客户端发SYN包,服务器回SYN+ACK包,客户端再发ACK包,这一来一回会消耗网络延迟;而且每次关闭Socket还要经历TCP四次挥手的过程。
如果频繁创建销毁Socket,这些握手、挥手的开销会不断累积,尤其是在高并发或者网络延迟较高的场景下,性能下降会非常明显。另外,操作系统对每个进程能打开的Socket数量是有限制的,频繁创建还可能导致资源耗尽,出现无法新建连接的错误。
内容的提问来源于stack exchange,提问作者Trt Trt
相关产品推荐
相关产品推荐

