C 这是关闭fork上套接字描述符的正确方法吗?
考虑以下代码:C 这是关闭fork上套接字描述符的正确方法吗?,c,sockets,client-server,fork,tcpclient,C,Sockets,Client Server,Fork,Tcpclient,考虑以下代码: 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_wit
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;
}
}
socket\u fd=启动服务器(端口);
而(1){
新的\u套接字\u fd=接受客户端(套接字\u fd);
int-pid=fork();
如果(pid==0){
//我是子服务器进程
关闭(socket_fd);将注释流转换为答案
太长,读不下去了
是的。问题中的描述看起来是正确的,推理是正确的
在某种程度上,您的父进程应该等待已死亡的子进程,以防止僵尸的累积(但在子进程死亡之前它不应该阻止)。在循环中使用WNOHANG
参数可能是合适的,在循环的父循环关闭new\u socket\u fd
的部分。这可能会留下一个或多个僵尸,直到发出下一个传入请求。如果这是一个问题,您可以忽略SIGCHLD
(因此永远不会创建僵尸),或者您可以安排定期唤醒,在此期间父进程检查僵尸
讨论
快速提问-那么父进程何时/何地关闭套接字
当父进程退出循环或被告知停止侦听套接字时,父进程将关闭套接字。\u fd
。所示代码中没有这方面的实际规定,因此当父进程终止(或发生fork故障)时,它将关闭。关键是侦听套接字可用于许多连接-在完成侦听之前,您不希望在父级中关闭它
在这种情况下,因为这是一个无止境的循环,所以永远不会。服务器将始终侦听listen(socket\u fd,N)
中定义的多达N个连接
请注意,listen()
调用中的N参数是可排队等待侦听进程的未完成连接数。也就是说,尚未通过accept()返回值的连接请求数
调用。这不是对accept()
接受连接后可同时激活的连接数的限制
在孩子关闭套接字\u fd
之前,绑定端口是否映射到两个PID?如果有传入数据包,它将被放入谁的队列
传入数据包与套接字的“打开文件描述”(或等效项-与“文件描述符”或“套接字描述符”不同)。无论是家长还是孩子,只要先读,都可以使用。类似地,传入的连接请求在套接字_fd
上排队;家长或孩子都可以接受这些请求。但是,家庭已经同意由谁来做,这样他们就不会妨碍彼此
马特奥
我猜是父母的
阿杰
如果是这种情况,那么新的\u socket\u fd的数据包也会发生同样的情况,因为两个数据包都是打开的。这意味着在父节点关闭数据包之前,子节点将无法读取数据包。这可能会导致争用情况
这是基于误解。数据包通过文件描述符可供两个进程使用。当一个进程关闭文件描述符时,它将无法再访问发送到连接的信息(当然,也不能发送该连接上的数据)在那之前,除非参与者在谁读取数据、谁监听连接的问题上达成一致意见,否则只能靠抽签来判断
马特奥
但是文件描述符不应该在父级和子级之间产生干扰;这就是为什么关闭子级上的socket\u fd
不会阻止父级侦听的原因
巴本
同意。但我认为你应该在while循环后关闭插座\u fd
。万一明天你因某种情况而将循环更改为中断,你将冒着无故保持插座打开的风险
这是一种良好的做法,但循环不会退出(这是一个而(1)
循环,故障模式会从循环中返回
——在执行该操作之前,它可能会关闭套接字返回
).如果程序退出,那么系统会关闭套接字,因此这并不重要,因为关闭打开的内容是一种良好的内务管理
阿杰
父级和子级中的文件描述符都不同。因此关闭一个描述符不应影响另一个描述符。但两个副本具有相同的4元组(src-ip、src-port、dest-ip、dest-port),因此具有此类头的数据包会去哪里
描述符不同,但它们所指的套接字连接是相同的。数据包可用于任何读取它的进程-父进程或子进程
马特奥
在我的示例中,accept\u client
为客户机创建了sockaddr
结构,因此4元组转到孩子的new\u socket\u fd
这不太准确。首先,accept\u client()
在有子函数之前调用;new\u socket\u fd
仅在该函数完成时位于父函数中。第二,在fork()之后
,这两个进程都可以访问新的\u socket\u fd
,并且都可以读取客户端进程发送的数据。但是,该程序的设计使服务器能够在子进程在新的\u socket\u fd
上处理传入的连接时重新侦听更多的连接请求,这是一种合理的分工。
请注意,允许父进程监听请求,子进程继续监听。但是,这与约定相反。这意味着“守护进程”进程监听会在每个连接请求上更改PID,从而难以确定当前正在套接字上监听的进程。传统方法代码中使用的是守护进程在很长一段时间内保持不变,因此记录PID以供以后的进程控制(杀死守护进程)是明智的