socket编程—— 服务器遇到Broken Pipe崩溃

我写了一个服务器程序, 在Linux下测试时, 总是莫名退出. 最后跟踪到是write调用导致退出. 用gdb执行程序, 退出时提示"Broken pipe".

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

具体的分析可以结合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. 程序便能知道对端已经关闭.

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


当然还有其他方法来处理SIGPIPE

     设置当前socket在进行写操作时不产生SIGPIPE。

?
1
2
int set = 1;
setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, ( void *)&set, sizeof ( int ));

这样做的好处在于:在某些情况 下我们并不需要一个全局的SIGPIPE handler。但是据说这种并不通用,在linux下没有相应的定义—-但我在mac下测试通过。



转自 http://blog.csdn.net/mustanglau/article/details/4485491

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
发生"Broken Pipe"错误通常是由于在一个已经关闭的socket上进行读写操作引起的。为了避免这个错误,你可以采取以下几个步骤: 1. 检查socket是否已经关闭:在进行读写操作之前,你可以使用`socket.fileno()`方法来检查socket是否已经关闭。如果socket已经关闭,你可以选择重新建立连接或者放弃继续操作。 2. 检查写入缓冲区是否已满:当你向socket写入数据时,数据会被放入写入缓冲区。如果写入缓冲区已满,继续写入数据可能会导致"Broken Pipe"错误。你可以使用`socket.send()`方法的返回值来检查是否成功写入了所有数据。如果返回值小于发送的数据大小,表示缓冲区已满。你可以选择等待一段时间或者适当减少写入的数据量。 3. 使用keepalive机制:通过设置socket的keepalive选项,可以在空闲一段时间后发送一些特殊的探测数据包,以保持连接的活跃状态。这样可以防止底层网络设备关闭闲置连接。具体实现方式取决于所使用的编程语言和库。 4. 错误处理:当出现"Broken Pipe"错误时,你可以捕获该错误并进行适当的处理。例如,在Python中,你可以使用try-except语句来捕获socket.error异常,并进行相应的处理,比如重试连接或者关闭连接。 总之,要避免"Broken Pipe"错误,你需要仔细处理socket的状态、写入缓冲区和错误处理。根据具体的使用场景和编程语言,你可能需要采取不同的措施来解决该问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值