Ruby Common Network Exception in Ruby (1)

zgm · 2015年08月04日 · 最后由 zgm 回复于 2015年08月06日 · 3590 次阅读

Errno::EHOSTUNREACH

当试图连接一个无法通过 ARP 协议获取 MAC 地址的 IP 地址时抛出该异常.

require 'socket'

begin
  # 假设 192.169.1.100 这个 IP 与请求方在同一子网, 但是该子网内不存在该主机.
  client = TCPSocket.new('192.168.1.100', 80)
rescue => error
  puts error.class
  puts error.message
end

=>

Errno::EHOSTUNREACH
No route to host - connect(2) for "192.168.1.100" port 3000

Errno::ETIMEDOUT

当建立连接时, 请求方由于未收到接收方的 ACK 报文, 经过 N 次超时重传之后抛出该异常.

require 'socket'

begin
  # 已通过 iptables DROP 掉所有到达 3000 端口的 TCP 数据包.
  client = TCPSocket.new('localhost', 3000)
rescue => error
  puts error.class
  puts error.message
end

=>

Errno::ETIMEDOUT
Connection refused - connect(2) for "localhost" port 3000

Errno::ECONNREFUSED

当建立连接时, 接收方对应的端口未开启会传回一个 RST 报文抛出该异常.

require 'socket'

begin
  # 接收方并未开启 3000 端口的服务.
  client = TCPSocket.new('localhost', 3000)
rescue => error
  puts error.class
  puts error.message
end

=>

Errno::ECONNREFUSED
Connection refused - connect(2) for "localhost" port 3000

Errno::EPIPE

当接收方正常关闭连接并发送 FIN 报文后, 如果发送方执行写操作, 则接收方会返回一个 RST 报文, 如果发送方继续执行写操作, 则抛出该异常.

# server.rb

require 'socket'

begin
  server = TCPServer.new('localhost', 3000)

  client = server.accept
  # 让客户端先关闭, 并发送 FIN 报文
  sleep 1
  # 此时客户端发送 RST 报文
  client.write 'hello'
  # 抛出 Error::EPIPE 异常
  client.write 'world'
rescue => error
  puts error.class
  puts error.message
end

=>

Errno::EPIPE
Broken pipe
# client.rb

require 'socket'

begin
  client = TCPSocket.new('localhost', 3000)
  client.close
end

Errno::ECONNRESET

当接收方异常关闭连接并发送 RST 报文后, 如果发送方继续执行读或者写操作, 则抛出该异常.

# server.rb

require 'socket'

begin
  server = TCPServer.new('localhost', 3000)
  client = server.accept
  client.write 'hello'
  # 等待客户端异常退出, 发送 RST 报文
  sleep 2
  # 抛出 Errno::ECONNRESET
  client.write 'world'
rescue => error
  puts error.class
  puts error.message
end

=>

Errno::ECONNRESET
Connection reset by peer
# client.rb

require 'socket'

begin
  client = TCPSocket.new('localhost', 3000)
  # 等待服务端发送数据过来
  sleep 1
  # 由于缓冲区仍有数据, 此时关闭 socket 会导致发送一个 RST 报文到服务端
  client.close
end

原文 http://zhouguangming.me/2015/05/26/common-network-exception-in-ruby(1)

哈哈,我来抢沙发。

请教一个问题

require 'socket'

local_socket = Socket.new(:INET, :STREAM)
local_addr   = Socket.pack_sockaddr_in(4481, '0.0.0.0')
local_socket.bind(local_addr)
server.listen(Socket::SOMAXCONN)

# accept a connection
connection, remote_addr = server.accept

建立连接后,connection 是一个 Socket 对象,instance_variable 是空的,local_address/remote_address 是保存在哪里呢?

> connection.instance_variables
> []

> p connection.local_address
Local address: #<Addrinfo: 0.0.0.0:4481 TCP>

> p connection.remote_address
Remote address #<Addrinfo: 59.102.12.1:4481 TCP>

#2 楼 @xiaoronglv connection.methods

#3 楼 @zgm

我的意思是,这两个方法 local_address/remote_address 是在哪拿的数据呢?

> c.method(:local_address).source_location
nil

是用的 C 的库吗?

需要 登录 后方可回复, 如果你还没有账号请 注册新账号