我们有一个连接到游戏服务器的applet。两天以来,我们收到了用户的投诉,他们说我们无法连接。我追踪到了下面的代码:
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然后小程序就挂起了(没有cpu使用率)。没有异常,但也没有‘套接字创建’打印!注意,这段代码已经成功运行了很多年(当然没有打印和try/catch )。在java1.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)吗?
发布于 2014-10-17 18:11:12
我已经找到了原因和解决方案,所以是时候回答我自己的问题了,希望能帮助其他在这一页上遇到同样问题的可怜的人。
问题的根源在于,在Java 8中,处于“沙盒”模式的签名小程序不再接收“SocketPermission”,而只接收“URLPermission”。
当你调用'socket.connect()‘(或者'new Socket(host,port)’进行连接时,一些神奇的事情发生了,Java决定你必须打开一个http连接。然后,它会尝试使用http协议通过套接字获取“/Crossdomain.xml”文件。
这就是我的代码出错的原因:我的自定义游戏服务器不会说http,并且在保持套接字打开的同时也没有提供答案。Java尝试读取没有到来的响应,'socket.connect()‘调用再也没有返回。
“解决方案”是小程序必须在“所有权限”模式下运行才能打开常规套接字。具有讽刺意味的是,Java 8中加强的安全性实际上迫使我们启用“所有权限”。
https://stackoverflow.com/questions/26407417
复制相似问题