• tcp连接时,BROKEN PIPE错误的原因以及解决方法


    问题:

    写了一个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些内容,就会出错。

    解决方法:

    • 忽略SIGPIPE信号

        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端发送数据这种情况)

       

  • 相关阅读:
    SQL 启动服务方法
    SQL 2012 连接失败
    数据库 基本操作有哪些
    windows 计算机 管理 命令
    windows下编译使用NDK,调用SO文件
    windows 注册表命令
    spring @Transactional 声明式事务
    Set List Map
    bean 的各个属性
    util:
  • 原文地址:https://www.cnblogs.com/cthon/p/9139553.html
Copyright © 2020-2023  润新知