c – 如何处理生成它的对象内的SIGPIPE错误?

c – 如何处理生成它的对象内的SIGPIPE错误?,第1张

概述我有两个应用程序,一个服务器和另一个客户端,都用C和Qt编写,但它们都使用C库,它使用C套接字方法在它们之间执行套接字通信(这一切都在 Linux中). 当它们都连接并关闭客户端时,当服务器尝试向其发送新消息时,它会收到SIGPIPE错误并关闭.我在网上进行了一些研究,在SO中看看如何为SIGPIPE创建一个处理程序,而不是关闭应用程序,我告诉定时器不断发送信息停止. 现在我确实学会了如何简单地处 我有两个应用程序,一个服务器和另一个客户端,都用C和Qt编写,但它们都使用C库,它使用C套接字方法在它们之间执行套接字通信(这一切都在 @L_419_0@中).

当它们都连接并关闭客户端时,当服务器尝试向其发送新消息时,它会收到SIGPIPE错误并关闭.我在网上进行了一些研究,在SO中看看如何为SIGPIPE创建一个处理程序,而不是关闭应用程序,我告诉定时器不断发送信息停止.

现在我确实学会了如何简单地处理信号:创建一个方法,在main()或global(内部)中接收int和使用信号(SIGPIPE,myMethod)(注意:从SO中学到了,是的,我知道signal()已经过时了).

但问题是,通过这种方式,我无法停止向死客户端发送信息,因为处理信号的方法需要在发送消息的类之外,或者是静态方法.可以访问我的服务器对象.

为了澄清,这是当前的架构:

//main.cpp

voID signal_callback_handler(int signum){    qDeBUG() << "Caught signal SIGPIPE" << signum << "; closing the application";    exit(EXIT_FAILURE);}int main(int argc,char *argv[]){    QApplication app(argc,argv);    app.setApplicationname("ConnEmulator");    app.setApplicationVersion("1.0.0");    app.setorganizationname("Embrasul");    app.setorganizationDomain("http://www.embrasul.com.br");    MainWidget window;    window.show();    /* Catch Signal Handler SIGPIPE */    signal(SIGPIPE,signal_callback_handler);    return app.exec();}

// MainWidget类(简化)

MainWidget::MainWidget(QWidget *parent) :    QWidget(parent),ui(new Ui::MainWidget),timerSendData(new QTimer(this)){    ui->setupUi(this);    connect(timerSendData,SIGNAL(timeout()),this,SLOT(slotSendData()));    timerSendData->start();    //...}voID MainWidget::slotSendData(){    //Prepares data    //...    //Here the sending message is called with send()    if (hal_socket_write_to_clIEnt(&socket_descriptor,(u_int8_t *)buff_write,myBufferSize) == -1)        qDeBUG() << "Error writting to clIEnt";}

//套接字库

int hal_socket_write_to_clIEnt(socket_t *obj,u_int8_t *buffer,int size){    struct s_socket_private * const socket_obj = (struct s_socket_private *)obj;    int retval = send(socket_obj->clIEnt_fd,buffer,size,0);    if (retval < 0)        perror("write_to_clIEnt");    return retval;}

那么如何在int main()中创建我的MainWidget对象来处理信号,这样他就可以调用timerSendData-> stop()?

解决方法 SIGPIPE是丑陋的,但可以以完全封装,线程安全的方式处理,并且除了使得写入可能导致SIGPIPE的代码之外不会影响任何东西.一般方法是:

>使用pthread_sigmask(或sigprocmask阻止SIGPIPE,但后者不保证在多线程程序中是安全的)并保存原始信号掩码.
>执行可能引发SIGPIPE的 *** 作.
>使用零超时调用sigtimeDWait以使用任何挂起的SIGPIPE信号.
>恢复原始信号掩码(如果之前未阻塞,则解锁SIGPIPE).

以下是使用此方法的一些示例代码的尝试,以编写的纯包装器的形式避免SIGPIPE:

ssize_t write_nosigpipe(int fd,voID *buf,size_t len){    sigset_t oldset,newset;    ssize_t result;    siginfo_t si;    struct timespec ts = {0};    sigemptyset(&newset);    sigaddset(&newset,SIGPIPE);    pthread_sigmask(SIG_BLOCK,&newset,&oldset);    result = write(fd,buf,len);    while (sigtimeDWait(newset,&si,&ts)>=0 || errno != EAGAIN);    pthread_sigmask(SIG_SETMASK,&oldset,0);    return result;}

它未经测试(甚至没有编译),可能需要一些小修复,但希望得到重点.显然,为了提高效率,您希望以比单个写入调用更大的粒度执行此 *** 作(例如,您可以在整个库函数的持续时间内阻止SIGPIPE,直到它返回到外部调用者).

另一种设计是简单地阻塞SIGPIPE并且永远不会阻塞它,并在函数的接口中记录它阻止SIGPIPE(注意:阻塞是线程本地的,不会影响其他线程)并且可能使SIGPIPE挂起(处于阻塞状态) .然后调用者将负责在必要时恢复它,因此想要SIGPIPE的罕见调用者可以通过解锁信号来获取它(但是在你的函数完成之后),而大多数调用者可以愉快地让它被阻塞.阻塞代码的工作方式如上所述,删除了sigtimeDWait / unblocking部分.这与Maxim的答案类似,只是影响是线程本地的,因此是线程安全的.

总结

以上是内存溢出为你收集整理的c – 如何处理生成它的对象内的SIGPIPE错误?全部内容,希望文章能够帮你解决c – 如何处理生成它的对象内的SIGPIPE错误?所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/1216151.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-05
下一篇 2022-06-05

发表评论

登录后才能评论

评论列表(0条)

保存