java - windows下socket读取超时: strange hardcode in native method

标签 java c windows sockets java-native-interface

我试图了解如何在 native 代码中处理套接字读取超时,并在那里发现了一些奇怪的硬编码值 5000 毫秒:

if (timeout) {
    if (timeout <= 5000 || !isRcvTimeoutSupported) {
        int ret = NET_Timeout (fd, timeout);
        .....
        .....
    }
}

来源: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");
            }

        }
        ......
        ......
    }

来源: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

至于 5 秒阈值的来源,我最好的猜测是他们以某种方式发现(通过测试或反复试验?)select 对于超时值更可靠或更准确超过 5 秒。并不是说它与这个问题特别相关(它针对不同的操作系统),而是 here is an example有人报告 SO_RCVTIMEO 对于较小的超时值不可靠。

关于java - windows下socket读取超时: strange hardcode in native method,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49154522/

相关文章:

java - 在 Javassist 中修改行号

java - 如何使用行和列索引(TableCellRenderer)设置 JTable 中特定单元格的颜色

c - 双链表和二叉树的节点结构有什么区别?

c - ANSI C 我在 fwrite 和 fread 上做错了什么?

windows - 在 Windows 主机文件中使用端口号

java - Android:我想让recyclerView处于横向模式,所有应用程序处于纵向模式

java - 用于 Wicket 口概念和状态的数据绑定(bind)器

C# 字符指针,调用 C++ dll 函数和传递参数

windows - Inno Setup - 卸载程序时从 PATH 环境变量中删除路径

windows - 如何在 Windows 中修复 "git-sh-setup: file not found"?