我怀疑这可能是导致服务器代码中长时间或无限循环/无限等待的原因,而Jetty根本没有机会关闭连接(除非有某种超时在一段时间后强制关闭套接字)。请考虑以下示例:
public class TestSocketClosedWaitState
{
private static class SocketResponder implements Runnable
{
private final Socket socket;
//Using static variable to control the infinite/waiting loop for testing purposes, with while(true) Eclipse would complain of dead code in writer.close() -line
private static boolean infinite = true;
public SocketResponder(Socket socket)
{
this.socket = socket;
}
@Override
public void run()
{
try
{
PrintWriter writer = new PrintWriter(socket.getOutputStream());
writer.write("Hello");
//Simulating slow response/getting stuck in an infinite loop/waiting something that never happens etc.
do
{
Thread.sleep(5000);
}
while(infinite);
writer.close(); //The socket will stay in CLOSE_WAIT from server side until this line is reached
}
catch(Exception e)
{
e.printStackTrace();
}
System.out.println("DONE");
}
}
public static void main(String[] args) throws IOException
{
ServerSocket serverSocket = new ServerSocket(12345);
while(true)
{
Socket socket = serverSocket.accept();
Thread t = new Thread(new SocketResponder(socket));
t.start();
}
}
}
将 -变量设置为 true 时,Printwriter(和底层套接字)永远不会由于无限循环而关闭。如果我运行这个并使用telnet连接到套接字,然后退出telnet客户端,将显示服务器端套接字仍处于-状态(我也可以看到客户端套接字处于FIN_WAIT2状态一段时间,但它会消失):infinite
netstat
CLOSE_WAIT
~$ netstat -anp | grep 12345
tcp6 0 0 :::12345 :::* LISTEN 6460/java
tcp6 1 0 ::1:12345 ::1:34606 CLOSE_WAIT 6460/java
服务器端接受的套接字卡在 CLOSE_WAIT -状态。如果我检查进程的线程堆栈,我可以看到线程在do...而 -循环:
~$ jstack 6460
<OTHER THREADS>
"Thread-0" prio=10 tid=0x00007f424013d800 nid=0x194f waiting on condition [0x00007f423c50e000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at TestSocketClosedWaitState$SocketResponder.run(TestSocketClosedWaitState.java:32)
at java.lang.Thread.run(Thread.java:701)
<OTHER THREADS...>
如果我将 -变量设置为 false,并执行相同的操作(连接客户端和断开连接),则具有 -state 的套接字将显示,直到编写器关闭(关闭底层套接字),然后消失。如果编写器或套接字从未关闭,即使线程终止,服务器端套接字也会再次卡住(我不认为这应该发生在Jetty中,如果你的方法在某个时候返回,Jetty可能应该负责关闭套接字)。infinite
CLOSE_WAIT
CLOSED_WAIT
因此,我建议您尝试找到罪魁祸首的步骤是
- 将日志记录添加到您的方法中,以查看它们正在做什么
- 检查你的代码,是否有任何地方的执行可能会陷入无限循环或需要很长时间,从而阻止底层套接字被关闭?
- 如果仍然发生,请在下次出现此问题时从正在运行的 Jetty 进程中获取线程转储,并尝试识别任何“卡住”的线程
jstack
- 是否有可能抛出一些东西(OutOfMemoryError等),这些东西可能不会被调用你的方法的底层Jetty架构捕获?我从来没有偷看过Jetty的内部,它很可能是捕捉到的,所以这可能不是问题,但如果所有其他方法都失败了,也许值得检查一下。
Throwable
当线程进入和退出您的方法时,您还可以使用类似如下方式命名线程
String originalName = Thread.currentThread().getName();
Thread.currentThread().setName("myMethod");
//Your code...
Thread.currentThread().setName(originalName);
如果有很多线程正在运行,可以更容易地发现它们。