Java 客户端SocketInputStream.close()是否会导致更多的资源消耗?
如果我在没有“inputStream.close()”行的情况下执行下面的JUnit测试(请参见下文),那么可以处理60000多个请求(当时我终止了该进程)。在这一行中,我没有提出超过15000个请求,因为:Java 客户端SocketInputStream.close()是否会导致更多的资源消耗?,java,windows,performance,sockets,Java,Windows,Performance,Sockets,如果我在没有“inputStream.close()”行的情况下执行下面的JUnit测试(请参见下文),那么可以处理60000多个请求(当时我终止了该进程)。在这一行中,我没有提出超过15000个请求,因为: java.net.SocketException: No buffer space available (maximum connections reached?): connect at java.net.PlainSocketImpl.socketConnect(Native
java.net.SocketException: No buffer space available (maximum connections reached?): connect
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:351)
at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:213)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:200)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366)
at java.net.Socket.connect(Socket.java:529)
at java.net.Socket.connect(Socket.java:478)
at java.net.Socket.<init>(Socket.java:375)
at java.net.Socket.<init>(Socket.java:189)
at SocketTest.callServer(SocketTest.java:60)
at SocketTest.testResourceConsumption(SocketTest.java:52)
java.net.SocketException:没有可用的缓冲区空间(已达到最大连接数?):连接
位于java.net.PlainSocketImpl.socketConnect(本机方法)
位于java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:351)
位于java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:213)
在java.net.PlainSocketImpl.connect(PlainSocketImpl.java:200)
位于java.net.socksocketimpl.connect(socksocketimpl.java:366)
位于java.net.Socket.connect(Socket.java:529)
位于java.net.Socket.connect(Socket.java:478)
位于java.net.Socket(Socket.java:375)
位于java.net.Socket(Socket.java:189)
在SocketTest.callServer上(SocketTest.java:60)
测试资源消耗(SocketTest.java:52)
我在Windows上运行它,在开始测试之前,我等待netstat列表恢复正常
问题:
- 在这种情况下,为什么在客户端调用socketInputStream.close()会造成伤害
- 或者代码有什么问题
import java.io.IOException;
导入java.io.InputStream;
导入java.io.OutputStream;
导入java.net.ServerSocket;
导入java.net.Socket;
导入junit.framework.TestCase;
公共类SocketTest扩展了TestCase{
专用静态最终int端口=12345;
私有服务器套接字服务器套接字;
public void setUp()引发异常{
serverSocket=新的serverSocket(端口);
新线程(newrunnable()){
@凌驾
公开募捐{
while(true){
试一试{
最终套接字=serverSocket.accept();
新线程(newrunnable()){
@凌驾
公开募捐{
试一试{
OutputStream OutputStream=socket.getOutputStream();
对于(int i=0;i<100;i++){
outputStream.write(i);
}
outputStream.close();
//事实上,前一行已经调用了:
//socket.close();
}捕获(IOE异常){
抛出新的运行时异常(e);
}
}
}).start();
}捕获(例外e){
抛出新的运行时异常(e);
}
}
}
}).start();
}
public void testResourceConsumption()引发异常{
对于(int i=0;i当显式调用inputStream.close()时)
更改TCP优雅连接释放的顺序。在这种情况下,连接的客户端在从服务器接收FIN数据包之前关闭,从而使套接字处于TIME\u WAIT状态。在某个时候,用于传出连接的所有本地端口都被这些TIME\u WAIT套接字占用,不再有传出连接c必须作出决定
当您不调用inputStream.close()
时,服务器端会通过调用outputStream.close()
关闭连接。客户端套接字有足够的时间从服务器接收FIN,然后在垃圾收集时,它们会通过终结器方法正常关闭
有两个选项可以修复测试中的过程:
更好的方法是继续从inputStream
读取,直到您收到-1,这意味着另一方已经启动了连接关闭(即接收到FIN)。只需在inputStream.close()之前插入assertEquals(-1,inputStream.read());
第二个选项是通过设置
clientSocket.setSoLinger(true,0);
在这种情况下,inputStream.close()
将强制客户端发送RST并中止连接
确定你没有背对背吗?你能提供有关Windows版本、平台32或64位以及java版本的更多信息吗?仅供参考,我在Ubuntu 15.04上运行了你的测试。它完成了所有百万次迭代,没有错误。在执行期间的任何给定时间,状态时间中大约有28000个套接字等待。(这是由于执行和打开新套接字的速度)作为参考,只有第二个选项(强制关闭)在OSX上的Java8上对我有效。
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import junit.framework.TestCase;
public class SocketTest extends TestCase {
private static final int PORT = 12345;
private ServerSocket serverSocket;
public void setUp() throws Exception {
serverSocket = new ServerSocket(PORT);
new Thread(new Runnable() {
@Override
public void run() {
while(true) {
try {
final Socket socket = serverSocket.accept();
new Thread(new Runnable() {
@Override
public void run() {
try {
OutputStream outputStream = socket.getOutputStream();
for(int i = 0; i < 100; i++) {
outputStream.write(i);
}
outputStream.close();
// in fact the previous line calls this already:
// socket.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}).start();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}).start();
}
public void testResourceConsumption() throws Exception {
for (int i=0; i<1000000; i++) {
callServer();
if (i % 1000 == 0) {
System.out.println(i);
}
}
}
private void callServer() throws Exception {
Socket clientSocket = new Socket("localhost", PORT);
InputStream inputStream = clientSocket.getInputStream();
for (int i = 0; i < 100; i++) {
assertEquals(i, inputStream.read());
}
///////////////// THIS LINE IS INTERESTING
inputStream.close();
// in fact the previous line calls this already:
// clientSocket.close();
}
public void tearDown() throws Exception {
serverSocket.close();
}
}