客户端套接字创建挂起在jdk1.8.0_25上

时间:2014-10-16 14:51:05

标签: java sockets applet hang

我们有一个连接到我们游戏服务器的小程序。由于两天我们收到用户抱怨无法连接的投诉。我将问题跟踪到以下代码:

System.err.println("<PO> creating socket host=" + host + ", port=" + port);
try {
    socket = new Socket(host, port);
} catch (Throwable t) {
    System.err.println("<PO> OOPS: " + t.getMessage());
    t.printStackTrace();
}
System.err.println("<PO> socket created");

输出如下:

<PO> creating socket host=<host deleted>, port=7754

然后applet挂起(没有cpu使用)。没有例外,但也没有“套接字创建”打印!请注意,此代码已成功运行多年(当然没有print和try / catch)。使用java 1.7它仍然运行良好,但使用java 1.8.0_25代码挂起。

“新套接字”呼叫在什么条件下可以挂起?

有没有人对如何进一步调试此问题有任何建议?

我找到了与strace相关的系统调用:

socket(PF_INET6, SOCK_STREAM, IPPROTO_IP) = 53
setsockopt(53, SOL_IPV6, IPV6_V6ONLY, [0], 4) = 0
fcntl(53, F_GETFL)                      = 0x2 (flags O_RDWR)
fcntl(53, F_SETFL, O_RDWR|O_NONBLOCK)   = 0
connect(53, {sa_family=AF_INET6, sin6_port=htons(7754), inet_pton(AF_INET6, "::ffff:<server ip in v4 format>", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 28) = -1 EINPROGRESS (Operation now in progress)
poll([{fd=53, events=POLLOUT}], 1, 120000) = 1 ([{fd=53, revents=POLLOUT}])
getsockopt(53, SOL_SOCKET, SO_ERROR, [0], [4]) = 0
fcntl(53, F_GETFL)                      = 0x802 (flags O_RDWR|O_NONBLOCK)
fcntl(53, F_SETFL, O_RDWR)              = 0
getsockname(53, {sa_family=AF_INET6, sin6_port=htons(52535), inet_pton(AF_INET6, "::ffff:<client ip in v4 format>", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, [28]) = 0
setsockopt(53, SOL_TCP, TCP_NODELAY, [1], 4) = 0

我怀疑'setsocketopt(... IPV6_V6ONLY ...)'调用:服务器肯定是IPV4!知道如何强制Java使用IPv4(或至少阻止Java使用IPV6_V6ONLY)?

1 个答案:

答案 0 :(得分:2)

我找到了原因和解决方案,所以现在是时候回答我自己的问题了,希望能帮助其他可怜的灵魂在这个页面上遇到同样的问题。

问题的根源在于Java 8签名小程序中的沙盒&#39;模式不再接收&#39; SocketPermission&#39;,只接受&#39; URLPermission&#39;。

当您拨打&#39; socket.connect()&#39; (或者&#39;新的Socket(主机,端口)&#39;进行连接),一些神奇的事情发生了,Java决定你必须打开一个http连接。然后它尝试获取&#39; /crossdomain.xml'使用http协议通过套接字文件。

这就是绊倒我的代码:我的自定义游戏服务器不会说http,也没有提供答案,同时保持套接字打开。 Java试图读取未来的响应,并且&#39; socket.connect()&#39;电话永远不会回来。

&#39;解决方案&#39;是applet必须在&#39;所有权限&#39;中运行模式打开常规套接字。具有讽刺意味的是,Java 8中更严格的安全性实际上迫使我们启用“所有权限”。