Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.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 如何从外部停止udp_服务器_循环_Ruby_Sockets_Server_Udp - Fatal编程技术网

Ruby 如何从外部停止udp_服务器_循环

Ruby 如何从外部停止udp_服务器_循环,ruby,sockets,server,udp,Ruby,Sockets,Server,Udp,我用Ruby编写了小UDP服务器: 听着 将启动的UDP服务器置于{@port}。。。 Socket.udp_服务器_loop@portdo |消息,消息源| 放置从{message\u source}获取的\{message}\ 处理\u传入消息\u消息 终止 终止 我从一个单独的线程开始: thread=thread.new{listen} 有没有一种方法可以从线程外部优雅地停止udp_服务器_循环,而不只是终止它thread.kill?我也不想通过接收任何UDP消息从内部阻止它。udp_s

我用Ruby编写了小UDP服务器:

听着 将启动的UDP服务器置于{@port}。。。 Socket.udp_服务器_loop@portdo |消息,消息源| 放置从{message\u source}获取的\{message}\ 处理\u传入消息\u消息 终止 终止 我从一个单独的线程开始:

thread=thread.new{listen}
有没有一种方法可以从线程外部优雅地停止udp_服务器_循环,而不只是终止它thread.kill?我也不想通过接收任何UDP消息从内部阻止它。udp_server_loop可能不是适合我的工具吗?

虽然我不知道和/或Threadexit会有什么问题,但您可能会使用thread局部变量

def listen
  Socket.udp_server_loop(@port) do |message, message_source|
    break :interrupted if Thread.current[:break]
    handle_incoming_message(message)
  end
end

thread[:break] = true

从外部来看。

我不认为您可以使用udp_服务器_循环实现这一点,尽管您可能可以使用它使用的一些方法。您将不得不调用自己的循环,以某种方式发出退出信号,并以某种方式唤醒线程,这样您就不必发送数据包来停止它

一种简单的方法是使用timeout选项进行选择,并设置一个变量来指示您希望线程结束,例如:

@halt_loop = false

def listen
  puts "Started UDP server on #{@port}..."
  sockets = Socket.udp_server_sockets(@port)

  loop do
    readable, _, _ = IO.select(sockets, nil, nil, 1) # timeout 1 sec
    break if @halt_loop
    next unless readable # select returns nil on timeout

    Socket.udp_server_recv(readable) do |message, message_source|
      puts "Got \"#{message}\" from #{message_source}"

      handle_incoming_message(message)
    end
  end
end
然后,当您想要停止线程时,将@halt_loop设置为true

@read, @write = IO.pipe
@halt_loop = false

def listen
  puts "Started UDP server on #{@port}..."
  sockets = Socket.udp_server_sockets(@port)
  sockets << @read

  loop do
    readable, _, _ = IO.select(sockets)
    break if @halt_loop

    readable.delete @read

    Socket.udp_server_recv(readable) do |message, message_source|
      puts "Got \"#{message}\" from #{message_source}"

      handle_incoming_message(message)
    end
  end
end

def end_loop
  @halt_loop = true
  @write.puts "STOP!"
end
这样做的缺点是,它实际上是在进行投票。如果减少超时,则可能会在空循环上做更多的工作,如果增加超时,则在停止线程时必须等待更长的时间

@read, @write = IO.pipe
@halt_loop = false

def listen
  puts "Started UDP server on #{@port}..."
  sockets = Socket.udp_server_sockets(@port)
  sockets << @read

  loop do
    readable, _, _ = IO.select(sockets)
    break if @halt_loop

    readable.delete @read

    Socket.udp_server_recv(readable) do |message, message_source|
      puts "Got \"#{message}\" from #{message_source}"

      handle_incoming_message(message)
    end
  end
end

def end_loop
  @halt_loop = true
  @write.puts "STOP!"
end
另一个稍微复杂一点的解决方案是使用,并将select listen与套接字一起放在上面。然后,您可以直接发出信号以完成选择并退出线程

@read, @write = IO.pipe
@halt_loop = false

def listen
  puts "Started UDP server on #{@port}..."
  sockets = Socket.udp_server_sockets(@port)
  sockets << @read

  loop do
    readable, _, _ = IO.select(sockets)
    break if @halt_loop

    readable.delete @read

    Socket.udp_server_recv(readable) do |message, message_source|
      puts "Got \"#{message}\" from #{message_source}"

      handle_incoming_message(message)
    end
  end
end

def end_loop
  @halt_loop = true
  @write.puts "STOP!"
end
要退出线程,只需调用end_循环,该循环设置@halt_循环标志,然后写入管道,使另一端可读,并使另一个线程从select返回

您可以让这段代码检查可读的IOs,并在其中一个IOs是管道的读取端而不是使用变量时退出,但至少在Linux上存在一个潜在的错误,调用select可能会返回一个文件描述符作为可读的,而实际上它不是。我不知道Ruby是否能解决这个问题,所以安全总比抱歉好

还要确保在将管道传递到udp_服务器_recv之前将其从可读阵列中移除。它不是一个套接字,因此如果您不这样做,将导致异常


这种技术的缺点是管道是“[n]ot在所有平台上都可用。

这只在服务器收到UDP数据包时才会停止,对吗?对。该块仅在新消息上执行。我更希望在不发送UDP数据包的情况下从应用程序内部停止它。我不知道处理传入消息需要多长时间。我正在搜索的内容在语义上类似于:杀死一旦不再处理任何消息,就立即执行线程。您如何知道将不再有任何消息?套接字不是这样工作的。