use*_*601 6 c java sockets windows java-native-interface
我试图了解如何在本机代码中处理套接字读取超时,并发现一些奇怪的硬编码值,即5000毫秒:
if (timeout) {
if (timeout <= 5000 || !isRcvTimeoutSupported) {
int ret = NET_Timeout (fd, timeout);
.....
.....
}
}
Run Code Online (Sandbox Code Playgroud)
来源:http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/windows/native/java/net/SocketInputStream.c
我可以看到,变量isRcvTimeoutSupported通常设置为true,但在设置套接字选项时可能会被删除为false:
/*
* SO_RCVTIMEO is only supported on Microsoft's implementation
* of Windows Sockets so if WSAENOPROTOOPT returned then
* reset flag and timeout will be implemented using
* select() -- see SocketInputStream.socketRead.
*/
if (isRcvTimeoutSupported) {
jclass iCls = (*env)->FindClass(env, "java/lang/Integer");
jfieldID i_valueID;
jint timeout;
CHECK_NULL(iCls);
i_valueID = (*env)->GetFieldID(env, iCls, "value", "I");
CHECK_NULL(i_valueID);
timeout = (*env)->GetIntField(env, value, i_valueID);
/*
* Disable SO_RCVTIMEO if timeout is <= 5 second.
*/
if (timeout <= 5000) {
timeout = 0;
}
if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
sizeof(timeout)) < 0) {
if (WSAGetLastError() == WSAENOPROTOOPT) {
isRcvTimeoutSupported = JNI_FALSE;
} else {
NET_ThrowCurrent(env, "setsockopt SO_RCVTIMEO");
}
}
......
......
}
Run Code Online (Sandbox Code Playgroud)
来源:http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/windows/native/java/net/TwoStacksPlainSocketImpl.c
虽然我不太确定,看起来读取超时应该在高于5秒时通过套接字选项设置,如果小于或等于5秒则通过NET_Timeout设置.这是对的吗?
无论如何,这些硬编码5秒来自哪里?
我没有在MSDN上看到任何解释.
此代码决定如何实现阻塞套接字超时 - 是否使用SO_RCVTIMEO或 来实现select,因为 Windows 套接字支持两者(SO_RCVTIMEO并非所有平台都支持,甚至并非所有 Windows 实现都支持它,如代码注释中所述)。在幕后NET_Timeout使用。select
基本上算法是:
if SO_RCVTIMEO is supported and timeout is more than 5 seconds:
use SO_RCVTIMEO
else:
use select
Run Code Online (Sandbox Code Playgroud)
至于 5 秒阈值的来源,我最好的猜测是他们以某种方式(通过测试或反复试验?)发现select对于小于 5 秒的超时值更可靠或更准确。并不是说它与此问题具体相关(它适用于不同的操作系统),但这里有一个有人报告 SO_RCVTIMEO 对于小超时值不可靠的示例。
| 归档时间: |
|
| 查看次数: |
333 次 |
| 最近记录: |