NIO设置SO_LINGER引发的异常

欢迎关注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过来的。呵呵。

### 参考资料

  1. http://msdn.microsoft.com/en-us/library/windows/desktop/ms737582(v=vs.85).aspx
  2. http://msdn.microsoft.com/en-us/library/windows/desktop/ms741580(v=vs.85).aspx
  3. http://msdn.microsoft.com/en-us/library/windows/desktop/ms740668(v=vs.85).aspx#WSAEWOULDBLOCK

NIO设置SO_LINGER引发的异常

时间: 2024-10-13 13:10:25

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

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

异常: 在可以调用 OLE 之前,必须将当前线程设置为单线程单元(STA)模式.请确保您的 Main 函数带有 STAThreadAttribute 标记. 只有将调试器附加到该进程才会引发此异常. 方法1: class Program { /// <summary> /// 图片资料文件同步 /// </summary> /// <param name="args"></param> [STAThread] //加这个属性,创建并进入单

mono 3.10 Socket引发未知异常的悲剧事情...

最近在做mono 3.10针对socket性能方面的测试,在想对压力比较高的情况下发现了mono的一个bug会导致程序引发未知异常从而导致程序结束的严重问题. 错误信息 Unhandled Exception: System.InvalidOperationException: EndSend can only be called once per asynchronous operation at System.Net.Sockets.Socket.EndSend (IAsyncResult

在MS单元测试中引发期望异常

首先准备一个引发异常的方法. 1 public static void ThrowException() 2 { 3 throw new ArgumentException(); 4 } 然后在单元测试项目中,写下测试方法. [TestMethod] [ExpectedException(typeof(ArgumentException))]// 构造函数中为期望引发的异常. public void ThrowExceptionTest() { Program.ThrowException();

C# WPF VS2012 对类型“ ”的构造函数执行符合指定的绑定约束的调用时引发了异常 问题解决办法 产生什么原因

运行程序时报 对类型"XX.XXX"的构造函数执行符合指定的绑定约束的调用时引发了异常 XX.XXX  代表命名空间.类 namespace Test { /// <summary> /// Test.xaml 的交互逻辑 /// </summary> public partial class Test : Test { public Test() { InitializeComponent(); // 报错位置 对类型" "的构造函数执行符

setsockopt 设置 SO_LINGER 选项

setsockopt 设置 SO_LINGER 选项 最近和后台的server通信 server发现在读数据的时候  客户端已经关闭连接 ,也就是 没有等服务器读完数据,客户端已经fclose了, 联调以后的发现需要设置这个选项: so_linger 此选项指定函数close对面向连接的协议如何操作(如TCP).内核缺省close操作是立即返回,如果有数据残留在套接口缓冲区中则系统将试着将这些数据发送给对方. SO_LINGER选项用来改变此缺省设置.使用如下结构: struct linger

因DataTable的字段值为DBNull引发的异常

1 问题重现 (1)新建项目DBNullExp,项目属性为"控制台应用程序": (2)在项目下新建数据集Schools(数据集文件的后缀名为.xsd): (3)在数据集下新建数据表Students,表字段的定义如下表所示: 字段名 说明 ID dc.DataType = Type.GetType("System.Int32");//类型 dc.AutoIncrement = true;//自动增量 dc.AutoIncrementSeed = 1;//起始为1 dc

int Parse方法引发的异常

今天,我们来介绍一下Parse方法引发的异常. 一.Parse方法(String): 首先,我们先来介绍一下这个Parse方法的主要作用,即将数字的字符串表示形式转换为它的等效 32 位有符号整数.在C++中,它的具体语法如下: public: static int Parse( String^ s ) 其中,参数是s,类型是String,包含要转换的数字的字符串.返回值是int,与 s 中包含的数字等效的 32 位有符号整数. Parse方法主要有三个异常: 1)System.Argument

Aircrack-ng设置监听模式异常

Aircrack-ng设置监听模式异常 aircrack-ng 在某些情况下,用户使用Aircrack-ng工具集中的airmon-ng命令,将无线网卡设置为监听模式时,会出现异常.如SIOCSIFFLA65:Name not unique on network等.此时,用户可以尝试使用iwconfig来设置.具体设置方法如下所示: (1)关闭无线网卡.执行如下命令: ifconfig wlan0 down (2)设置监听模式.执行命令如下所示: iwconfig wlan0 mode moni

0x0F19B7EC (ucrtbased.dll)处(位于 ex6.exe 中)引发的异常: 0xC0000005: 写入位置 0x00740000 时发生访问冲突。

下面的代码在编译,运行时没有问题,在输入内容是出现异常如下: 0x0F19B7EC (ucrtbased.dll)处(位于 ex6.exe 中)引发的异常: 0xC0000005: 写入位置 0x00740000 时发生访问冲突. #include "stdafx.h"#include <conio.h>#include <stdio.h> int main(){ int NUM, I; struct STUDENT { char NAME[30]; int A