对函数 shutdown(fd, options) 的行为感到困惑

标签 c sockets tcp

我正在测试用于传输基于文本的文件的套接字代码,我正在引用 Unix 网络编程(中文版)一书编写这段代码。我将简要地在下面粘贴一些代码:

我的 serve_client 函数:

void serve_client(int connfd, const char *filename, size_t filesize)
{
    char header[1024];
    int fd = open(filename, O_RDONLY, 0);
    char *file_mapped;
    if (fd == -1)
    {
        char *not_found = "HTTP/1.1 404 NOT FOUND\r\n";
        send(connfd, not_found, strlen(not_found), 0);
    }
    else
    {
        sprintf(header, "HTTP/1.1 200 OK\r\n");
        sprintf(header, "%sContent-Length: %u\r\n", header, filesize);
        sprintf(header, "%sContent-Type: text/plain; charset=utf-8\r\n\r\n", header);
        // send http response header
        send(connfd, header, strlen(header), 0);

        printf("Response headers:\n");
        printf("%s", header);

        file_mapped = (char *)mmap(0, filesize, PROT_READ, MAP_PRIVATE, fd, 0);
        close(fd);

        // send http response body
        send(connfd, file_mapped, filesize, 0);
        int unmapped = munmap(file_mapped, filesize);
        if (unmapped == -1)
        {
            perror("memory unmapped failed!");
            _exit(1);
        }
    }
}

有几个问题想请教各位:

  1. 在这个serve_client()函数成功返回后,我的意思是至少我需要的数据应该被完全复制到内核缓冲区中,以便在不久的将来发送。我对此是否正确?

  2. shutdown() 函数调用如下:

    serve_client(connfd, path, st.st_size);
    shutdown(connfd, SHUT_WR); 
    // thread or process ends
    

我查看了这本书中提到的提示,它说这个函数带有这个选项 SHUT_WR 将导致保留在内核缓冲区中的数据首先被发送,然后是最终的 FIN。是吗?

  1. 我使用 WireShark 抓取发送和接收的数据,如下图所示: https://i.imgur.com/Xu8gAgh.jpg 我看到 RST 在所有数据出现之前就到了。这让客户失败了,例如wget 或只是网络访问。任何建议都会很棒。

现在我通过这样做解决了这个问题,让客户端关闭连接并且服务器等待 FIN 到达。有用。但是,仍然不是我想要的。 :(

while (1)
{
    ssize_t bytes_read = recv(connfd, buf, 1024, 0);
    if (bytes_read > 0)
    {
        continue;
    }
    else if (bytes_read == 0)
    {
        close(connfd);
        break;
    }
    else
    {
        // < 0
        // handle error
        close(connfd);
        break;
    }
} 

编辑 对于这个问题造成的误解,我们深表歉意,转储显示了从服务器发送的 RST,就像我被告知的那样,进程过早退出。这就是前面的代码不起作用的原因。感谢您的所有解释,真正帮助我更好地了解引擎盖下的进展。

最佳答案

Ending a process隐式地 close() 所有文件/套接字描述符。这就是问题所在。发送后关闭可能导致接收方数据丢失(取决于 TCP 堆栈的实现)。

您需要实现一个应用程序级协议(protocol),让客户端在服务器关闭套接字之前确认接收到所有数据。

总结一下:使用 closure of a socket as part of the application level protocol is not reliable .不要这样做。

关于对函数 shutdown(fd, options) 的行为感到困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55528503/

相关文章:

c - C 中整数除法返回 0

c - 如何以与在终端中写入的方式完全相同的方式在文件中写入文本?(保留所有空格)

c# - 从外部 LAN raspberry pi 3 windowsiot 连接到网络服务器

c# - 如何正确处理 "existing connection forcibly closed"

c - 这个c程序跳过scanf();命令并且 switch case 有错误

c - 以特定格式读取日期和时间

c - 协议(protocol)不支持的地址族

c# - 理论 : C# Sockets, 通过网络发送序列化对象

mysql - node-mysql connection.end() 去哪里

c# - TCP 套接字服务器 Windows 应用程序