参考资料:

1.博客1:https://blog.csdn.net/qq_37535749/article/details/113781338

2.博客2:https://blog.csdn.net/zkkdcs1/article/details/88659069

3.博客3:https://superuser.com/questions/554855/how-can-i-fix-a-broken-pipe-error

4.博客4:https://www.cnblogs.com/cthon/p/9139553.html

#include <stdlib.h>
#include <sys/signal.h> //默认读写一个关闭的socket会触发sigpipe信号 该信号的默认操作是关闭进程 有时候这明显是我们不想要的
//所以此时我们需要重新设置sigpipe的信号回调操作函数 比如忽略操作等 使得我们可以防止调用它的默认操作
//信号的处理是异步操作 也就是说 在这一条语句以后继续往下执行中如果碰到信号依旧会调用信号的回调处理函数
//处理sigpipe信号
void handle_for_sigpipe()
{
struct sigaction sa; //信号处理结构体
memset(&sa, '\0', sizeof(sa));
sa.sa_handler = SIG_IGN;//设置信号的处理回调函数 这个SIG_IGN宏代表的操作就是忽略该信号
sa.sa_flags = 0;
if(sigaction(SIGPIPE, &sa, NULL))//将信号和信号的处理结构体绑定
return;
} int main(int argc, char *argv[])
{
handle_for_sigipipe();
while(1){}
return 0;
}

今天在原程序中需要新加若干个http接口,用来请求server端的版本信息,代码写完后放到开发环境测试,

一直在报broken pipe的错误,

后来经过排查,定位到时http client请求server数据的地方有错误。

回忆pipe的特性,pipe如果是两个父子进程掌控读端和写端,可能出现,“子进程写端关闭,父进程读端未关闭,产生僵尸进程”的现象。

用这个思路查阅了相关资料https://blog.csdn.net/zqz_zqz/article/details/52235479

摘除博客中的一句话:客户端读取超时关闭了连接,这时候服务器端再向客户端已经断开的连接写数据时就发生了broken pipe异常!

今天回溯了一下这个错误,发现了一篇讲的比较透彻的博客:https://www.cnblogs.com/cthon/p/9139553.html

问题:

写了一个server和一个client,UNIX套接字的,server不断接收消息并打印出来,client是一个交互程序,输入一个消息回车发送,接着又可以输入消息。
出问题了:
当server监听着,client第一次发送消息成功,server接收并打印出来了。
client第二次发送消息没成功并且结束程序了,server没接收到消息,保持继续监听。
我用GDB调试时,发现client第二次发送消息时,client收到SIGPIPE(Broken Pipe)信号。server明明还监听着,而且再次启动client还是第一次成功,第二次失败退出。

同样的,当client因为断开(关闭了网络描述符sfd,或者ctrl+c/ctrl+\异常断开),server端也产生SIGPIPE信号。

分析:

TCP协议是端到端的传输控制协议,之所以是“端到端”的协议,是因为”路由“是由IP协议负责的,TCP协议负责为两个通信端点提供可靠性保证,这个可靠性不是指一个端点发送的数据,另一个端点肯定能收到(这显然是不可能的),而是指,数据的可靠投递或者故障的可靠通知。

所谓的“端到端”,指的是在通信两端之间建立了一个全双工的通信管道,既然是管道,就不得不了解管道。

管道的特点:

  • 管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道;
  • 只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程);
  • 单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中。
  • 数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。

管道特性的表现:

  • 如果一个进程以只写打开管道,但是没有以只读或读写打开这个管道的进程,则打开操作会阻塞, 直到有进程以读或读写打开,open 才会返回。(写端打开,读端关闭)
  • 如果一个进程以只读打开管道,但是没有以只写或读写打开这个管道的进程,则打开操作会阻塞, 直到有进程以写或读写打开,open 才会返回。(写端关闭,读端打开)
  • 当写端没有写入数据时,读端会阻塞到 read 调用,直到写端写入数据或者写端关闭。 当管道没有空间时,再写入数据就会被阻塞。直到有进程读取数据,或者所有的读端关闭。(读写顺序)

注意:全双工,指的是每一端都可读可写。前提是对端打开。如果对端都关闭了,本端读数据为空,不会出错;但本段写数据肯定出错。

总结:

如果要进行顺利的管道通信:管道的两端必需都打开。

  • 管道读端关闭,写端不能写,否则会发出SIGPIPE信号,即会生成BROKEN PIPE错误。

也就是说tcp通信时,client端通过 pipe发送信息到server端后,client端挂不必,这时server端返回信息,向pipe些内容,就会出错。

解决方法:

    1、signal(SIGPIPE,SIG_INT);//(全局范围内)

    2、setsocketop;//(tcp特性设置)

/// sock 就是设置不发送 `SIGPIPE` 信号的 socket 变量
int value = 1;
setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, &value, sizeof(value));
    • 合理规避读端关闭,写端打开的问题。(避免client端关闭,server端发送数据这种情况)

broken pipe 报错分析和解决办法的更多相关文章

  1. MyEclipse的JQuery.min.js报错红叉解决办法

    MyEclipse的JQuery.min.js报错红叉解决办法 1.选中报错的jquery文件"jquery-1.2.6.min.js".2.右键选择 MyEclipse--> ...

  2. 因采用 Flask 原生 WSGI 出现 "Broken pipe" 报错的故障处理

    :first-child { margin-top: 0; } blockquote > :last-child { margin-bottom: 0; } img { border: 0; m ...

  3. pom.xml内容没有错,但一直报错红叉 解决办法

    转自:http://www.cnblogs.com/sxdcgaq8080/p/5590254.html [maven] pom.xml内容没有错,但一直报错红叉 解决办法 1.首先看一下下面的这两个 ...

  4. Eclipse中引入com.sun.image.codec.jpeg包报错的完美解决办法

    转: Eclipse中引入com.sun.image.codec.jpeg包报错的完美解决办法  更新时间:2018年02月14日 17:13:03   投稿:wdc   我要评论   Java开发中 ...

  5. std::unique_ptr使用incomplete type的报错分析和解决

    Pimpl(Pointer to implementation)很多同学都不陌生,但是从原始指针升级到C++11的独占指针std::unique_ptr时,会遇到一个incomplete type的报 ...

  6. 关于Maven报错的一些解决办法(别处贴的)

    1.警告:The tag handler class for "s:form"(org.apache.struts2.views.jsp.ui.FormTag) was not f ...

  7. win7+IE11 中开发工具报错occurredJSLugin.3005解决办法

    系统环境 win7+IE11 报错描述: Exception in window.onload: Error: An error has ocurredJSPlugin.3005 Stack Trac ...

  8. iOS 提交审核报错 ERROR ITMS-90087解决办法

    ERROR ITMS-: "Unsupported Architectures. The executable for yht.temp_caseinsensitive_rename.app ...

  9. 【java-console】如何双击运行可执行jar包及遇到依赖dll报错问题的解决办法

    如何配置双击运行可执行jar包的步骤,请移步到   这里   查看具体的操作,此处不再介绍. 本文主要解决如何处理依赖dll报错的问题解决办法. 我有一个jar包可执行文件运行需要依赖第三方的dll文 ...

随机推荐

  1. linux编译安装(全面教程解析)

    目录 一:编译安装 1.编译安装特点 2.编译安装 简介 编译安装 1.使用源代码,编译打包软件 2,编译安装,只能按照源代码 一:编译安装 1.编译安装特点 1.可以自定制软件 2.按需求构建软件 ...

  2. new JSONObject 无异常卡顿【Maven+Idea 导包不更新的小坑】

    问题描述 今天在使用JSONObject过程中出现了一个非常不可思议的现象,我Junit测试没有问题,但是就是打开服务器运行的时候,结果就是出不来,经过多次测试发现代码竟然卡在了new JSONObj ...

  3. SpringBoot+MyBatis通过ScriptRunner读取SQL文件

    @Component public class InitDBTables implements CommandLineRunner { @Autowired DataSource dataSource ...

  4. StringUtils.isBlank(str)和StringUtils.isEmpty(str)的区别

    1.StringUtils.isEmpty(CharSequence cs)实现源码 public static boolean isEmpty(CharSequence cs) { return c ...

  5. Android下数据库创建

    什么情况下我们才用数据库做数据存储? 大量数据结构相同的数据需要存储时. sqlite 嵌入式 轻量级 SqliteOpenHelper 创建数据库步骤: 1.创建一个类集成SqliteOpenHel ...

  6. Copy as Markdown - 将页面链接按照 Markdown 格式copy

    将页面文字和链接组成 Markdown 格式的网址 直接对页面链接右键使用时,无法获取链接标题,只能显示 No Title 所以需要: 选中「想作为标题的部分文字」, 然后去对「页面链接」右键-> ...

  7. Linux如何查看端口占用情况

    Linux如何查看端口 1.lsof -i:端口号 用于查看某一端口的占用情况,比如查看8000端口使用情况,lsof -i:8000 # lsof -i:8000 COMMAND PID USER ...

  8. 解压命令tar zxvf中zxvf分别是什么意思

    x : 从 tar 包中把文件提取出来z : 表示 tar 包是被 gzip 压缩过的,所以解压时需要用 gunzip 解压v : 显示详细信息f xxx.tar.gz : 指定被处理的文件是 xxx ...

  9. 无脑安装java编程语言开发的集成环境 IDEA 白嫖版本

    无脑安装java编程语言开发的集成环境  IDEA 根python很类似:可以借鉴无脑安装--Python 及 安装python集成开发环境pycharm - 隐姓埋名4869 - 博客园 (cnbl ...

  10. Docker容器和宿主机互传文件

    1.docker容器向宿主机传送文件 格式: docker cp container_id:<docker容器内的路径> <本地保存文件的路径> 例: docker cp 10 ...