首页 > 解决方案 > 在 Linux 上处理多线程损坏管道案例的服务器端套接字最佳实践是什么?

问题描述

考虑到在 Linux 上是 C 语言的新手,我已经完成了套接字编程场景,在这些场景中你必须处理 SIGPIPE 问题并且我遇到了以下情况:
1- 捕获进程的 sigaction 然后继续,这等于忽略信号。

struct sigaction sginal_action;
memset(&sginal_action, 0, sizeof (sginal_action));
sginal_action.sa_handler = SIG_IGN;
sginal_action.sa_flags = SA_RESTART;
if (sigaction(SIGPIPE, &sginal_action, null)) {
    perror("signal action error"); 
}

2-忽略线程使用的信号

sigset_t sigpipe_mask;
sigemptyset(&sigpipe_mask);
sigaddset(&sigpipe_mask, SIGPIPE);
sigset_t saved_mask;
if (pthread_sigmask(SA_RESTART, &sigpipe_mask, &saved_mask) == -1) {
  perror("pthread_sigmask");
}



- 现在一切正常,但我需要关于此测试用例行为的答案:

1- 服务器接受来自用户 A 的套接字,文件描述符为 int 7
2- 我运行冗长的 SQL 语句,需要 25 秒
3- 在 20 秒时客户端关闭套接字
4- 在 21 秒 Linux 内核发送了 SIGPIPE
5- 在 22 秒进程忽略了 SIGPIPE 并继续使用文件描述符 7,因为没有任何信号出现任何问题
6- 在 23 秒服务器接受来自用户 B 的套接字,文件描述符为 int 7 , 再次!
7- 用户 B 授权需要 2 秒,在用户 A 的 25 秒完成。
8-核心问题开始在第二个 25 写入(file_dsciptor,缓冲区,缓冲区大小);来自两个线程的数据都将写入用户 A 和用户 B 通道
9- 碰巧用户 B 无权登录服务器,但在服务器关闭线程 B 的文件描述符 7 之前,客户端 A 的线程 A 写入文件描述符 7 和由于套接字文件描述符 7 的重用,客户端 B 收到了重要数据!

我的问题
是,这种情况是错误的并且永远不会发生吗?
还是有可能发生,但有正确的方法可以应用?
并且是否有一个 C 系统调用函数来停止通过套接字连接重用 file_discriptor?
或者应该做些什么来确保打开的频道不会与另一个频道冲突,比如我猜的唯一文件描述符?

标签: cmultithreadingsocketssignalssigpipe

解决方案


(正常)SIGPIPE本质上是一个同步信号。您会得到它以响应您所做的事情,即尝试写入被另一方关闭的管道/套接字/FIFO。忽略SIGPIPE是无害的,因为如果您这样做,您仍然会以通常报告同步错误的方式获知错误:通过失败的返回码并errno设置为适当的错误号 ( EPIPE)。在这种情况下,我认为SIGPIPE在继续检查错误的同时忽略将是最好的方法,无论您使用的是什么 POSIX 平台。

关于您的示例,您在第 5 点的假设是“没有任何信号出错”是不正确的。会有信号。它不会是一个信号,而是一个呼叫EPIPE失败。write


推荐阅读