草庐IT

linux - 套接字、TCP 状态和写入系统调用

coder 2023-06-21 原文

我一直在使用一个简单的服务器,它每 30 秒向客户端发送一个心跳数据包,然后客户端使用心跳回复数据包确认心跳。当我通过发送 SIGKILL、SIGSEGV 粗暴地终止服务器时,客户端很容易通过 select() 和 read() 系统调用发现了这一点。然后我开始想知道当你在客户端写入心跳回复数据包之前这样做会发生什么,所以我在客户端代码中休眠了 20 秒并同时终止了服务器,但发现客户端写入仍然成功。之后立即尝试第二次写入会触发预期的 SIGPIPE 信号并写入返回的 EPIPE。据我所知,这是正常行为,但是,出于好奇,我打印了客户端 tcp 状态。结果是:

  1. TCP_ESTABLISHED - 在发送服务器 SIGKILL 之前。
  2. TCP_CLOSE_WAIT - 在第一次客户端写入之前的服务器端 SIGKILL 之后。
  3. TCP_CLOSE - 在第一次和第二次写入尝试之后。

所以我的问题是:

  1. 为什么第一次写入不引发 SIGPIPE 并返回 EPIPE?
  2. 我能否得出结论:如果在第一次写入后 TCP 状态为 TCP_CLOSE,则表明与服务器的连接已断开,或者我是否必须再次发送数据才能确定?

根据我的理解,目前正在发生的事情的图表:

                       server                               client

          [ESTABLISHED]  |                                     | [ESTABLISHED] 
 SIGKILL or close () --> |                                     |  
          [FIN_WAIT_1]   |------------FIN M------------------->| [CLOSE_WAIT] 
                         |                                     |            ---\
          [FIN_WAIT_2]   |<-----------ACK M+1------------------|               |  
                         |                                     |               |   a read performed after a
          [TIME_WAIT]    |<-----------FIN N--------------------| [LAST_ACK?]   |-- serverside SIGKILL returns 0
                         |                                     |               |   but write succeeds
                         |------------ACK N+1----------------->| [CLOSE]       |
                         |                                     |            ---/
                         |                                     | 
                         |                                     |            ---\
                         |                                     | [CLOSE]       |   After the first write returns
                         |                                     |               |   the TCP/IP state is CLOSED 
                         |                                     | [CLOSE]       |   but even so only the a second 
                         |                                     |               |   returns EPIPE and raises SIGPIPE.
                         |                                     | [CLOSE]       |   
                         |                                     |               v 

最佳答案

Why does the first write not raise SIGPIPE and return EPIPE?

TCP 是异步的。您的 write 仅将数据复制到套接字缓冲区并返回。 TCP 栈在后台接管并发送数据。也就是说,当send/sendmsg/write返回时,并不代表数据已经发送完毕。

当服务器被终止时,内核会为您关闭套接字,发送未完成的数据,然后发送FIN,这会将您的客户端套接字置于TCP_CLOSE_WAIT 状态。它是半开连接状态,客户端仍然可以发送数据,前提是服务器需要它。

您的客户端发送更多数据,但服务器操作系统以 RST 响应,因为没有处理传入数据的进程。这会将您的客户端套接字放入 TCP_CLOSE

can I conclude that if the TCP state is TCP_CLOSE after the first write that the connection to the server is down or do I have to resend the data one more time to be sure?

TCP_CLOSE 是最终的 TCP 状态。不确定您到底在问什么,但是如果您需要确保其他对等点接收并处理了您的数据,则需要发回一些应用程序级消息。

关于linux - 套接字、TCP 状态和写入系统调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24680966/

有关linux - 套接字、TCP 状态和写入系统调用的更多相关文章

  1. ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态 - 2

    我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0

  2. Ruby 写入和读取对象到文件 - 2

    好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信

  3. ruby-on-rails - 跳过状态机方法的所有验证 - 2

    当我的预订模型通过rake任务在状态机上转换时,我试图找出如何跳过对ActiveRecord对象的特定实例的验证。我想在reservation.close时跳过所有验证!叫做。希望调用reservation.close!(:validate=>false)之类的东西。仅供引用,我们正在使用https://github.com/pluginaweek/state_machine用于状态机。这是我的预订模型的示例。classReservation["requested","negotiating","approved"])}state_machine:initial=>'requested

  4. 使用 ACL 调用 upload_file 时出现 Ruby S3 "Access Denied"错误 - 2

    我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file

  5. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  6. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

  7. ruby - 字符串文字中的转义状态作为 `String#tr` 的参数 - 2

    对于作为String#tr参数的单引号字符串文字中反斜杠的转义状态,我觉得有些神秘。你能解释一下下面三个例子之间的对比吗?我特别不明白第二个。为了避免复杂化,我在这里使用了'd',在双引号中转义时不会改变含义("\d"="d")。'\\'.tr('\\','x')#=>"x"'\\'.tr('\\d','x')#=>"\\"'\\'.tr('\\\d','x')#=>"x" 最佳答案 在tr中转义tr的第一个参数非常类似于正则表达式中的括号字符分组。您可以在表达式的开头使用^来否定匹配(替换任何不匹配的内容)并使用例如a-f来匹配一

  8. ruby - 调用其他方法的 TDD 方法的正确方法 - 2

    我需要一些关于TDD概念的帮助。假设我有以下代码defexecute(command)casecommandwhen"c"create_new_characterwhen"i"display_inventoryendenddefcreate_new_character#dostufftocreatenewcharacterenddefdisplay_inventory#dostufftodisplayinventoryend现在我不确定要为什么编写单元测试。如果我为execute方法编写单元测试,那不是几乎涵盖了我对create_new_character和display_invent

  9. ruby - Net::HTTP 获取源代码和状态 - 2

    我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur

  10. 电脑0x0000001A蓝屏错误怎么U盘重装系统教学 - 2

      电脑0x0000001A蓝屏错误怎么U盘重装系统教学分享。有用户电脑开机之后遇到了系统蓝屏的情况。系统蓝屏问题很多时候都是系统bug,只有通过重装系统来进行解决。那么蓝屏问题如何通过U盘重装新系统来解决呢?来看看以下的详细操作方法教学吧。  准备工作:  1、U盘一个(尽量使用8G以上的U盘)。  2、一台正常联网可使用的电脑。  3、ghost或ISO系统镜像文件(Win10系统下载_Win10专业版_windows10正式版下载-系统之家)。  4、在本页面下载U盘启动盘制作工具:系统之家U盘启动工具。  U盘启动盘制作步骤:  注意:制作期间,U盘会被格式化,因此U盘中的重要文件请注

随机推荐