这是关闭 fork 上的套接字描述符的正确方法吗?

2024-02-06

考虑这段代码:

socket_fd = start_server(port);

while (1){

    new_socket_fd = accept_client(socket_fd);

    int pid = fork();

    if (pid == 0){

        //I am the child server process

        close(socket_fd);      <------(1)

        do_stuff_with_client(new_socket_fd, buffer);

        close(new_socket_fd);       <------(2)

        exit(0);

    } else if (pid > 0){

        //I am the parent server process

        close(new_socket_fd);      <------(3)

    } else {

        fprintf(stderr, "Fork error\n");
        return 1;
    }
}

据我了解,当进程调用 fork() 时,其地址空间是重复的但不是共享的,因此如果我更改子进程中的变量或关闭文件描述符,它不会影响父进程。

也就是说,在服务器接受新连接后(从而创建new_socket_fd)它自己分叉,子进程关闭socket_fd(1) 因为它不是必需的,因为父级仍在监听socket_fd.

子进程处理请求然后关闭它的new_socket_fd(2) 并退出。

当子进程执行所有这些操作时,父进程已经关闭new_socket_fd(3) 因为连接正在由子进程处理。

问题是:这些假设正确吗?


Converting the comment stream into an answer.

TL; DR

是的。问题中的描述看起来正确并且推理合理。

在某些时候,您的父进程应该等待已死亡的子进程,以防止僵尸进程的累积(但在子进程死亡之前它不应该阻塞)。使用waitpid() http://pubs.opengroup.org/onlinepubs/9699919799/functions/waitpid.html循环中WNOHANG在父级关闭循环的部分中,参数可能是合适的new_socket_fd。这可能会留下一个或多个僵尸,直到发出下一个传入请求。如果这是一个问题,你可以忽略SIGCHLD(因此永远不会创建僵尸),或者您可以安排定期唤醒,在此期间父进程检查僵尸。

讨论

babon https://stackoverflow.com/users/4845636/babon asked https://stackoverflow.com/questions/45190328/is-this-the-correct-way-to-close-socket-descriptors-on-fork?noredirect=1#comment77351441_45190328

快速问题 - 那么父进程何时/在何处关闭 socket_fd?

父级关闭socket_fd当它退出循环或被告知停止侦听套接字时。所示代码中没有对此进行真正的规定,因此当父进程被终止(或发生分叉失败)时它将被关闭。重点是侦听套接字可用于许多连接 - 在完成侦听之前,您不想在父级中关闭它。

Matteo https://stackoverflow.com/users/5238305/matteo noted https://stackoverflow.com/questions/45190328/is-this-the-correct-way-to-close-socket-descriptors-on-fork?noredirect=1#comment77351554_45190328

在这种情况下,因为它是一个无限循环,所以永远不会。服务器将始终监听最多 N 个定义的连接listen(socket_fd, N).

请注意,N 参数listen()call 是可以排队等候侦听进程的未完成连接数。即尚未通过连接返回值的连接请求数accept()称呼。它不是对可以同时活动的连接数的限制accept()已接受连接。

阿贾伊·布拉马克沙特里亚 https://stackoverflow.com/users/2858773/ajay-brahmakshatriya asked https://stackoverflow.com/questions/45190328/is-this-the-correct-way-to-close-socket-descriptors-on-fork?noredirect=1#comment77351472_45190328

在孩子关闭之前socket_fd,绑定端口是否映射到两个 PID?如果有传入的数据包,它会被放入谁的队列中?

传入数据包与套接字的“打开文件描述”(或等效内容 - 与“文件描述符”或“套接字描述符”不同)相关联。它可供父母或孩子使用,以先读者为准。同样,传入的连接请求也会在socket_fd;它们可以被父母或孩子接受。然而,家人已经就谁该做什么达成了一致,这样他们就不会互相妨碍。

Matteo 评论了 https://stackoverflow.com/questions/45190328/is-this-the-correct-way-to-close-socket-descriptors-on-fork?noredirect=1#comment77351585_45190328

我想是给父母的。

Ajay 回应了 https://stackoverflow.com/questions/45190328/is-this-the-correct-way-to-close-socket-descriptors-on-fork?noredirect=1#comment77351665_45190328

如果是这种情况,同样的情况也应该发生在数据包上new_socket_fd因为两者都打开了。这意味着在父级关闭数据包之前,子级将无法读取数据包。这可能会导致竞争条件。

这是基于一个误解。该数据包可通过文件描述符供两个进程使用。当进程关闭文件描述符时,它无法再访问发送到连接的信息(当然,也无法在该连接上发送数据)。在那之前,谁能看到什么就像一场抽签,除非参与者进程就哪个读取数据、哪个监听连接达成一致

Matteo 回应了 https://stackoverflow.com/questions/45190328/is-this-the-correct-way-to-close-socket-descriptors-on-fork?noredirect=1#comment77352107_45190328

但文件描述符不应该干扰父子之间的关系;这就是为什么关闭socket_fd孩子这边并不能阻止父母倾听。

babon 评论了 https://stackoverflow.com/questions/45190328/is-this-the-correct-way-to-close-socket-descriptors-on-fork?noredirect=1#comment77352171_45190328

同意。但我认为你应该关闭socket_fd在 while 循环之后。如果明天您更改循环以在某些情况下中断,您将面临无缘无故保持打开套接字的风险。

这是一个很好的做法,但是循环不会退出(它是一个while (1)循环,并且故障模式会执行return退出循环 - 它可以在执行此操作之前关闭套接字return)。如果程序退出,那么系统将关闭套接字,因此这并不重要,尽管关闭您打开的内容是很好的内务处理。

Ajay notes https://stackoverflow.com/questions/45190328/is-this-the-correct-way-to-close-socket-descriptors-on-fork?noredirect=1#comment77352301_45190328

父级和子级中的文件描述符不同。因此关闭一个不应影响另一个。但是两个副本都具有相同的(src-ip、src-port、dest-ip、dest-port)4 元组,那么具有此类标头的数据包会去哪里?

描述符不同,但它们引用的套接字连接是相同的。该数据包可供任何读取它的进程(父进程或子进程)使用。

Matteo 回应了 https://stackoverflow.com/questions/45190328/is-this-the-correct-way-to-close-socket-descriptors-on-fork?noredirect=1#comment77352650_45190328

在我的例子中accept_client创造了sockaddr结构体为客户端,所以 4 元组去孩子的new_socket_fd.

这不太准确。第一的,accept_client()在有孩子之前被调用;这new_socket_fd(仅)当该函数完成时位于父级中。其次,之后fork(),两个进程都可以访问new_socket_fd,并且都可以读取客户端进程发送的数据。然而,该程序的设计是为了让服务器在子进程处理传入连接时返回侦听更多连接请求。new_socket_fd——合理的分工。

请注意,允许父进程处理请求而子进程继续监听。然而,这有悖于惯例。这意味着监听的“守护进程”进程会更改每个连接请求的 PID,从而很难确定当前正在监听套接字的进程。代码中使用的传统方法是守护进程在很长一段时间内保持不变,因此记录 PID 以供以后的进程控制(当不再需要时杀死守护进程)是明智的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

这是关闭 fork 上的套接字描述符的正确方法吗? 的相关文章

  • 为什么存在 async 关键字

    浏览 msdn 9 频道视频时 我发现以下未答复的评论 希望有人能解释一下 我不明白 async 关键字的意义 为什么不直接允许 任何时候方法返回任务时都会使用await关键字 就像迭代器一样 可以在任何返回 IEnumerable 的方法
  • Subversion 和 Visual Studio 项目的最佳实践

    我最近开始在 Visual Studio 中处理各种 C 项目 作为大型系统计划的一部分 该系统将用于替换我们当前的系统 该系统是由用 C 和 Perl 编写的各种程序和脚本拼凑而成的 我现在正在进行的项目已经达到了颠覆的临界点 我想知道什
  • 从多线程程序中调用 system()

    我们正在开发一个用 C 编写的多线程内存消耗应用程序 我们必须执行大量的 shellscript linux 命令 并获取返回码 读完之后article http www linuxprogrammingblog com threads a
  • System.IO.IOException:由于意外>数据包格式,握手失败?

    有谁知道这意味着什么 System Net WebException 底层连接已关闭 发送时发生意外错误 gt System IO IOException 由于意外 握手失败 数据包格式 在 System Net Security SslS
  • ASP.NET Core 与现有的 IoC 容器和环境?

    我想运行ASP NET 核心网络堆栈以及MVC在已托管现有应用程序的 Windows 服务环境中 以便为其提供前端 该应用程序使用 Autofac 来处理 DI 问题 这很好 因为它已经有一个扩展Microsoft Extensions D
  • SSL/TLS/HTTPS 站点在 C#/.NET WebBrowser 控件中非常慢,但在 Internet Explorer 中则很好

    背景 我正在修改自动维基浏览器 http en wikipedia org wiki Wikipedia AutoWikiBrowser使用托管在安全服务器上的 MediaWiki 站点 我允许用户通过 C 应用程序中的 WebBrowse
  • 在 C# Winforms 应用程序中嵌入 Windows XP 主题

    我有一个旧版 C Windows 窗体应用程序 其布局是根据 Windows XP 默认主题设计的 由于需要将其作为 Citrix 应用程序进行分发 该应用程序现在看起来像经典主题应用程序 因为 Citrix 不鼓励使用主题系统服务 所以
  • TcpClient 在异步读取期间断开连接

    我有几个关于完成 tcp 连接的问题 客户端使用 Tcp 连接到我的服务器 在接受客户端后listener BeginAcceptTcpClient ConnectionEstabilishedCallback null 我开始阅读netw
  • 两种类型的回发事件

    1 我发现了两篇文章 每篇文章对两种类型的回发事件的分类都略有不同 一位资源说两种类型的回发事件是Changed事件 其中控件实现 IPostbackDataHandler 当数据在回发之间更改时触发 然后Raised事件 其中控件实现 I
  • C# 委托责任链

    为了我的理解目的 我实现了责任链模式 Abstract Base Type public abstract class CustomerServiceDesk protected CustomerServiceDesk nextHandle
  • libxml2 xmlChar * 到 std::wstring

    libxml2似乎将所有字符串存储在 UTF 8 中 如xmlChar xmlChar This is a basic byte in an UTF 8 encoded string It s unsigned allowing to pi
  • 预处理后解析 C++ 源文件

    我正在尝试分析c 使用我定制的解析器的文件 写在c 在开始解析之前 我想摆脱所有 define 我希望源文件在预处理后可以编译 所以最好的方法是运行C Preprocessor在文件上 cpp myfile cpp temp cpp or
  • C++11 动态线程池

    最近 我一直在尝试寻找一个用于线程并发任务的库 理想情况下 是一个在线程上调用函数的简单接口 任何时候都有 n 个线程 有些线程比其他线程完成得更快 并且到达的时间不同 首先我尝试了 Rx 它在 C 中非常棒 我还研究了 Blocks 和
  • C# 中的常量和只读? [复制]

    这个问题在这里已经有答案了 可能的重复 const 和 readonly 之间有什么区别 https stackoverflow com questions 55984 what is the difference between cons
  • 二叉树中的 BFS

    我正在尝试编写二叉树中广度优先搜索的代码 我已将所有数据存储在队列中 但我不知道如何访问所有节点并消耗它们的所有子节点 这是我的 C 代码 void breadthFirstSearch btree bt queue q if bt NUL
  • Visual Studio 2017 完全支持 C99 吗?

    Visual Studio 的最新版本改进了对 C99 的支持 最新版本VS2017现在支持所有C99吗 如果没有 C99 还缺少哪些功能 No https learn microsoft com en us cpp visual cpp
  • C语言声明数组没有初始大小

    编写一个程序来操纵温度详细信息 如下所示 输入要计算的天数 主功能 输入摄氏度温度 输入功能 将温度从摄氏度转换为华氏度 独立功能 查找华氏度的平均温度 我怎样才能在没有数组初始大小的情况下制作这个程序 include
  • 受限 AppDomain 中的代码访问安全异常

    Goal 我需要在权限非常有限的 AppDomain 中运行一些代码 它不应该访问任何花哨或不安全的内容 except对于我在其他地方定义的一些辅助方法 我做了什么 我正在创建一个具有所需基本权限的沙箱 AppDomain 并创建一个运行代
  • 如何查找连接到 AF_INET 套接字的客户端的 UID?

    有什么方法或类似的东西ucred for AF UNIX如果是AF INET插座 TCP在我的例子中 找出连接到我的套接字的客户端的UID 还有 proc net tcp但它显示了UID of the creator插座的而不是连接的cli
  • C++、三元运算符、std::cout

    如何使用 C 用三元运算符编写以下条件 int condition1 condition2 condition3 int double result int or double std cout lt lt condition1 resul

随机推荐

  • 如何在 php 中创建类似 twitter 的 search.json

    我在我的网站上创建了一个 search php 文件 它生成一个 JSON 字符串 帮助我为我的应用程序使用实时 ajax 但现在 我想将它作为 API 向其他人开放 但我发现 get getJSON ajax 不允许使用来自其他服务器 域
  • 使用 Django dumpdata 转储整体数据的子集?

    我正在尝试使用 dumpdata 为数据库生成 JSON 该数据库对于 django 来说足够大 需要很长一段时间才能输出 有没有办法只转储字段的子集 比如说 100 用于测试 我正在使用 MySQL 和 Django 1 0 第三方 dj
  • Plotly:如何在桑基图中设置节点位置?

    样本数据如下 unique list home0 page a0 page b0 page a1 page b1 page c1 page b2 page a2 page c2 page c3 sources 0 0 1 2 2 3 3 4
  • 如何使用冒泡排序对链表进行排序?

    我正在尝试使用冒泡排序来对链接列表进行排序 我使用 curr 和 Trail 来遍历列表 curr 应该总是比 Trail 领先一步 到目前为止 这是我的代码 void linked list sort int i j 0 int coun
  • 将 Docker 镜像内的用户切换为非 root 用户

    我正在尝试将用户切换到 tomcat7 用户以设置 SSH 证书 当我做su tomcat7 什么都没发生 whoami完成后仍然会rootsu tomcat7 Doing a more etc passwd 我得到以下结果 清楚地表明 t
  • 如何通过给出正在运行的进程名称来获取窗口句柄?

    如何通过在 c 中给出进程名称或窗口标题来获取窗口句柄 假设进程已经在运行 您可以使用Process class Process processes Process GetProcessesByName someName foreach P
  • 我应该在 for in 构造中使用 var 吗?

    我在一段 JavaScript 逻辑中使用了 for in 循环 我应该使用 var 关键字吗 当我按照 W3School 的示例运行 for in 循环时 如果没有 var 那么作为副作用 它被定义为全局范围 窗口 上的属性 functi
  • 登录后如何重定向 django.contrib.auth.views.login ?

    我添加了 django contrib auth views login我的网页上到处都是 为此我必须加载一个模板标签 https docs djangoproject com en 1 2 ref templates builtins 返
  • Rails:“in”之间的区别?和“包括?”在 Rails 中

    我正在研究 Rails 的 ActiveSupport 扩展 并且遇到了 in 方法 对我来说 它的外观和工作方式与 包含 完全相同 方法 只不过是反过来而已 1 5 include 1 1 in 1 5 我一直在使用 包含 自从我第一次开
  • 结合使用关系数据库和键值存储

    我正在工作的项目的要求似乎是同时使用关系数据库 例如 postgre MySQL 和键值存储 例如 HBase Cassandra 除了少量的相互依赖之外 我们的数据几乎可以很好地分解为两个数据模型之一 这并不是试图将关系数据库塞进键值存储
  • X,Y 坐标到 gcode

    我正在从事一个计算机科学项目 该项目是一个 CNC 绘图仪 基本上我看到的所有获取 Gcode 的方法都使用 Inkscape 我已经编写了软件将普通图像仅转换为黑白边缘 并且我已经从图像中提取了坐标 有什么方法可以使用 X Y 坐标生成
  • 如何从大量文件夹中删除单个用户 ACL?

    我有一个非常大的文件夹列表 我需要从每个文件夹中删除一个 ACL 我没有手动执行此操作 而是尝试编写一个脚本来在很短的时间内完成此操作 但我遇到了一些麻烦 这是我到目前为止所拥有的 filepath C ALCTEST user domai
  • VS Code 在哪里存储打开文件的列表?

    我正在尝试在工作和家里同步 VS Code 实例 包括打开文件的列表 我知道有同步设置的扩展 但它们不包括打开文件 AFAIK 我不希望在运行实例下进行实时同步 但是如果我重启两台机器并在它们上启动代码 我希望它们相同 目前 我在 OneD
  • HAML 和 Ruby 循环以及 UL 不起作用

    我试图让这个简单的列表正常工作 但是 ul 正在关闭 并且没有将 li 元素包含在循环中 我是否缺少一个简单的方法来做到这一点 ul nav nav tabs nav stacked courses each do c li link to
  • 将数组作为单独的值传递给 params

    我正在调用一个与以下形式相同的函数string format其中第一个参数是字符串 其余参数是替换值 我在变量中有字符串 在数组中有替换值 给定数组中任意数量的对象 如何调用此函数 简单地传入数组作为最后一个参数是行不通的 Use the
  • 亚马逊 Lambda 到 Firebase

    当我尝试在 Lambda Node js 4 3 中运行此模块时 出现 找不到模块 firebase var Firebase require firebase 当我尝试上传包含 node modules firebase 的压缩包时 也会
  • 将“%>%”与“lm”和“rbind”一起使用

    我有一个数据框Z看起来像 t x y d 0 1 2 1 1 2 3 1 2 3 4 1 0 1 2 2 1 2 3 2 2 3 4 2 with d是一个因子列 我知道想要拟合线性模型lm to y over t对于两个因素d并将其作为新
  • 如何处理“无法将代码块解析为 Rust 代码”rustdoc 警告?

    我正在写一些 Rust 文档示例 正在编译 rust macro use extern crate But cargo doc给我这个 不正确 警告 warning could not parse code block as Rust co
  • 如何使用 FK 设置集合属性?

    我有一个Business and a Category model Each Business有很多Categories通过公开的集合 Category是无视Business实体 现在这是我的控制器操作 HttpPost ValidateA
  • 这是关闭 fork 上的套接字描述符的正确方法吗?

    考虑这段代码 socket fd start server port while 1 new socket fd accept client socket fd int pid fork if pid 0 I am the child se