我有一个带有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个其他套接字,然后才能发送它。另请注意,据我所知,这个套接字可以在突然挂起之前发送数百条消息。有没有人知道我应该寻找什么样的错误?
答案 0 :(得分:5)
有许多事情可能会导致这种情况,但听起来你可能会在TCP级别上受到反压。
通常,当您在套接字上发送数据时,它只是缓冲而发送调用(在您的情况下,println()
和flush()
)可以在数据实际发送到网络之前返回。可能是您在此套接字上的所有先前写入都被缓冲到本地SO_SNDBUF,您只需填写它。
(1)你能用tcpdump或Wireshark来追踪它,并找到挂起的确切连接(我知道这很难连接很多)?在程序挂起时检查TCP窗口大小将告诉您更多关于是在Java本身还是在网络级别阻止。
(2)转储堆栈并将其发布到此处。 Java套接字有一个内部锁,可以防止两个线程同时写入它们。您确定在您尝试编写时,只有一个线程正在访问该套接字吗?
你肯定想尝试做一个
$ jstack <PID>
当它被冻结以确切地看到它挂在哪里,以及写作线程是否试图获得任何锁定。
答案 1 :(得分:3)
Socket
对象的OutputStream
将在基础send()
调用将阻止的相同条件下阻止写入:当本地套接字缓冲区已满时。它保持阻塞状态表示输出缓冲区无法清空,这反过来表明连接另一端的读缓冲区已满,处理连接另一端的应用程序未读取已到达的数据