linux下网络程序遭遇SIGPIPE的解决(转)

http://blog.chinaunix.net/uid-20135786-id-3409085.html

问题描述:

我的一个服务器程序, 在Windows下运行正常.

但当在Linux(centos 6.3)下,进行对端未开启的异常测试时,出现莫名退出 . 最后跟踪到是write调用导致退出. 用gdb执行程序, 退出时提示"Broken pipe".

问题分析:

对一个对端已经关闭的socket调用两次write, 第二次将会生成SIGPIPE信号, 该信号默认结束进程.

具体的分析可以结合TCP的”四次握手”关闭. TCP是全双工的信道, 可以看作两条单工信道, TCP连接两端的两个端点各负责一条. 当对端调用close时, 虽然本意是关闭整个两条信道, 但本端只是收到FIN包. 按照TCP协议的语义, 表示对端只是关闭了其所负责的那一条单工信道, 仍然可以继续接收数据. 也就是说, 因为TCP协议的限制, 一个端点无法获知对端已经完全关闭.

对一个已经收到FIN包的socket调用read方法, 如果接收缓冲已空, 则返回0, 这就是常说的表示连接关闭. 但第一次对其调用write方法时, 如果发送缓冲没问题, 会返回正确写入(发送). 但发送的报文会导致对端发送RST报文, 因为对端的socket已经调用了close, 完全关闭, 既不发送, 也不接收数据. 所以, 第二次调用write方法(假设在收到RST之后), 会生成SIGPIPE信号, 导致进程退出.

解决办法:

为了避免进程退出, 可以捕获SIGPIPE信号, 或者忽略它, 给它设置SIG_IGN信号处理函数:

signal(SIGPIPE, SIG_IGN);

这样, 第二次调用write方法时, 会返回-1, 同时errno置为SIGPIPE. 程序便能知道对端已经关闭.

PS: Linux下的SIGALRM似乎会每1秒钟往后偏移1毫秒, 但Windows下经过测试完全准时, 不差1毫秒.

忽略SIGPIPE信号的方法
struct sigaction sa;
sa.sa_handler = SIG_IGN;//设定接受到指定信号后的动作为忽略
sa.sa_flags = 0;
if (sigemptyset(&sa.sa_mask) == -1 ||   //初始化信号集为空
sigaction(SIGPIPE, &sa, 0) == -1) {   //屏蔽SIGPIPE信号
perror("failed to ignore SIGPIPE; sigaction");
exit(EXIT_FAILURE);
}

pthread线程里如何屏蔽SIGPIPE异常
hi.baidu.com/ailacy/blog/item/a7eb65f8b8b55707d8f9fdd5.html
http://bbs2.chinaunix.net/viewthread.php?tid=985166&extra=&page=1
在pthread中,可能会遇到Program received signal SIGPIPE, Broken pipe的问题,解决方法是每一个线程启动之前时,先执行下面代码:

#ifndef WIN32
sigset_t signal_mask;
sigemptyset (&signal_mask);
sigaddset (&signal_mask, SIGPIPE);
int rc = pthread_sigmask (SIG_BLOCK, &signal_mask, NULL);
if (rc != 0) {
printf("block sigpipe error\n");

#endif        
当然,这只是多种方法之一~

根据赖半仙的使用经验,只要在main函数一开始就写入上面这段代码,就能屏蔽掉pthread线程中的SIGPIPE

[linux] SIGPIPE信号及其处理
http://hi.baidu.com/mckeyzhang/blog/item/d647f26034eee542eaf8f823.html
在linux下写socket的程序的时候,如果尝试send到一个disconnected socket上,就会让底层抛出一个SIGPIPE信号。
这个信号的缺省处理方法是退出进程,大多数时候这都不是我们期望的。因此我们需要重载这个信号的处理方法。调用以下代码,即可安全的屏蔽SIGPIPE:
struct sigaction sa;
sa.sa_handler = SIG_IGN;
sigaction( SIGPIPE, &sa, 0 );
//======================================================================
SIGPIPEFrom Wikipedia, the free encyclopediaJump to: navigationsearch SIGPIPE Description Write on a pipe with no one to read it Default action Abnormal termination of the process SA_SIGINFOmacros one

On POSIX-compliant platforms, SIGPIPE is the signal raised when a computer program attempts to write to a pipe without a process connected to the other end. The symbolic constant for SIGPIPE is defined in the header file signal.h. Symbolic signal names are used because signal numbers can vary across platforms.

Etymology

SIG is a common prefix for signal names. PIPE refers to the Unix pipe.

Description

Unix supports the principle of piping, which allows processes to send data to other processes without the need for creating temporary files. When a pipe is broken, the process writing to it is sent the SIGPIPE signal. The default reaction to this signal for a process is to terminate.

A simple example of piping is the following.

ps l | head

This command, when run on a Unix-like machine (including Linux), returns a list of processes, limited to ten lines.

  • ps l returns a list of all processes (including those of other users).
  • head selects the first ten lines.

When ps has written ten lines, head has received all it needs and exits. ps will receive a SIGPIPE when it tries to write the remaining lines, causing it to terminate as well: It is no use writing data that no one will use. It is also possible that the reading process terminates while reading the data. This will also cause SIGPIPE to be sent to the writing process.

One can ignore SIGPIPE (using, for example, the signal system call). In this case, all system calls that would cause SIGPIPE to be sent will return -1 and set errno to EPIPE.

Uinx 下 Broken pipe 问题

www.javaeye.com/topic/456975#

前段时间在处理延时函数时遇到过 "Alarm clock" 信号问题(见我的 "Unix C 延时函数小结")。现在测试中还遇到了 "Broken pipe" 信号问题,同样产生这个信号程序就中止了。

我的程序产生这个信号的原因是: 
client端通过 pipe 发送信息到server端后,就关闭client端, 这时server端,返回信息给 client 端时就产生Broken pipe 信号了。

对于产生信号,我们可以在产生信号前利用方法 signal(int signum, sighandler_t handler) 设置信号的处理。如果没有调用此方法,系统就会调用默认处理方法:中止程序,显示提示信息(就是我们经常遇到的问题)。我们可以调用系统的处理方法,也可 以自定义处理方法。

系统里边定义了三种处理方法: 
1)SIG_DFL    /* Default action */ 
2)SIG_IGN    /* Ignore action */ 
3)SIG_ERR    /* Error return */

项目中我调用了 signal(SIGALRM, SIG_IGN) 和 signal(SIGPIPE, SIG_IGN), 这样产生 SIGALAM 和 SIGPIPE 信号时就不会中止程序,直接把这个信号忽略掉。

自定义处理方法:

  1. void   signal_handle(ing   signo)
  2. {
  3. //do   something;
  4. }
  5. int   main()
  6. {
  7. signal(SIGPIPE, signal_handle);
  8. ......
  9. }

void signal_handle(ing signo) { //do something; } int main() { signal(SIGPIPE, signal_handle); ...... }

时间: 2024-10-28 22:01:30

linux下网络程序遭遇SIGPIPE的解决(转)的相关文章

Linux下检测IP地址冲突及解决方法

Linux下检测IP地址冲突及解决方法 问题说明: 在公司办公网内的一台物理机A上安装了linux系统(ip:192.168.9.120),在上面部署了jenkins,redmine,svn程序.由于是在办公网内,这台机器和同事电脑都是在同一网段的. 突然某天问题出来了:有部分同事远程ssh登陆不上这台linux系统的机器,jenkins/redmine/svn也登陆不上,其他部分同事可以正常使用. 后来发现,是因为这台linux机器的ip被人占用了,ip地址冲突引起的!! 下面介绍下检查ip地

基于嵌入式Linux下GCC编译器__sync_sub_and_fetch_4错误的解决心得

******************************************************************************************************************************************************* 作者:EasyWave                                                                                      

Linux下安装Android的adb驱动-解决不能识别的问题

Linux下安装Android的adb驱动-解决不能识别的问题 20141011更新: 老方法对我当时使用的一款设备一直都没有出现问题,最后遇到小米手机还有Android4.4版本的系统都会每次出现error: insufficient permissions for device问题,老方法的最后也说了这个问题的解决方法是什么.大意就是adb服务得以root用户身份启动,比较靠谱的方法是添加或者修改/etc/udev/rules.d/51-android.rules文件,内容如下: SUBSY

Linux下网络故障诊断

Linux下网络故障诊断 导读 由于实现网络服务器的层次结构比较多,因此当网络出现故障时,解决起来比较复杂.下面由我来为大家详细介绍Linux系统中可能出现的一些网络问题,如网卡硬件问题.网络配置问题.驱动程序问题,以及网络层.传输层.应用层问题等. 网卡故障可以分为硬件故障和软件故障,判断硬件故障最简单的方法是把该网卡插到其它计算机上使用,如果还是老毛病则网卡损坏,否则网卡正常.实际情况下,大部分网卡出现的故障都属于软件故障,软件故障一般分为两类:一类为设置故障:一类为驱动程序故障. 诊断网卡

linux下网络排错以及查看网络信息命令

ping命令利用icmp协议(echorequest----echo reply包)来实现 选项 -c 次数  指定ping几次后退出 -W 时间  指定最大等待时间 注:如有大量ping请求发到本主机,会影响本机其他网络服务. ping输出详解 rtt:请求报文的响应时间 报错信息:timeout关键字:原因有2种:1,无此主机 2,对方主机不响应 目标主机不可达:这个去查rfc文档(学习网络协议的好方法就是看rfc文档),有中文版的! 判断主机是否在线的脚本: 1) for .. in ..

Linux 下网络 IO 的多路复用

2019-10-20 关键字:select 与 poll 在 Linux 系统下,IO 总共可以分为以下四种: 1.阻塞 IO: 2.非阻塞 IO: 3.IO多路复用: 允许同时对多个 IO 进行控制. 4.信号驱动 IO: 一种异步通信模型.前面三种 IO 都是同步型的,唯这一种是异步型的. 阻塞 IO 所谓阻塞 IO 就是在调用相关函数时,程序的运行指针会暂停往下执行,直至这个 IO 操作有结果返回为止.简单来说就是我发起一个 IO 操作请求,你有数据就返回给我,没数据我就等你到有数据为止.

Linux下忘记用户名和密码的解决方法

今天用vmware workstation安装了ubuntu,不记得用户名和密码是什么了,郁闷,还好ubuntu修改密码很简单,方法如下: 进入shell(Drop to root shell prompt) 1.      在ubuntu启动界面长按shift键进入GRUB界面,选择第二项,进入recovery mode 2.      在recovery mode中,选择root 找到用户名 在shell中输入cat /etc/shadow列出所有用户名 可以看到忘记的用户名就在倒数第三行

Linux下C程序的链接过程

今天看到一个很有意思的小程序,它让我对Linux下C程序的编译链接有了一个全新的认识! 这个程序的就是写一个简单的输出"hello World!":   要求:1.不使用C运行库,写一个独立于任何库的程序.(也就是说我们不能#include<stdio>).       2.不适用main函数为程序的入口(大家都知道一般使用了库的程序都是使用main函数作为程序的入口,在这里我们使用自己写的函数nomain作为程序的入口).       3.使用连接器ld把程序的所有段合为

Linux下的程序包管理之源码形式

 Linux下程序包管理之源码形式 程序包的前世今生: 说到程序包管理,不得不提到是就是程序包是由什么组成的?也就是怎么形成的?程序是由源代码程序经过预处理.编译.然后汇编形成二进制的程序,这是针对特定硬件而形成的程序.有计算机编程基础的同学都应该知道源代码编译的时候是要调用特定的库(库文件),而这些库,在不同的系统上是不同的,比如Linux和window上的就不同,不同发行版的Linux上的库也不尽相同,所以这就导致了在不同种类系统上编译生成的二进制程序的运行环境也不尽相同,那么这些程序是不能