解决方案
我刚刚看到httparty,您可以使用:local_port 和:local_host 请求选项:
显然,如果要指定 local_port,则必须指定 local_host,这是一直到 Socket 和事件 connect(2) 的限制
# Get the first local IP address which is not the loopback
# There are far better way of doing this, this is just for the example
addr = Socket.ip_address_list.select(&:ipv4?).detect{|addr| addr.ip_address != '127.0.0.1'}
# Start a connection using a predefined port
HTTParty.get 'http://google.com', local_port: 60000, local_host: addr.ip_address
如果要覆盖本地端口,我们必须同时指定 local_host 和 local_port 的原因是 Socket 使用Addrinfo.getaddrinfo,如果只指定端口,它会返回环回地址。
这是由于getaddrinfo(3):
如果在hints.ai_flags 中未设置AI_PASSIVE 标志,则返回的套接字地址将适合与connect(2)、sendto(2) 或sendmsg(2) 一起使用。如果 node 为 NULL,则网络地址将设置为环回接口地址(INADDR_LOOPBACK 用于 IPv4 地址,IN6ADDR_LOOPBACK_INIT 用于 IPv6 地址);这由打算与在同一主机上运行的对等方通信的应用程序使用。
并且在这种情况下没有设置 AI_PASSIVE,因为我们不想设置bind,而是设置connect。
使用环回地址,外部网络因此无法访问,这也是我们需要指定 local_host 的原因。
原答案
您可以通过首先创建Net::HTTP 实例然后配置local_port(一个R/W 属性)然后开始连接来做到这一点。
如果您使用任何其他方式建立连接,您可能需要查看文档以查看是否有此类方法可用。
http = Net::HTTP.new(address, port)
http.local_port = 666
http.local_host = 'your ip address'
http.start do
# whatever
end
local_port 是一个attr_accessor,@local_port 直接用于打开 TCP 套接字:TCPSocket.open(conn_address, conn_port, @local_host, @local_port)