Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby-TCPSocket不';当服务器被关闭时,我不会注意到它_Ruby_Sockets - Fatal编程技术网

Ruby-TCPSocket不';当服务器被关闭时,我不会注意到它

Ruby-TCPSocket不';当服务器被关闭时,我不会注意到它,ruby,sockets,Ruby,Sockets,我有一个连接到TCP服务器(即netcat)的ruby代码。它循环20次,并发送“ABCD”。如果我杀死netcat,则需要两次循环才能触发异常。在netcat被终止后的第一个循环中,不会触发异常,“发送”报告已正确写入5个字节。。。这最终不是真的,因为服务器当然从未收到过它们 有办法解决这个问题吗?现在我正在丢失数据:因为我认为数据传输正确,所以我不会重放它 #!/usr/bin/env ruby require 'rubygems' require 'socket' sock = TCPS

我有一个连接到TCP服务器(即netcat)的ruby代码。它循环20次,并发送“ABCD”。如果我杀死netcat,则需要两次循环才能触发异常。在netcat被终止后的第一个循环中,不会触发异常,“发送”报告已正确写入5个字节。。。这最终不是真的,因为服务器当然从未收到过它们

有办法解决这个问题吗?现在我正在丢失数据:因为我认为数据传输正确,所以我不会重放它

#!/usr/bin/env ruby
require 'rubygems'
require 'socket'

sock = TCPSocket.new('192.168.0.10', 5443)
sock.sync = true

20.times do
  sleep 2
  begin
    count = sock.write("ABCD ")
    puts "Wrote #{count} bytes"
  rescue Exception => myException
    puts "Exception rescued : #{myException}"
  end
end

我尝试不使用
sleep
功能(只是为了确保它没有挂起任何东西),但仍然没有成功:

#!/usr/bin/env ruby
require 'rubygems'
require 'socket'
require 'activesupport' # Fixnum.seconds

sock = TCPSocket.new('127.0.0.1', 5443)
sock.sync = true

will_restart_at = Time.now + 2.seconds
should_continue = true

while should_continue
  if will_restart_at <= Time.now
    will_restart_at = Time.now + 2.seconds
    begin
      count = sock.write("ABCD ")
      puts "Wrote #{count} bytes"
    rescue Exception => myException
      puts "Exception rescued : #{myException}"
      should_continue = false
    end
  end
end

那么这里的结论是什么?除非您确实希望从服务器获得一些数据,否则您必须检测到您已失去连接:)

要检测正常关闭,您必须从套接字读取数据-读取返回0表示套接字已关闭


如果您确实需要知道数据是否成功发送,那么除了在应用程序级别实现数据确认之外,没有其他方法。

当您发送数据时,当数据写入TCP输出缓冲区时,阻塞调用将返回。它只会在缓冲区已满时阻塞,等待服务器确认收到以前发送的数据

一旦数据进入缓冲区,网络驱动程序就会尝试发送数据。如果连接丢失,在第二次尝试写入时,应用程序会发现连接的断开状态

另外,连接是如何关闭的?服务器是否正在主动关闭连接?在这种情况下,客户端套接字将在其下一次套接字调用时得到通知。还是它崩溃了?或者可能是网络故障,这意味着您无法再通信

只有在尝试通过套接字发送或接收数据时,才会发现断开的连接。这与主动关闭连接不同。如果不对连接进行操作,就无法确定该连接是否仍然存在

因此,尝试在写入后执行
sock.recv(0)
——如果套接字失败,这将引发“
Errno::ECONNRESET:Connection reset by peer-recvfrom(2)
”。您也可以尝试
sock.sendmsg”“、0
(不是sock.write或sock.send),这将报告一个“
Errno::eppe:breaked pipe-sendmsg(2)

即使您获得了TCP数据包并确认数据已在另一端收到,也无法保证服务器将处理此数据-它可能在其输入缓冲区中,但尚未处理


所有这些都可能有助于更早地识别断开的连接,但仍然不能保证服务器能够接收和处理数据。要知道应用程序已处理您的消息,唯一可靠的方法是使用应用程序级响应。

确实如此。那就意味着我完蛋了?“二进制接口为二进制内容使用一个普通TCP套接字;它本质上是流式的,没有任何确认响应。”我注意到,在这个套接字上读取的IO.select确实返回true。因此,至少如果你使用它,你会知道如何阅读。它将抛出一个错误。这比默默失败要好得多。谢谢你发布这个答案。别人看到这种奇怪的行为让我感觉好多了。注意:我在jruby和mri 1.9.3中看到了这一点。供将来参考-方法名称中有一个输入错误(它是
sendmsg
,而不是
send\u msg
)。对于明目张胆的复制粘贴者来说,这肯定是致命的。如果编辑时没有6个字符的限制,我会自己更正。
irb> sock = TCPSocket.new('127.0.0.1', 80)
=> #<TCPSocket:0xb743b824>
irb> sock.write("salut")
=> 5
irb> sock.read
=> "<html>\r\n<head><title>400 Bad Request</title></head>\r\n<body>\r\n</body>\r\n</html>\r\n"

# Here, I kill nginx

irb> sock.write("salut")
=> 5
irb> sock.read
=> ""
irb> sock.write("salut")
Errno::EPIPE: Broken pipe