Java - 奇怪的挂插座?

时间:2009-12-16 17:54:12

标签: java sockets

我有一个带有java服务器的客户端 - 服务器应用程序。它的工作非常完美,只是经过一段时间后,突然间,一个插座一直悬挂着。这个套接字只是其中之一,其余的似乎仍然很好,但一旦进入套接字,服务器就不会超过发送线。这些是代码的相关部分:

Socket socket; // A normal socket
out  = new PrintWriter(socket.getOutputStream(), true); // The outstream
out.println(msg + "\0"); // This command is used to send stuff, msg is a String

没有抛出任何异常,行应用程序似乎没有超越该行:

out.println(msg + "\0");

我知道String是一个很好的,导致4或5个其他套接字,然后才能发送它。另请注意,据我所知,这个套接字可以在突然挂起之前发送数百条消息。有没有人知道我应该寻找什么样的错误?

2 个答案:

答案 0 :(得分:5)

有许多事情可能会导致这种情况,但听起来你可能会在TCP级别上受到反压。

通常,当您在套接字上发送数据时,它只是缓冲而发送调用(在您的情况下,println()flush())可以在数据实际发送到网络之前返回。可能是您在此套接字上的所有先前写入都被缓冲到本地SO_SNDBUF,您只需填写它。

(1)你能用tcpdump或Wireshark来追踪它,并找到挂起的确切连接(我知道这很难连接很多)?在程序挂起时检查TCP窗口大小将告诉您更多关于是在Java本身还是在网络级别阻止。

(2)转储堆栈并将其发布到此处。 Java套接字有一个内部锁,可以防止两个线程同时写入它们。您确定在您尝试编写时,只有一个线程正在访问该套接字吗?

你肯定想尝试做一个

$ jstack <PID>

当它被冻结以确切地看到它挂在哪里,以及写作线程是否试图获得任何锁定。

答案 1 :(得分:3)

Socket对象的OutputStream将在基础send()调用将阻止的相同条件下阻止写入:当本地套接字缓冲区已满时。它保持阻塞状态表示输出缓冲区无法清空,这反过来表明连接另一端的读缓冲区已满,处理连接另一端的应用程序未读取已到达的数据