关闭 Ruby TCPSocket 客户端时流已关闭(IOError)

发布于 2024-11-17 00:08:42 字数 1581 浏览 0 评论 0原文

我有一个 Ruby TCPSocket 客户端,它工作得很好,除非我试图关闭它。当我在下面的代码中调用 disconnect 方法时,出现此错误:

./smartlinc.rb:70:in `start_listen': stream closed (IOError)
    from ./smartlinc.rb:132:in `initialize'
    from ./smartlinc.rb:132:in `new'
    from ./smartlinc.rb:132:in `start_listen'
    from bot.rb:45:in `initialize'
    from bot.rb:223:in `new'
    from bot.rb:223

这是(简化的)代码:

class Smartlinc

    def initialize
        @socket = TCPSocket.new(HOST, PORT)
    end

    def disconnect
        @socket.close
    end

    def start_listen
        # Listen on a background thread
        th = Thread.new do
            Thread.current.abort_on_exception = true

            # Listen for Ctrl-C and disconnect socket gracefully.
            Kernel.trap('INT') do 
                self.disconnect
                exit
            end

            while true
                ready = IO.select([@socket])
                readable = ready[0]
                readable.each do |soc|
                    if soc == @socket
                        buf = @socket.recv_nonblock(1024)
                        if buf.length == 0
                            puts "The socket connection is dead. Exiting."
                            exit
                        else
                            puts "Received Message"
                        end
                    end
                end # end each
            end # end while

        end # end thread
    end # end message callback

end

有没有办法可以防止或捕获此错误?我不是套接字编程方面的专家(显然!),因此感谢所有帮助。

I've got a Ruby TCPSocket client that works great except when I'm trying to close it. When I call the disconnect method in my code below, I get this error:

./smartlinc.rb:70:in `start_listen': stream closed (IOError)
    from ./smartlinc.rb:132:in `initialize'
    from ./smartlinc.rb:132:in `new'
    from ./smartlinc.rb:132:in `start_listen'
    from bot.rb:45:in `initialize'
    from bot.rb:223:in `new'
    from bot.rb:223

Here's the (simplified) code:

class Smartlinc

    def initialize
        @socket = TCPSocket.new(HOST, PORT)
    end

    def disconnect
        @socket.close
    end

    def start_listen
        # Listen on a background thread
        th = Thread.new do
            Thread.current.abort_on_exception = true

            # Listen for Ctrl-C and disconnect socket gracefully.
            Kernel.trap('INT') do 
                self.disconnect
                exit
            end

            while true
                ready = IO.select([@socket])
                readable = ready[0]
                readable.each do |soc|
                    if soc == @socket
                        buf = @socket.recv_nonblock(1024)
                        if buf.length == 0
                            puts "The socket connection is dead. Exiting."
                            exit
                        else
                            puts "Received Message"
                        end
                    end
                end # end each
            end # end while

        end # end thread
    end # end message callback

end

Is there a way I can prevent or catch this error? I'm no expert in socket programming (obviously!), so all help is appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

涙—继续流 2024-11-24 00:08:42

您的线程位于 IO.select() 中,而陷阱代码则愉快地使用 @socket.close 关上门,因此您会收到一些抱怨。

不要将 abort_on_exception 设置为 true,或者然后在代码中正确处理异常:
沿着这些思路的东西......

Kernel.trap('INT') do
  @interrupted = true
  disconnect
  exit
end

...
ready = nil
begin
  ready = IO.select(...)
rescue IOError
  if @interrupted
    puts "Interrupted, we're outta here..."
    exit
  end
  # Else it was a genuine IOError caused by something else, so propagate it up..
  raise
end

...

Your thread is sitting in IO.select() while the trap code happily slams the door in its face with @socket.close, hence you get some complaining.

Don't set abort_on_exception to true, or then handle the exception properly in your code:
Something along these lines...

Kernel.trap('INT') do
  @interrupted = true
  disconnect
  exit
end

...
ready = nil
begin
  ready = IO.select(...)
rescue IOError
  if @interrupted
    puts "Interrupted, we're outta here..."
    exit
  end
  # Else it was a genuine IOError caused by something else, so propagate it up..
  raise
end

...
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文