【问题标题】:shutdown() and close() does nothingshutdown() 和 close() 什么都不做
【发布时间】:2012-11-13 10:04:56
【问题描述】:

我有一个服务器正在侦听一个 tcp 端口。当有传入连接时,它使用accept() 并使用fork() 生成一个子进程。客户端/子进程从连接中读取一些数据并通过管道将其发送回服务器。在此之后,我想关闭连接。我尝试在客户端进程中使用shutdown()close(),但运气不佳。

我检查了shutdown()close() 的结果,它们都返回0。显然它们运行顺利。在shutdown()close() 都运行后,服务器从子进程接收sigchld。这是在一般基础上处理的,但我更愿意在接收信号之前关闭连接。 任何有关如何执行此操作的建议将不胜感激。

附带说明 close() 已用于关闭整个服务器/客户端程序中不需要的文件描述符和套接字,但现在我不确定它们是否真的被关闭了。

下面是两个代码sn-ps。 首先是程序服务器部分的accept()fork()

if ((client_s = accept(s, &info.addr, &addrlen)) == -1) {
    //Error handling
}
if ((info.pid = fork()) == -1) {
    //More error handling
}
else if (info.pid == 0) {
    //Closing all unneeded file descriptors

    // Set default signal handler for SIGCHLD
    signal(SIGCHLD, SIG_DFL);

    _exit(clientStatus_main(client_s, info_pipes[1]));
}
else {
    //Adding client to list of clients and closing some file descriptors.
    close(client_s);
}

最后是来自函数clientStatus_main的代码sn-p:

//Signal handling
signal(SIGINT, client_sighandler);
signal(SIGTERM, client_sighandler);
signal(SIGKILL, client_sighandler);
signal(SIGHUP, client_sighandler);
signal(SIGCHLD, SIG_DFL);

//Read data from socket
read(socket, &status_packet.type, iLength)
//Do data handling and write back to server
write(info_pipe, &status_packet, status_packet.len)

//Close down socket
res = shutdown(socket, SHUT_RDWR);
addlog(LOG_INFO, "Result of shutdown: %i\n", res); //Write to log
res = close(socket);
addlog(LOG_INFO, "Result of close: %i\n", res);
return (iCount > 0 ? 0 : -1);

有什么好主意吗?

*编辑: 阅读 cmets 后,我尝试从父进程执行 close(client_s),但它并没有解决我的问题。为了清楚起见,我还在代码 sn-p 中添加了这一行。

【问题讨论】:

  • 你省略了有趣的部分:在 else 部分中“关闭一些文件描述符”。
  • ""//将客户端添加到客户端列表并关闭一些文件描述符。" , 那么你关闭了哪些文件描述符?你close(client_s)了吗?
  • 不,我没有close(client_s)。是否需要从父进程和客户端关闭文件描述符?
  • 是的,fork()ed 进程的两个副本都有文件描述符的副本。当所有套接字都关闭时,套接字将关闭。

标签: c sockets shutdown


【解决方案1】:

涉及三个过程:

客户端:连接到父级的监听套接字。

父进程:侦听套接字、接受连接并将其交给子进程的服务器进程。

子进程:通过已建立的连接与客户端对话的服务器进程。

已建立的连接仅存在于the childthe client 之间。 The parent 无法检测到客户端套接字何时从任一侧关闭。

有两种方法可以通知the parent the child 正在关闭连接并终止,要么捕获SIGCHLD 信号,要么让the childthe parent 发送消息,例如通过pipe问题中提到。

【讨论】:

  • 描述/解释很好 - 但我不确定父母应该如何处理有关被孩子关闭的连接的信息......我已经尝试过close(),如编辑问题。至于在父进程中捕获SIGCHLD - 这已经完成了。我记得(如果我错了,请纠正我),信号也可以被解释为出现问题 - 连接中断或类似情况。我非常想区分这种情况和那种情况。
  • 如果可以的话,我会处理孩子的客户端错误。孩子可以检测客户端是否关闭了套接字或者连接是否超时并且应该能够处理它。如果你不能对孩子进行足够的错误处理,那么我建议第二种方法:孩子以某种方式通知父母,例如通过管道发送消息。
  • 好吧,处理SIGCHLD(在父进程或子进程中)对关闭连接没有帮助。我的主要问题是如何关闭连接 :o) SIGCHLD 实际上就是我意识到连接没有关闭的方式。
【解决方案2】:

这有点尴尬,但问题似乎并不在于close()shutdown()。 cmets 和 Klas Lindbäck 的回答让我开始思考,我做了一些实验,发现发送了 SIGCHLD 是因为客户端实际上在子进程关闭连接的同时关闭了连接。

所以我的解决方案受到了 Klas Lindbäck 建议的启发。子进程通过前面提到的管道发送进程 ID,父进程现在可以安全地忽略/阻止从该进程发送的SIGCHLD

【讨论】:

    猜你喜欢
    • 2016-05-15
    • 1970-01-01
    • 2013-04-10
    • 1970-01-01
    • 2015-10-26
    • 2021-07-31
    • 2019-02-21
    • 2020-10-15
    • 1970-01-01
    相关资源
    最近更新 更多