4

我有一种情况,我的服务器可能会关闭TCPServer并重新启动,将所有用户保存到一个文件中,然后立即重新加载它们;他们的连接不会断开。

问题是我似乎无法重新初始化他们的流。

当我们重新启动(并尝试保持连接)时,我重新初始化 TCPServer,并加载我的已连接用户数组 -因为这些每个都有一个现有的套接字地址,存储为<TCPSocket:0x00000000000000>,我可以用 TCPServer 重新初始化这些地址吗?

通常,每个用户都连接并被接受:

$nCS = TCPServer.new(HOST, PORT)

begin
  while socket = $nCS.accept
    Thread.new( socket ) do |sock|
      begin
        d = User.new(sock)
        while sock.gets
          szIn = $_.chomp
          DBG( "Received '" + szIn + "' from Client " + sock.to_s )
          d.parseInput( szIn )
        end
      rescue => e
        $stdout.puts "ERROR: Caught error in Client Thread: #{e} \r\n #{e.backtrace.to_s.gsub(",", ",\r\n")}"
        sock.write("Sorry, an error has occurred, and you have been disconnected."+EOL+"Please try again later."+EOL)
        d.closeConnection
      end
    end
  end
rescue => e
  $stdout.puts "ERROR: Caught error in Server Thread: #{e} \r\n #{e.backtrace.to_s.gsub(",", ",\r\n")}"
  exit
end

为了给它一个热重启的命令,我们exec('./main --copyover')用来标记正在发生复制。

如果$connected包含所有用户的数组,并且每个用户都有一个套接字,我如何重新初始化在重新启动之前打开的套接字(假设另一端仍然连接)?

我怀疑 usingexec("./main", "--copyover", *$nCS, *$connected)让我更接近,因为这只是替换了进程,并且应该维护文件(而不是关闭它们)。

4

2 回答 2

1

你不能。套接字仅在进程的生命周期内有效:当进程退出时它被操作系统关闭。这反过来又使连接无效,因此另一端仍未连接。

于 2012-09-04T23:52:31.210 回答
1

如何在 Ruby 中热重启 TCPServer

热重启(又名复制)是管理员可以在不丢失客户端连接的情况下重新加载应用程序(以及自上次启动以来所做的任何新更改)的过程。这对于管理客户期望很有用,因为应用程序在使用时不需要遭受严重的停机和中断。

我在下面提出的建议可能不是最佳实践,但它正在发挥作用,并且可能会引导其他人采用类似的解决方案。

命令

我使用一种特殊的编码风格,利用命令表来查找函数及其可访问性。所有命令函数都以cmd. 我将清理杂项以提高可读性:

def cmdCopyover
  #$nCS is the TCPServer object
  #$connected holds an array of all users sockets
  #--copyover flags that this is a hot reboot.
  connected_args = $connected.map do |sock|
    sock.close_on_exec = false if sock.respond_to?(:close_on_exec=)
    sock.fileno.to_s
  end.join(",")
  exec('./main.rb', '--copyover', $nCS.fileno.to_s, connected_args)
end

我们传递的是字符串;$nCS.fileno.to_s为我们提供主 TCPServer 对象的文件描述符,同时connected_args是每个连接的用户的文件描述符的逗号分隔列表。当我们重新启动时,ARGV将是一个包含每个参数的数组:

  • ARGV[0] == "--copyover"
  • ARGV[1] == "5"(或者无论 TCPServer 的文件描述符是什么)
  • ARGV[2] == "6,7,8,9"(例如,假设有 4 个连接的用户)

当您期待时会期待什么(复制)

在正常情况下,我们可能有一个基本服务器(main.rb看起来像这样:

puts "Starting Server"
$connected = Array.new
$nCS = TCPServer.new("127.0.0.1",9999)

begin
  while socket = $nCS.accept
    # NB: Move this loop to its own function, threadLoop()
    Thread.new( socket ) do |sock|
      begin
        while sock.gets
          szIn = $_.chomp
          #do something with input.
        end
      rescue => e
        puts "ERROR: Caught error in Client Thread: #{e}"
        puts #{e.backtrace.to_s.gsub(",", ",\r\n")}"
        sock.write("Sorry, an error has occurred, and you have been disconnected."+EOL+"Please try again later."+EOL)
        sock.close
      end
    end
  end
rescue => e
  puts "Error: Caught Error in Server Thread: #{e}"
  puts "#{e.backtrace.to_s.gsub(",", ",\r\n")}"
  exit
end

我们想将该主循环移动到它自己的函数中以使其可访问——我们重新连接的用户将需要重新插入循环中。

因此,让我们main.rb准备好接受热重启:

def threadLoop( socket )
  Thread.new( socket ) do |sock|
    begin
      while sock.gets
        szIn = $_.chomp
        #do something with input.
      end
    rescue => e
      puts "ERROR: Caught error in Client Thread: #{e}"
      puts #{e.backtrace.to_s.gsub(",", ",\r\n")}"
      sock.write("Sorry, an error has occurred, and you have been disconnected."+EOL+"Please try again later."+EOL)
      sock.close
    end
  end
end

puts "Starting Server"
$connected = Array.new
if ARGV[0] == '--copyover'
  $nCS = TCPServer.for_fd( ARGV[1].to_i )
  $nCS.close_on_exec = false if $nCS.respond_to?(:close_on_exec=)
  connected_args = ARGV[2]
  connected_args.split(/,/).map do |sockfd|
  $connected << sockfd

  $connected.each {|c| threadLoop( c ) }
else
  $nCS = TCPServer.new("127.0.0.1",9999)
  $nCS.close_on_exec = false if $nCS.respond_to?(:close_on_exec=)
end

begin
  while socket = $nCS.accept
    threadLoop( socket )
  end
rescue => e
  puts "Error: Caught Error in Server Thread: #{e}"
  puts "#{e.backtrace.to_s.gsub(",", ",\r\n")}"
  exit
end

警告

我的实际使用要复杂得多,所以我尽力去除所有垃圾;然而,当我在这里结束时,我意识到你可能没有这样做$connected(它对我来说是一个更大系统的一部分)。可能有一些错误,所以如果你发现它们请评论,我会更正。

希望这对找到它的人有所帮助。

于 2012-09-06T19:49:42.300 回答