欢迎关注Github:https://github.com/teaey/

### 背景

银时跟我讲,想从 Netty3迁移到Netty4 。


问其原因是由于 Netty3在容器里会报错,错误堆栈:

java.io.IOException: 无法马上完毕一个非阻止性套接字操作。

at sun.nio.ch.SocketDispatcher.close0(Native Method)

at sun.nio.ch.SocketDispatcher.preClose(SocketDispatcher.java:44)

at sun.nio.ch.SocketChannelImpl.implCloseSelectableChannel(SocketChannelImpl.java:677)

at java.nio.channels.spi.AbstractSelectableChannel.implCloseChannel(AbstractSelectableChannel.java:201)

at java.nio.channels.spi.AbstractInterruptibleChannel.close(AbstractInterruptibleChannel.java:97)

### 分析

看到这个问题,之前我也没有遇到过,只是假设 netty3有这个问题,netty4应该也会存在。那就看看究竟什么导致这个问题。

找到 SocketDispatcher的close0 方法,这是个本地方法:

找到 Windows的实现:

Windows平台通过调用closesocket( winsock2.h)关闭套接字。
接着查看巨硬的 官方文档,内容摘要:

if no error occurs, closesocket returns zero. Otherwise, a value of SOCKET_ERROR is
returned, and a specific error code can be retrieved by calling WSAGetLastError.

意思就是假设正确返回 0,假设错误返回SOCKET_ERROR。而且通过 WSAGetLastError函数获取错误状态。

这里非常明显是发生出错误向上抛出了异常。
通过分析 closesocket的错误状态信息以及谷歌“无法马上完毕一个非阻止性套接字操作”,确诊为错误状态 WSAEWOULDBLOCK  。

阅读 官方文档,得知该错误状态是设置了 SO_LINGER所致。

于是回过头去看下代码,果然,图为截取的 Netty代码片段:


巨硬的文档是这么说的:

Setting the l_onoff member of the  linger structure
to nonzero and the l_linger member with a nonzero timeout interval on a nonblocking socket is not recommended.

意思是,在非堵塞的 Socket情况下不建议设置SO_LINGER參数。

In this case, the call to  closesocket  will
fail with an error of WSAEWOULDBLOCK if
the close operation cannot be completed immediately. If  closesocket fails
with WSAEWOULDBLOCK the
socket handle is still valid, and a disconnect is not initiated. The application must call closesocket again to close the socket.

假设设置了 SO_LINGER,而且制定了超时时间,这时,我们调用 closesocket方法,方法不能马上完毕的话,会抛出 WSAEWOULDBLOCK  错误。可是,这个 socket此时还是有效的,能够一段时间之后再次调用 close方法进行关闭尝试。

### 解决方法

可是 java抛出简单IOException ,我们无法推断是否为 WSAEWOULDBLOCK  错误。非常难推断是否是由于其它原因导致的 IOException,所以不可能进行重试。

终于,解决方法去掉

这行代码。

改进之后,在调用 close方法时,不会抛出异常而且在底层 socket关闭前,系统会尽可能的把将缓冲队列的数据发送给对端。原文例如以下:

If the l_onoff member of the  LINGER structure
is zero on a stream socket, the closesocket call will return immediately and does not receive  whether the socket is blocking or nonblocking. However, any data queued for transmission will be sent, if possible, before the underlying socket is closed.

### 总结

在使用NIO 的时候,最好不要配置 SO_LINGER,假设设置了该參数,在 close的时候如缓冲区有数据待写出,会抛出 IOException。

后记:近期银时发现,Zookeeper之前的版本号也是有设置这个參数,而且在最新版本号去掉了这个參数,难道大神们的代码也是Ctrl+C,Ctrl+V过来的。呵呵。

### 參考资料

NIO设置SO_LINGER引发的异常的更多相关文章

  1. 选择目录,选择文件夹的COM组件问题。在可以调用 OLE 之前,必须将当前线程设置为单线程单元(STA)模式。请确保您的 Main 函数带有 STAThreadAttribute 标记。 只有将调试器附加到该进程才会引发此异常。

    异常: 在可以调用 OLE 之前,必须将当前线程设置为单线程单元(STA)模式.请确保您的 Main 函数带有 STAThreadAttribute 标记. 只有将调试器附加到该进程才会引发此异常. ...

  2. c# Clipboard.SetDataObject(bmp1) 在可以调用 OLE 之前,必须将当前线程设置为单线程单元(STA)模式。请确保您的 Main 函数带有 STAThreadAttribute 标记。 只有将调试器附加到该进程才会引发此异常

    c# Clipboard.SetDataObject(bmp1)  在可以调用 OLE 之前,必须将当前线程设置为单线程单元(STA)模式.请确保您的 Main 函数带有 STAThreadAttri ...

  3. 2019-4-12-WPF-类型的构造函数执行符合指定的绑定约束的调用时引发了异常

    title author date CreateTime categories WPF 类型的构造函数执行符合指定的绑定约束的调用时引发了异常 lindexi 2019-04-12 08:52:35 ...

  4. 调试器地址出现大小端紊乱,引发的异常: 0xC0000005: 读取位置 0xFFFFFFFFFFFFFFFF 时发生访问冲突。

    今天在编写一系列新增需求代码后,开始调试代码 发现上个版本正常可运行的代码出现了:引发的异常: 0xC0000005: 读取位置 0xFFFFFFFFFFFFFFFF 时发生访问冲突. 上个版本数代码 ...

  5. 将不确定变为确定~DateTime.MinValue和MaxValue引发的异常

    回到目录 问题描述: SqlDateTime 溢出.必须介于 1/1/1753 12:00:00 AM 和 12/31/9999 11:59:59 PM 之间 概念相关 .Net中的DateTime结 ...

  6. WPF控件ComboBox 每个Item的ToolTip引发的异常

    介绍 首先介绍下要实现的任务.做一个下拉框,当选择每个项的时候将鼠标发在上面显示该项的ToolTip的内容(Image). 实现 Model: public class SkinInfo : Noti ...

  7. VS2010 F5调试时出现:“ 尝试运行项目时出错:未捕获通过反射调用的方法引发的异常”解决

    VS2010 F5调试时出现 尝试运行项目时出错:未捕获通过反射调用的方法引发的异常 两个解决方法:1) 打开项目属性,选择调试选项卡,将“启用非托管代码调试”一项钩上.2) 打开项目属性,选择调试选 ...

  8. setsockopt 设置 SO_LINGER 选项

    setsockopt 设置 SO_LINGER 选项 最近和后台的server通信 server发现在读数据的时候  客户端已经关闭连接 ,也就是 没有等服务器读完数据,客户端已经fclose了, 联 ...

  9. WPF关于“在“System.Windows.Markup.StaticResourceHolder”上提供值时引发了异常。”问题解决办法

    在WPF中添加样式,在MainWindow.xaml使用自定义按钮FButton时报错,报错信息如下: "System.Windows.Markup.XamlParseException&q ...

随机推荐

  1. YZOI Easy Round 2_化简(simplify.c/cpp/pas)

    Description 给定一个多项式,输出其化简后的结果. Input 一个字符串,只含有关于字母x 的多项式,不含括号与分式,没有多余的空格. Output 一个字符串,化简后的多项式,按照次数从 ...

  2. css3学习--css3动画详解二(3d效果)

    一.设置3D场景 perspective:800       //浏览器到物体的距离(像素)perspective-origin:50% (x轴) 50% (y轴)    //视点的位置 transf ...

  3. 常用sql笔记

    Student(S#,Sname,Sage,Ssex) 学生表Course(C#,Cname,T#) 课程表SC(S#,C#,score) 成绩表Teacher(T#,Tname) 教师表问题:1.查 ...

  4. 下载安装sublime text3,打包sublime text3便携版,激活sublime text3,配置sublime text3的php环境

      下载安装sublime text3: http://www.sublimetext.com/3 安装就一直下一步   打包sublime text3便携版 : 参考http://segmentfa ...

  5. 百度云推送 pem

    1. p12证书导出 在钥匙串访问中选中推送证书,导出为个人信息交换文件(.p12格式). 选择文件格式.文件名和保存路径. 输入导出密码. 2. pem证书生成 将p12证书文件转换成pem证书文件 ...

  6. 从零开始学习MySQL1---MySQL基础

    数据库基础 数据库是一个长期存储在计算机内的.有组织的.有共享的.统一管理的.数据集合.它是一个按数据结构来存储和管理数据的计算机软件系统.数据库包含两层含义:保管数据的仓库,以及数据管理的方法和技术 ...

  7. 变更到Android4.4的问题

    更新到Android 4.4,写了个小程序.发现运行不起来了.抛空指针异常.debug模式下,发现在onCreate方法中获取Button是null. Android 4.4把layout进行了重组, ...

  8. Hadoop 学习笔记 (十一) MapReduce 求平均成绩

    china:张三 78李四 89王五 96赵六 67english张三 80李四 82王五    84赵六 86math张三 88李四 99王五 66赵六 77 import java.io.IOEx ...

  9. cademy的Java习题做后感

    在cademy各种语言的hello world也做了不少,好像都差不多,先是数据类型,然后条件语句,之后面向对象,再上几个特殊对象. 以前都没有做笔记,导致ruby做完就忘光了,这次好歹写点什么,比如 ...

  10. Children's Day

    hdu4706:http://acm.hdu.edu.cn/showproblem.php?pid=4706 题意:让你打出3--10的N,这个N是由连续的小写字母组成的. 题解:直接模拟啊,水题啊. ...