草庐IT

c - tcp 指示流结束

coder 2023-09-20 原文

我无法结束 TCP 流。我正在编写一个简单的服务器和客户端,其中客户端连接到服务器并且服务器显示一条欢迎消息,要求客户端输入用户名。

问题是,当服务器写入消息时,客户端的 read() 被阻塞。它只有在我调用 shutdown() 时才会解锁。

服务器:

           if (FD_ISSET(tcp_listenfd, &rset)) {
                  len = sizeof(cliaddr);
                  if ((new_confd = accept(tcp_listenfd, (struct sockaddr *) &cliaddr, &len)) < 0) {
                            perror("accept");
                            exit(1);
                  }
                  /* Send connection message asking for handle */
                  writen(new_confd, handle_msg, strlen(handle_msg));
                  /* Fork here or shutdown fd is inherited */
                  shutdown(new_confd, SHUT_WR);

客户:

    if ((connect(sock, (struct sockaddr *) server, sizeof(struct sockaddr_in))) < 0) {
            perror("inet_wstream:connect");
            exit(1);
    }

    s_welcome_msg[19] = '\0';
    readn(sock, s_welcome_msg, 20); //Blocks here if shutdown() is not called in server 

readn()writen() 函数改编自 Stevens 的“The Socket Networking API”,可在此处找到:http://www.informit.com/articles/article.aspx?p=169505&seqNum=9

如何在不调用 shutdown() 且不让客户端阻塞的情况下从服务器编写欢迎消息?如果需要更多上下文,我将发布更多代码。

最佳答案

请注意,readn() 设计为循环read(),直到读取了 20 个字节或出现 EOF 或套接字错误。如果服务器发送的消息长度小于 20 个字节,客户端将阻塞等待更多数据。

为防止阻塞,您可以在套接字上执行普通的read()(或recv())。在这种情况下,这很可能会满足您的要求。

不过,一般来说,您不能依赖于将 write()read() 配对用于 TCP 连接。字符串“bar”的单个 write() 可以任意拆分数据。作为一个极端的例子,三个连续的 read() 可能会返回“b”、“a”和“r”。该特定示例不太可能,但对于较大的 write()read(),您必须考虑到这一点(对于较小的传输,如果您想绝对安全)。

要解决此问题,您必须在接收端进行自己的缓冲。在这种情况下,最简单的解决方案是一次 read() 一个字符(或者使用 readn() 与您期望的数据量,如果它是已知的).一个更通用的解决方案是 read() 尽可能多的数据(确保检查 read() 的返回值以查看您返回了多少数据!) 放入缓冲区,并且仅在收集到足够的数据时才对数据进行操作。只要有一些数据可供读取,普通的read() 就不会阻塞,但您取回的数据可能少于您请求的数据。

“够了”通常是您协议(protocol)中的完整“消息”。您将需要一些方法来确定消息边界。两种选择是长度字段(根据我的经验通常是最好的解决方案)或消息终止符。两者都将与其余数据一起发送。

更新:

顺便说一句,你的空终止逻辑有一个错误。将 20 个字节读入 s_welcome_msg 会将 s_welcome_msg[19] 设置为最后读取的字节,覆盖空终止符。如果要将 20 字节的非空终止字符串读入 s_welcome_msg 并以空终止它,s_welcome_msg 需要 21 字节长,并且您需要执行 s_welcome_msg[20] = '\0'

关于c - tcp 指示流结束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29189821/

有关c - tcp 指示流结束的更多相关文章

  1. ruby-on-rails - 有没有办法为 CarrierWave/Fog 设置上传进度指示器? - 2

    我在Rails应用程序中使用CarrierWave/Fog将视频上传到AmazonS3。有没有办法判断上传的进度,让我可以显示上传进度如何? 最佳答案 CarrierWave和Fog本身没有这种功能;你需要一个前端uploader来显示进度。当我不得不解决这个问题时,我使用了jQueryfileupload因为我的堆栈中已经有jQuery。甚至还有apostonCarrierWaveintegration因此您只需按照那里的说明操作即可获得适用于您的应用的进度条。 关于ruby-on-r

  2. ruby - 如何通过 Rubocop 指示打开 & :read as argument to File. - 2

    我有这个代码File.open(file_name,'r'){|file|file.read}但是Rubocop发出警告:Offenses:Style/SymbolProc:Pass&:readasargumenttoopeninsteadofablock.你是怎么做到的? 最佳答案 我刚刚创建了一个名为“t.txt”的文件,其中包含“Hello,World\n”。我们可以按如下方式阅读。File.open('t.txt','r',&:read)#=>"Hello,World\n"顺便说一下,由于第二个参数的默认值是'r',所以这样

  3. ruby - 如果满足给定条件,则结束 ruby​​ 程序 - 2

    基本上,我只是试图在满足特定条件时停止程序运行其余行。unlessraw_information.firstputs"Noresultswerereturnedforthatquery"breakend然而,在程序运行之前我得到了这个错误:Invalidbreakcompileerror(SyntaxError)执行此操作的正确方法是什么? 最佳答案 abort("Noresultswerereturnedforthatquery")unlesscondition或unlessconditionabort("Noresultswer

  4. ruby-on-rails - Ruby/Rails 中的夏令时开始和结束日期 - 2

    我正在开发一个Rails应用程序,我需要在其中找到给定特定偏移量或时区的夏令时开始和结束日期。我基本上在我的数据库中保存了从用户浏览器接收到的时区偏移量(“+3”,“-5”),我想在它出现时修改它由于夏令时的变化。我知道Time实例变量有dst?和isdst方法,如果存储在它们中的日期在夏令时与否。>Time.new.isdst=>true但是使用它来查找夏令时的开始和结束日期会占用太多资源,而且我还必须为我拥有的每个时区偏移量执行此操作。我想知道更好的方法。 最佳答案 好的,基于你所说的和@dhouty'sanswer:您希望能够

  5. ruby - 如何在 watir 测试套件结束时关闭浏览器? - 2

    使用ruby​​的watir测试网络应用程序时,浏览器最后会保持打开状态。网上的一些建议是,要进行真正的单元测试,您应该在每次测试时(在拆卸调用中)打开和关闭浏览器,但这很慢而且毫无意义。或者他们做这样的事情:defself.suites=superdefs.afterClass#Closebrowserenddefs.run(*args)superafterClassendsend但这会导致摘要输出不再显示(诸如“100次测试、100次断言、0次失败、0次错误”之类的内容仍应显示)。我怎样才能让ruby​​或watir在我的测试结束时关闭浏览器? 最佳答案

  6. ruby - 从结束值创建一系列字符串 - 2

    我使用irb。下面是我写的代码。“斧头”..“bc”我期待"ax""ay""az""ba"bb""bc"但结果只是“斧头”..“bc”我该如何纠正?谢谢。 最佳答案 >puts("ax".."bc").to_aaxayazbabbbc 关于ruby-从结束值创建一系列字符串,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/7617092/

  7. ruby - 如何在 vim 中删除 ruby​​ 周围的 block (做/结束) - 2

    如何用vim删除ruby中do/end分隔的环绕block例如(10..20).mapdo|i|(1..10).mapdo|j|pjendend我想做一些类似dsb的事情(删除环绕block)并得到(1..10).mapdo|j|pjend 最佳答案 也许你可以制作nnormap。每个end/do对都在同一个缩进上,所以首先你应该找到对缩进-在这种情况下,下一行相同的缩进(因为你的光标在do行。)所以你可以让vimscript函数找到下一个缩进线并删除它。这是函数的一个例子。您可以自定义您想要的-即)为休息行设置缩进。functio

  8. ruby - 如何检测 Ruby 中方法链的结束 - 2

    我有一个我不久前写的Flickr界面,其中一部分让我很困扰,我想让它变得更好。它的工作方式是我使用缺少的方法从调用flickr对象的方法构造flickr调用的url参数,例如。@flickr.groups.pools.getPhotos(:user_id=>"12656878@N06",:group_id=>"99404851@N00")这些“方法调用”构造了一个如下所示的api调用http://api.flickr.com/services/rest/?method=groups.pools.getPhotos&user_id=1848466274&group_id=99404851

  9. 计算机网络笔记:TCP三次握手和四次挥手过程 - 2

    TCP是面向连接的协议,连接的建立和释放是每一次面向连接的通信中必不可少的过程。TCP连接的管理就是使连接的建立和释放都能正常地进行。三次握手TCP连接的建立—三次握手建立TCP连接①若主机A中运行了一个客户进程,当它需要主机B的服务时,就发起TCP连接请求,并在所发送的分段中用SYN=1表示连接请求,并产生一个随机发送序号x,如果连接成功,A将以x作为其发送序号的初始值:seq=x。主机B收到A的连接请求报文,就完成了第一次握手。客户端发送SYN=1表示连接请求客户端发送一个随机发送序号x,如果连接成功,A将以x作为其发送序号的初始值:seq=x②主机B如果同意建立连接,则向主机A发送确认报

  10. ruby-on-rails - Rails Rake Tasks,在期间和结束时输出一条消息 - 2

    我做了一个railsrake任务,可以上传/裁剪/调整(使用回形针)大量图片。我想知道如何在运行时向终端输出消息(例如chipolata.jpg已处理),最后,它需要几分钟才能运行并且有一点反馈会很好。谢谢。 最佳答案 只需使用标准的Rubyputs命令:puts"HellofromRake!"您可以使用字符串插值在循环中输出单个文件名:puts"#{image_filename}processed" 关于ruby-on-rails-RailsRakeTasks,在期间和结束时输出一条消

随机推荐