草庐IT

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

coder 2023-09-18 原文

我正在测试用于传输基于文本的文件的套接字代码,我正在引用 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/

有关对函数 shutdown(fd, options) 的行为感到困惑的更多相关文章

  1. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  2. ruby - Capistrano 3 在任务中更改 ssh_options - 2

    我尝试使用不同的ssh_options在同一阶段运行capistranov.3任务。我的production.rb说:set:stage,:productionset:user,'deploy'set:ssh_options,{user:'deploy'}通过此配置,capistrano与用户deploy连接,这对于其余的任务是正确的。但是我需要将它连接到服务器中配置良好的an_other_user以完成一项特定任务。然后我的食谱说:...taskswithoriginaluser...task:my_task_with_an_other_userdoset:user,'an_othe

  3. ruby-on-rails - rspec should have_select ('cars' , :options => ['volvo' , 'saab' ] 不工作 - 2

    关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion在首页我有:汽车:VolvoSaabMercedesAudistatic_pages_spec.rb中的测试代码:it"shouldhavetherightselect"dovisithome_pathit{shouldhave_select('cars',:options=>['volvo','saab','mercedes','audi'])}end响应是rspec./spec/request

  4. ruby-on-rails - 在 ruby​​ 中使用 gsub 函数替换单词 - 2

    我正在尝试用ruby​​中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了

  5. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  6. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

  7. ruby - 在 Ruby 中按名称传递函数 - 2

    如何在Ruby中按名称传递函数?(我使用Ruby才几个小时,所以我还在想办法。)nums=[1,2,3,4]#Thisworks,butismoreverbosethanI'dlikenums.eachdo|i|putsiend#InJS,Icouldjustdosomethinglike:#nums.forEach(console.log)#InF#,itwouldbesomethinglike:#List.iternums(printf"%A")#InRuby,IwishIcoulddosomethinglike:nums.eachputs在Ruby中能不能做到类似的简洁?我可以只

  8. C51单片机——实现用独立按键控制LED亮灭(调用函数篇) - 2

    说在前面这部分我本来是合为一篇来写的,因为目的是一样的,都是通过独立按键来控制LED闪灭本质上是起到开关的作用,即调用函数和中断函数。但是写一篇太累了,我还是决定分为两篇写,这篇是调用函数篇。在本篇中你主要看到这些东西!!!1.调用函数的方法(主要讲语法和格式)2.独立按键如何控制LED亮灭3.程序中的一些细节(软件消抖等)1.调用函数的方法思路还是比较清晰地,就是通过按下按键来控制LED闪灭,即每按下一次,LED取反一次。重要的是,把按键与LED联系在一起。我打算用K1来作为开关,看了一下开发板原理图,K1连接的是单片机的P31口,当按下K1时,P31是与GND相连的,也就是说,当我按下去时

  9. ruby - Ruby gsub 替换中的行为不一致? - 2

    两个gsub产生不同的结果。谁能解释一下为什么?代码也可在https://gist.github.com/franklsf95/6c0f8938f28706b5644d获得.ver=9999str="\tCFBundleDevelopmentRegion\n\ten\n\tCFBundleVersion\n\t0.1.190\n\tAppID\n\t000000000000000"putsstr.gsub/(CFBundleVersion\n\t.*\.).*()/,"#{$1}#{ver}#{$2}"puts'--------'putsstr.gsub/(CFBundleVersio

  10. ruby-on-rails - 将字符串转换为 ruby​​-on-rails 中的函数 - 2

    我需要一个通过输入字符串进行计算的方法,像这样function="(a/b)*100"a=25b=50function.something>>50有什么方法吗? 最佳答案 您可以使用instance_eval:function="(a/b)*100"a=25.0b=50instance_evalfunction#=>50.0请注意,使用eval本质上是不安全的,尤其是当您使用外部输入时,因为它可能包含注入(inject)的恶意代码。另请注意,a设置为25.0而不是25,因为如果它是整数a/b将导致0(整数)。

随机推荐