ECONNRESET和WSAECONNRESET怎么产生的以及如何避免

ECONNRESET是linux环境网络编程产生的错误,错误码为104,

WSAECONNRESET是windows环境网络编程产生的错误,错误码为10054

两者产生的原因都一样,分以下几种情况:

1接收端recv或者read, 对端已经关闭连接,recv/read返回该错误

2 对端重启连接,还未建立连接

3 发送端已经断开连接,但是调用send会触发这个错误

第二点第三点都可以通过判断返回值解决,第一点在一些砍死正常情况下也会触发该错误。

比如对端close(fd),接收端调用recv并没有返回0,而是-1,打印错误码为104或

10054,按道理讲这种情况按照返回值为0处理是可以的,但是尽量将代码写的规范一些,

避免不必要的错误。

为什么close(fd)会导致接收端读到复位RST,也就是收到错误的104呢,

因为close(fd)只是将文件描述符关闭,并没有关闭tcp建立起来的连接,断开连接需要四次握手,

倘若发送端发送缓冲区有数据未发送完或者接受缓冲区有数据未读完,调用close(fd),那么连接并没有关闭,这样,接收端

收到的就是所谓的104或10054错误了。如何避免这个错误呢,就需要我们判断发送端发送和接受操作

是否进行完,也就是判断缓冲区是否有数据,如果有数据需要等待数据处理完毕在关闭,否则会出现上述错误。

我有一个做法是通过调用shutdown(s,SHUT_WR);关闭发送端的写端,这样发送端不发送数据,然后调用close

这次会发送关闭连接的FIN标志,接收端接收到FIN,那么recv或者read返回的就是0.

int shutdown(int sockfd,int how);
  Sockfd是需要关闭的socket的描述符。参数 how允许为shutdown操作选择以下几种方式:
    SHUT_RD:关闭连接的读端。也就是该套接字不再接受数据,任何当前在套接字接受缓冲区的数据将被丢弃。

  进程将不能对该套接字发出任何读操作。

  对 TCP套接字该调用之后接受到的任何数据将被确认然后无声的丢弃掉。
    SHUT_WR:关闭连接的写端,进程不能在对此套接字发出写操作
    SHUT_RDWR:相当于调用shutdown两次:首先是以SHUT_RD,然后以SHUT_WR

下面摘用网上的一段话来说明二者的区别:
close-----关闭本进程的socket id,但链接还是开着的,用这个socket id的其它进程还能用这个链接,能读或写这个socket id
shutdown--则破坏了socket 链接,读的时候可能侦探到EOF结束符,写的时候可能会收到一个SIGPIPE信号,这个信号可能直到
socket buffer被填充了才收到。

close(sockfd);使用close中止一个连接,但它只是减少描述符的参考数,并不直接关闭连接,只有当描述符的参考数为0时才关闭连接。

而且shutdown只是处理连接关闭,并不能回收描述符,所以最终还是要调用close(fd)才能回收描述符,在所有描述符引用次数为0时发送

FIN消息给对端。

出了采取shutdown的方式,还可以通过设置socket属性,调用close时,检测在socket完成缓冲区读写后,才关闭连接。

struct linger {

     int l_onoff; /* 0 = off, nozero = on */

     int l_linger; /* linger time */

};

有下列三种情况:

1、设置 l_onoff为0,则该选项关闭,l_linger的值被忽略,等于内核缺省情况,close调用会立即返回给调用者,如果可能将会传输任何未发送的数据;

2、设置 l_onoff为非0,l_linger为0,则套接口关闭时TCP夭折连接,TCP将丢弃保留在套接口发送缓冲区中的任何数据并发送一个RST给对方,而不是通常的四分组终止序列,这避免了TIME_WAIT状态;

3、设置 l_onoff 为非0,l_linger为非0,当套接口关闭时内核将拖延一段时间(由l_linger决定)。如果套接口缓冲区中仍残留数据,进程将处于睡眠状态,直 到(a)所有数据发送完且被对方确认,之后进行正常的终止序列(描述字访问计数为0)或(b)延迟时间到。

下面是代码:

int z;
 int s;
 struct linger so_linger;

 so_linger.l_onoff = 1
 so_linger.l_linger = 30;
 z = setsockopt(s,SOL_SOCKET,SO_LINGER,&so_linger,
     sizeof so_linger);
 if ( z )
     perror("setsockopt(2)");
     close(s);

到目前为止,我觉得比较好的主动关闭方式是:

关闭端:

1确保发送缓存区没有数据未发送,调用shutdown(fd,SHUTWR);

2如果能接收到数据,继续接受,直到接收到对方的FIN,也就是

read返回0或者-1

3如果接收到关闭信号,那么调用close正常关闭。

谢谢关注我的公众号:

时间: 2024-10-16 08:01:56

ECONNRESET和WSAECONNRESET怎么产生的以及如何避免的相关文章

关于Node.js的httpClieint请求报错ECONNRESET的原因和解决措施

背景说明 最近在工作项目中有下面一个场景: 使用Node.js的express框架实现了一个文件系统服务器端,其中有个API用于客户端上传文件.客户端使用Node.js的HttpClient来调用服务器端的API上传文件. 客户端在上传小文件时没有任何问题,在上传大文件时httpClient请求报错了下面的错误, { [Error: socket hang up] code: 'ECONNRESET' } google了很多资料,最后看了一下Node.js的相关源码终于知道了该问题的原因和解决办

java.net.SocketException: recvfrom failed: ECONNRESET (Connection reset by peer)

java.net.SocketException: recvfrom failed: ECONNRESET (Connection reset by peer)11-22 14:49:16.870: WARN/System.err(3581):     at libcore.io.IoBridge.maybeThrowAfterRecvfrom(IoBridge.java:542)11-22 14:49:16.870: WARN/System.err(3581):     at libcore.

在Android程序中使用Modbus协议时报 java.net.SocketException: recvfrom failed: ECONNRESET解决办法

最近在开发基本Modbus协议的Android端PLC控制程序,C#版程序没有任何问题,移到JAVA下出现各种问题,其中比较苦恼的是java.net.SocketException: recvfrom failed: ECONNRESET错误. 开始我的解决方法是每次向PLC发送一条数据后关掉socket,但是这样做太极端了. 经过分析发现是由于发送的数据包大小我设定为256,当写入1个寄存器值时,Modbus服务端直接报错,关掉了socket连接,将发送的数据包大小改成实际的大小后解决问题.

Error: read ECONNRESET

启动使用ionic serve启动服务器之后只要一刷新界面就会导致服务器关闭,报的错误如下: events.js:136 throw er; // Unhandled 'error' event ^ Error: read ECONNRESET at _errnoException (util.js:999:13) at TCP.onread (net.js:629:25) 删除node_modules/ws目录,然后在项目目录启动命令行,输入 npm install [email protec

gem install 出现Errno::ECONNRESET 使用RubyGems 镜像 - 淘宝网

由于国内网络原因(你懂的),导致 rubygems.org 存放在 Amazon S3 上面的资源文件间歇性连接失败.所以你会与遇到 gem install rack 或 bundle install的时候半天没有响应,具体可以用 gem install rails -V 来查看执行过程. 这是一个完整 rubygems.org 镜像,你可以用此代替官方版本,同步频率目前为15分钟一次以保证尽量与官方服务同步. $ gem sources --remove https://rubygems.or

【Java】 java.net.SocketException: recvfrom failed: ECONNRESET

今天碰到了这个异常,错误代码就不贴了,把答案记下. ok, the answer was that it's the server's fault - it had to close the connection after each request . it might be that android keeps a pool of connections and use the old one or something like that . anyway , now it works. E

gem install 出现Errno::ECONNRESET: Connection reset by peer - SSL_connect (https://api.rubygems.org

在安装了rvm来管理多版本的ruby之后,想在不同环境下安装一些gems,结果gem install puma 之后,发现一次又一次失败. 起初以为原因是:可能因为openssl上次的心血漏洞,使得服务器更新了ssl,拒绝所有低版本的ssl链接. 于是解决办法: 1. rvm pkg install openssl 2. rvm reinstall all --force 发现没用, 后来在淘宝的网站上发现了相同的描述,才发现是GFW的原因,他们提供了一个gem server. $ gem so

kibana6 访问出现"code":"ECONNRESET"

问题描述 ELK6.2.3日志系统,访问kibana界面出现该提示,无法访问后端es数据,但是es集群是健康状态 问题原因 kibana默认每2.5秒对es集群进行健康检查,如果短时间内没有数据返回,出现该报错 相关配置参数:elasticsearch.healthCheck.delay 代码如下: kibana/src/core_plugins/elasticsearch/lib/health_check.js const callDataAsKibanaUser = server.plugi

IOCP扩展方法AcceptEx, DisconnectEx, GetAcceptExSockaddr用法示例

这篇文章记录了我刚接触IOCP模型时的理解,对于初学者,应该算不错的调试程序,仅有一个400多行代码的dpr文件,可以直接用WriteLn输出信息,前提是会用delphi建立Console Application,当然你也可以很容易的就改成了C控制台程序或是其它语言.附加代码中有详细的注释,如果你已有IOCP经验,那么请不用在此浪费时间,这个示例不适合你.示例仅展示了IOCP中AcceptEx, DisconnectEx, GetAcceptExSockaddr等的用法.在文章最后有推荐的两个连