ruby - 2套接字互操作产生 "socket operation on non-socket - ENOTSOCK"错误

标签 ruby multithreading sockets http

在 Ruby 脚本中,我遇到了套接字连接问题。 我正在做的是以下内容:

  • 我有两个线程,每个线程创建一个到不同网络服务器的连接
  • 每当线程 1 从服务器 1 接收数据时,我希望线程 1 将此数据发布到服务器 2
  • 每当线程 2 从服务器 2 接收数据时,我希望线程 2 将此数据发布到服务器 1

基本上我充当了两个服务器之间的桥梁。

代码如下所示:

require 'uri'
require 'net/http'
require 'json'

@connection1 = Net::HTTP.start 'server1.com'
@connection2 = Net::HTTP.start 'server2.com'

# reads data from server 1 as it comes and sends it to server 2     
Thread.new{
  while JSON.parse(@connection1.post('/receive').body) !nil
      @connection2.post '/send', JSON.parse(@connection1.post('/receive').body) 
  end
}


# reads data from server 2 as it comes and sends it to server 2  
while JSON.parse(@connection2.post('/receive').body) !nil
    @connection1.post '/send', JSON.parse(@connection2.post('/receive').body) 
end

# Thread.join 
# not actually needed because the two connections are supposed to continuously stream data

然而,一旦两个连接之一接收到数据并尝试将其发送到另一个连接,我就会收到以下错误:

非套接字上的套接字操作 - Errno::ENOTSOCK

更多深度堆栈跟踪:

C:/Dev/Ruby24-x64/lib/ruby/2.4.0/net/protocol.rb:176:in wait_readable': socket operation on non-socket. (Errno::ENOTSOCK) from C:/Dev/Ruby24-x64/lib/ruby/2.4.0/net/protocol.rb:176:in 'rbuf_fill' from C:/Dev/Ruby24-x64/lib/ruby/2.4.0/net/protocol.rb:154:in 'readuntil' from C:/Dev/Ruby24-x64/lib/ruby/2.4.0/net/protocol.rb:164:in 'readline' from C:/Dev/Ruby24-x64/lib/ruby/2.4.0/net/http/response.rb:40:in 'read_status_line' from C:/Dev/Ruby24-x64/lib/ruby/2.4.0/net/http/response.rb:29:in 'read_new' from C:/Dev/Ruby24-x64/lib/ruby/2.4.0/net/http.rb:1446:in block in 'transport_request' from C:/Dev/Ruby24-x64/lib/ruby/2.4.0/net/http.rb:1443:in 'catch' from C:/Dev/Ruby24-x64/lib/ruby/2.4.0/net/http.rb:1443:in 'transport_request' from C:/Dev/Ruby24-x64/lib/ruby/2.4.0/net/http.rb:1416:in 'request' from C:/Dev/Ruby24-x64/lib/ruby/2.4.0/net/http.rb:1430:in 'send_entity' from C:/Dev/Ruby24-x64/lib/ruby/2.4.0/net/http.rb:1218:in 'post'

那么你认为我做错了什么?

我应该补充一点,出于我无法控制的原因,两个远程服务器被配置为在与 POST 而不是 GET 联系时提供数据。

最佳答案

核心问题

两个线程之间缺少任何类型的同步,Net::HTTP 不是线程安全的。 这里可能发生的情况是,您在一个线程中调用 @connection1.post/receive,该线程暂停,第二个线程尝试使用 @connection1.post/sendconnection1 仍在使用中。

另一个问题是您的代码效率低下,每个线程发出两个/receive 请求以获取信息。

while JSON.parse(@connection1.post('/receive').body) !nil
      @connection2.post '/send', JSON.parse(@connection1.post('/receive').body) 
  end

这使得总共三个请求

可能是

while True
  result = JSON.parse(@connection1.post('/receive').body)
  break if result.nil?
  @connection2.post '/send', result) 
end

这使得总共有两个请求


建议的解决方案

使用 Mutex 确保当 connection1 正在发送/接收请求时,没有其他线程接触它。

require 'uri'
require 'net/http'
require 'json'

@connection1 = Net::HTTP.start 'server1.com'
@connection2 = Net::HTTP.start 'server2.com'

connection_1_lock = Mutex.new
connection_2_lock = Mutex.new

# reads data from server 1 as it comes and sends it to server 2
Thread.new do
  while True
    receive_result = nil
    connection_1_lock.synchronize do
      receive_result = JSON.parse(@connection1.post('/receive').body)
    end
    connection_2_lock.synchronize do
      @connection2.post '/send', receive_result
    end
  end
end

Thread.new do
  while True
    receive_result = nil
    connection_2_lock.synchronize do
      receive_result = JSON.parse(@connection2.post('/receive').body)
    end
    connection_1_lock.synchronize do
      @connection1.post '/send', receive_result
    end
  end
end

我相信上面的代码应该可以解决您的问题,但我不能保证。并发编程很难。


进一步阅读:

我建议您阅读并发/多线程编程及其陷阱。网上有很多 Ruby 资源。

由于 Ruby 关于 Mutex 的文档是出了名的糟糕,我会厚颜无耻地在此处插入我自己的文章并建议您阅读它:

https://dev.to/enether/working-with-multithreaded-ruby-part-i-cj3 (“如何保护自己”段落介绍了互斥量)

关于ruby - 2套接字互操作产生 "socket operation on non-socket - ENOTSOCK"错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46750391/

相关文章:

ruby-on-rails - Rake des 不知道如何构建任务 'compile' ,如何跟踪这个错误?

ruby-on-rails - 如何查找两个范围内的共同日期

c - 将数据传输到工作线程的回调或从工作线程的回调传输数据

c# - 如何中断正在运行的线程并使其运行另一个方法?

multithreading - 在ZeroMQ中从多个线程到zmq_poll()一个REP套接字+ send()安全吗?

c++ - 从 linux 套接字读取 "varint"

java - Node.js 套接字 read() 像 Java 一样?

ruby-on-rails - 关于 ruby​​ on rails 的问答游戏

ruby - compass 配置因 Docker 组合失败

javascript - Python 套接字服务器在收到数据后崩溃