信号EAGAIN,SIGPIPE分析

今天收到测试反馈,服务异常退出了,观察服务日志看到以下错误

阅读源码如下

复制代码
int hio_write (hio_t* io, const void* buf, size_t len) {
    if (len <= 0) {
        LOGE("[ hio_write ] no data need sent! len: %d", len);
        return -1;
    }

    int nwrite = 0;
    //if (write_queue_empty(&io->write_queue)) {
    if (list_empty(&io->write_queue)) {
try_write:
        switch (io->io_type) {
#ifdef WITH_OPENSSL
        case HIO_TYPE_SSL:
            nwrite = SSL_write((SSL*)io->ssl, buf, len);
            break;
#endif
        case HIO_TYPE_TCP:
#ifdef OS_UNIX
            nwrite = write(io->fd, buf, len);
#else
            nwrite = send(io->fd, buf, len, 0);
#endif
            break;
        case HIO_TYPE_UDP:
        case HIO_TYPE_IP:
            nwrite = sendto(io->fd, buf, len, 0, io->peeraddr, sizeof(sockaddr_u));
            break;
        default:
            nwrite = write(io->fd, buf, len);
            break;
        }

        if (nwrite < 0) {
            if (socket_errno() == EAGAIN) {
                nwrite = 0;
                LOGE("try_write failed, enqueue (pid: %d)!!!!!!!!!!!!!", getpid());
                goto enqueue;
            }
            else {
                perror("hio_write(nwrite < 0)");
                io->error = socket_errno();
                goto write_error;
            }
        }
        if (nwrite == 0) {
            LOGE("disconnect! nwrite: %d", nwrite);
            goto disconnect;
        }
        if (io->write_cb) {
            io->write_cb(io, buf, nwrite);
        }
        if (nwrite == len) {
            return nwrite;
        }

    }
enqueue:
    if (nwrite < len) {
        write_queue_node_t *wnode = safe_malloc(sizeof(write_queue_node_t));
        wnode->buf.len = len;
        wnode->buf.offset = nwrite;
        // NOTE: free in nio_write
        SAFE_ALLOC(wnode->buf.base, len);
        memcpy(wnode->buf.base, (char*)buf, len);

        list_add_tail(&wnode->node, &io->write_queue);

        hio_add(io, hio_handle_events, HV_WRITE);
    }
    return nwrite;
write_error:
disconnect:
    hio_close(io);
    return nwrite;
}
复制代码

看来是write失败了,通过观察服务日志,原来是服务recv数据慢了,客户端就会抛出这种错误,出现write失败并且信号是EAGAIN,应该将数据放进等待队列中,并且注册可写事件,等触发可写事件再写入数据。

但是write失败不足以让服务退出,通过捕捉信号函数,发现程序收到信号13退出的。

知识补充

SIGPIPE信号产生的规则:当一个进程向某个已收到RST的套接字执行写操作时,内核向该进程发送SIGPIPE信号。(SIGPIPE信号产生的原因是2次write一个closed的文件描述符)
SIGPIPE信号产生的场景举例:初始时,C、S连接建立,若某一时刻,C端进程宕机或者被KILL而终止(终止的C端进程将会关闭打开的文件描述符,即向S端发送FIN段),S端收到FIN后,响应ACK假设此时,S端仍然向C端发送数据:当第一次写数据后,S端将会收到RST分节; 当收到RST分节后,第二次写数据后,S端将收到SIGPIPE信号(S端进程被终止)


我当时理解出现错误,我认为是自己不断向一个正常的fd写数据导致SIGPIPE信号,因此我一直在想办法加快报文接收,但是有些报文是需要解包的,本身耗时就很严重,就算扩大网络层缓冲区大小也无法彻底解决问题。
但是后来经过同事提醒,SIGPIPE信号是向一个closed的fd写数据,既然是closed的fd,根本不可能是我接收数据慢导致的,方向错了。向一个正常的fd写数据,哪怕write阻塞了也无法触发SIGPIPE。
最终我忽略SIGPIPE信号,问题解决。
signal(SIGPIPE, SIG_IGN);

 

积土成山,风雨兴焉;积水成渊,蛟龙生焉;积善成德,而神明自得,圣心备焉。故不积跬步,无以至千里;不积小流,无以成江海。骐骥一跃,不能十步,驽马十驾,功在不舍。锲而舍之,朽木不折;锲而不舍,金石可镂。

 

posted on   寒魔影  阅读(134)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
历史上的今天:
2016-04-30 C语言错误: HEAP CORRUPTION DETECTED

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示