TCP通信中一方关闭socket,另一方被强制退出(SIGPIPE)
参考博客:1、参考链接
一、问题来源
Linux上一个TCP服务器负责采集发送图片数据,windows客户端接收数据,当客户端关闭socket或者退出时,服务器进程被强制退出。
二、分析(网络)
具体的分析可以结合TCP的"四次握手"关闭. TCP是全双工的信道, 可以看作两条单工信道, TCP连接两端的两个端点各负责一条. 当对端调用close时, 虽然本意是关闭整个两条信道, 但本端只是收到FIN包. 按照TCP协议的语义, 表示对端只是关闭了其所负责的那一条单工信道, 仍然可以继续接收数据. 也就是说, 因为TCP协议的限制, 一个端点无法获知对端的socket是调用了close还是shutdown.对一个已经收到FIN包的socket调用read方法, 如果接收缓冲已空, 返回0, 这就是常说的表示连接关闭. 但第一次对其调用write方法时, 如果发送缓冲没问题, 会返回正确写入(发送). 但发送的报文会导致对端发送RST报文, 因为对端的socket已经用了close, 完全关闭, 既不发送, 也不接收数据. 所以, 第二次调用write方法(假设在收到RST之后), 会生成SIGPIPE信号, 导致进程退出.
为了避免进程退出, 可以捕获SIGPIPE信号, 或者忽略它, 给它设置SIG_IGN信号处理函数:
signal(SIGPIPE, SIG_IGN);
这样, 第二次调用write方法时, 会返回-1, 同时errno置为SIGPIPE. 程序便能知道对端已经关闭.
在linux下写socket的程序的时候,如果尝试send到一个disconnected socket上,就会让底层抛出一个SIGPIPE信号。这个信号的缺省处理方法是退出进程,大多数时候这都不是我们期望的。因此我们需要重载这个信号的处理方法。调用以下代码,即可安全的屏蔽SIGPIPE:
signal (SIGPIPE, SIG_IGN);
系统里边定义了三种处理方法:
(1)SIG_DFL信号专用的默认动作:
(a)如果默认动作是暂停线程,则该线程的执行被暂时挂起。当线程暂停期间,发送给线程的任何附加信号都不交付,直到该线程开始执行,但是SIGKILL除外。
(b)把挂起信号的信号动作设置成SIG_DFL,且其默认动作是忽略信号 (SIGCHLD)。
(2)SIG_IGN忽略信号
(a)该信号的交付对线程没有影响
(b)系统不允许把SIGKILL或SIGTOP信号的动作设置为SIG_DFL
(3)SIG_ERR
三、我的用法
1、包含头文件:
#include <signal.h>
2、声明定义一个处理函数
void signal_handler(int sigm);
2、在产生信号产生前调用一下代码:
struct sigaction act;
memset(&act,0,sizeof(act));
// act.sa_handler = SIG_IGN;//设定接受到指定信号后的动作为忽略
act.sa_handler = signal_handler;//设定接受到指定信号后的动作为 相关函数
act.sa_flags = 0;
sigemptyset(&act.sa_mask);
sigaction(SIGPIPE,&act,NULL);//屏蔽SIGPIPE信号
sigaction(SIGCHLD,&act,NULL);//屏蔽子进程终结信号,让init进程去处
TCP通信中一方关闭socket,另一方被强制退出(SIGPIPE)相关推荐
- TCP通信中服务器处理客户端意外断开
如果TCP连接被对方正常关闭,也就是说,对方是正确地调用了closesocket(s)或者shutdown(s)的话,那么上面的Recv或Send调用就能马上返回,并且报错.这是由于close soc ...
- Tcp通信中服务器处理客户端意外断开!
所谓意外断开,是客户端(多指支持3G的移动设备)并没有正常关闭socket,双方并未按照协议上的四次挥手去断开连接,一般的处理办法都是利用保活机制.而保活机制分又可以让底层实现也可自己实现. 一.双方 ...
- 网络通信-2(TCP通信、ServerSocket、Socket)
1. TCP通信 UDP中只有发送端和接收端,不区分客户端和服务器端.计算机之间可以任意地发送消息. TCP通信严格区分客户端和服务器. 通信时,必须由客户端去连接服务器才能实现通信.服务器不可主动连 ...
- TCP通信中的三次握手与四次挥手
下图是一次TCP通讯的时序图 TCP通讯时序 在这个例子中,首先客户端主动发起连接.发送请求,然后服务器端响应请求,然后客户端主动关闭连接.两条竖线表示通讯的两端,从上到下表示时间的先后顺序,注意,数 ...
- 【Android Protobuf 序列化】Protobuf 服务器与客户端通信 ( TCP 通信中使用 Protobuf )
文章目录 一.TCP 粘包和分包 二.TCP 粘包和分包解决方案 三.客户端 Android 应用使用 Protobuf 四.服务器端 Java 服务器使用 Protobuf 五.参考资料 一.TCP ...
- linux不保存强制退出指令,vi中哪条命令是不保存强制退出_网站服务器运行维护...
linux中vi查找关键字的方法_网站服务器运行维护 linux中vi查找关键字的方法:进入vi中,先按下"ESC"跳转成命令输入模式,输入斜杠"/",然后输入 ...
- java tcp read_【Java TCP/IP Socket】TCP Socket通信中由read返回值造成的的死锁问题(含代码)(转)...
书上示例 在第一章<基本套接字>中,作者给出了一个TCP Socket通信的例子--反馈服务器,即服务器端直接把从客户端接收到的数据原原本本地反馈回去. 书上客户端代码如下: 书上的服务器 ...
- 【Java TCP/IP Socket】TCP Socket通信中由read返回值造成的的死锁问题(含代码)(转)...
书上示例 在第一章<基本套接字>中,作者给出了一个TCP Socket通信的例子--反馈服务器,即服务器端直接把从客户端接收到的数据原原本本地反馈回去. 书上客户端代码如下: 1 2 3 ...
- 2-4:套接字(Socket)编程之TCP通信
文章目录 一 TCP通信服务端和客户端--和UDP区别 (1)服务端 (2)客户端 二:TCP通信-多进程/线程 (1)多进程版本 (2)多线程版本 (3)线程池版本 一 TCP通信服务端和客户端-- ...
最新文章
- 利用Mycat中间件实现RDS MySQL的分库分表及读写分离功能
- JavaScript闭包小窥
- 类的成员函数与内联以及静态成员
- oracle用EXPLAIN PLAN 分析SQL语句
- mysql myisam 支持事务吗_第三章(附)mysql表类型MyISAM和InnoDB区别(决定了是否支持事务)...
- ETL异构数据源Datax_数据准备_03
- linux udp 端口映射,Linux下的UDP/TCP端口映射(netcat and socat)
- pyqt5获取显示器的分辨率
- EJB 开发环境与入门实例
- oracle 函数 如何编写
- vue数据双向绑定,Android-MVP模式详解,附超全教程文档
- 一个美国人在上海-American McGee
- 实验室建立计量管理体系的重要性和意义
- p2p与反p2p的博弈,一劳永逸真的不容易么
- 2011年6个微博营销趋势
- git报错:fatal: 无法为 ‘https‘ 找到远程助手
- 1+X 网络系统 建设与运维(中级)实验
- 迪杰斯特拉(dijkstra)-两个地铁站最短距离
- 微信小程序云开发csv导入数据库中文乱码问题解决
- 东东动态夏目猫咪老师404官网html源码