正确关闭插座 - 另一侧在读取时卡住

时间:2018-02-02 13:20:33

标签: c sockets operating-system

while (((connfd = accept(listenfd)) != -1){
    if (fork() == 0) {
        write(connfd, buffer ,strlen(buffer));
        close(connfd);
    }
}

大家好,我在OS上获得了一个考试样题。 假设我有一个使用上述代码处理多个客户端的TCP服务器。如问题中所述,其余代码应该有效。现在,每次客户端连接到此服务器时,它都会从中读取数据然后卡住。这个问题的正确答案是,它发生是因为服务器没有正确关闭与客户端的连接。

我不确定我是否完全得到它,不是

  

接近(插座)

足够? 就我而言,当一个插座被一侧关闭时,另一侧读取EOF并返回0.考虑到客户端在读取时卡住了,它不应该到达那个EOF并继续前进?

2 个答案:

答案 0 :(得分:1)

fork()将在子进程中返回0,并在父进程中返回正pid。因此,close(connfd);仅在子进程中调用。

但是,父进程执行了accept,它仍然保留了一个打开的文件描述符到套接字。它也需要关闭它。在关闭所有打开的文件描述符之前,不会关闭套接字。也就是说,你需要像

这样的东西
pid_t child_pid = fork();
if (child_pid == 0) {
    write(connfd, buffer ,strlen(buffer));
    close(connfd);
}
else if (child_pid > 0) {
    // parent
    close(connfd);
}
else {
    // a fork error occurred, handle and remember to close(connfd)
}

答案 1 :(得分:0)

@ AnttiHaapala的回答。

发送内容后,不应立即关闭套接字。一旦数据排队就写入返回,并且在发送所有内容之前实际发生关闭。

万无一失的方法是使用graceful shutdown

pid_t child_pid = fork();
if (child_pid == 0) {
    write(connfd, buffer ,strlen(buffer));
    shutdown(connfd, SD_SEND);              // send an EOF condition
    while (read(connfd, buffer, sizeof(buffer) > 0);  // wait for the peer to close its side
    close(connfd);          // and actually close
}
else if (child_pid > 0) {
    // parent
    close(connfd);          // direct close because no send is pending
}
else {
    // a fork error occurred, handle and remember to close(connfd)
}