Socket
Parent:BasicSocket
Class Socket
提供对底层操作系统套接字实现的访问。它可以用来提供比特定于协议的套接字类更多的操作系统特定的功能。
在Socket::Constants下定义的常量也在Socket下定义。例如,Socket::AF_INET可以使用以及Socket::Constants::AF_INET。请参阅Socket::Constants获取常量列表。
什么是套接字?
套接字是双向通信通道的端点。套接字可以在进程内,同一机器上的进程或不同机器之间进行通信。有很多类型的套接字:例如TCPSocket,UDPSocket或UNIXSocket。
套接字有自己的词汇:
域:协议族:
- Socket::PF_INET
- Socket::PF_INET6
- Socket::PF_UNIX
- etc.
键入:典型的两个端点之间的通信类型
- Socket::SOCK_STREAM
- Socket::SOCK_DGRAM.
协议:通常为零。这可以用来识别协议的变体。
主机名:网络接口的标识符:
- 一个字符串(主机名,IPv4或IPv6地址或
broadcast
指定广播地址)
- 一个指定INADDR_ANY的零长度字符串
- 一个整数(按主机字节顺序解释为二进制地址)。
快速启动
许多类,例如TCPSocket,UDPSocket或UNIXSocket,相对于等效的C编程接口,可以更容易地使用套接字。
让我们使用类似C的方式使用IPv4协议创建一个互联网套接字:
require 'socket'
s = Socket.new Socket::AF_INET, Socket::SOCK_STREAM
s.connect Socket.pack_sockaddr_in(80, 'example.com')
你也可以使用TCPSocket类:
s = TCPSocket.new 'example.com', 80
一个简单的服务器可能如下所示:
require 'socket'
server = TCPServer.new 2000 # Server bound to port 2000
loop do
client = server.accept # Wait for a client to connect
client.puts "Hello !"
client.puts "Time is #{Time.now}"
client.close
end
一个简单的客户可能看起来像这样:
require 'socket'
s = TCPSocket.new 'localhost', 2000
while line = s.gets # Read lines from socket
puts line # and print them
end
s.close # close socket when done
异常处理
Ruby的Socket实现基于系统相关实现产生的错误引发异常。这就是为什么这些方法的记录方式是将基于Unix的系统异常从基于Windows的异常中分离出来。如果需要有关特定异常的更多信息,请参阅Unix手册页或Windows WinSock参考。
便利方法
尽管创建套接字的一般方法是:: new,但在大多数情况下,有几种套接字创建方法。
TCP client socket
::tcp, TCPSocket.open
TCP server socket
::tcp_server_loop, TCPServer.open
UNIX client socket
::unix, UNIXSocket.open
UNIX server socket
::unix_server_loop, UNIXServer.open
文档来自
- Zach Dennis
- Sam Roberts
- 从实用书架编程Ruby。
本文档中的许多内容是经过The Pragmatic Bookshelf 编程Ruby的许可获得的。
常量
AF_APPLETALK
AppleTalk协议
AF_ATM
异步传输模式
AF_AX25
AX.25协议
AF_CCITT
CCITT(现在的ITU-T)协议
AF_CHAOS
MIT CHAOS协议
AF_CNT
计算机网络技术
AF_COIP
面向连接的IP
AF_DATAKIT
Datakit协议
AF_DEC
DECnet协议
AF_DLI
DEC直接数据链路接口协议
AF_E164
CCITT(ITU-T)E.164建议
AF_ECMA
欧洲电脑制造商协议
AF_HYLINK
NSC Hyperchannel协议
AF_IMPLINK
ARPANET IMP协议
AF_INET
IPv4协议
AF_INET6
IPv6协议
AF_IPX
IPX协议
AF_ISDN
综合业务数字网络
AF_ISO
ISO开放系统互连协议
AF_LAT
局域传输协议
AF_LINK
链路层接口
AF_LOCAL
主机内部协议
AF_MAX
此平台的最大地址族
AF_NATM
本地ATM访问
AF_NDRV
网络驱动程序原始访问
AF_NETBIOS
NetBIOS
AF_NETGRAPH
Netgraph套接字
AF_NS
XEROX NS协议
AF_OSI
ISO开放系统互连协议
AF_PACKET
直接链接层访问
AF_PPP
点对点协议
AF_PUP
PARC通用分组协议
AF_ROUTE
内部路由协议
AF_SIP
简单的Internet协议
AF_SNA
IBM SNA协议
AF_SYSTEM AF_UNIX
UNIX套接字
AF_UNSPEC
未指定协议,任何受支持的地址系列
AI_ADDRCONFIG
只有在分配了任何地址时才接受
AI_ALL
允许所有地址
AI_CANONNAME
填写规范名称
AI_DEFAULT
getaddrinfo的默认标志
AI_MASK
getaddrinfo的有效标志掩码(不适用于应用程序)
AI_NUMERICHOST
防止主机名称解析
AI_NUMERICSERV
防止服务名称解析
AI_PASSIVE
获取使用bind()的地址
AI_V4MAPPED
接受IPv4映射的IPv6地址
AI_V4MAPPED_CFG
如果内核支持它,则接受IPv4映射地址
EAI_ADDRFAMILY
不支持主机名的地址族
EAI_AGAIN
名称解析中的临时失败
EAI_BADFLAGS
无效的标志
EAI_BADHINTS
提示值无效
EAI_FAIL
不可恢复的名称解析失败
EAI_FAMILY
地址家族不受支持
EAI_MAX
来自getaddrinfo的最大错误代码
EAI_MEMORY
内存分配失败
EAI_NODATA
没有与主机名关联的地址
EAI_NONAME
主机名或服务名称,或未知
EAI_OVERFLOW
参数缓冲区溢出
EAI_PROTOCOL
解决的协议是未知的
EAI_SERVICE
套接字类型不支持Servname
EAI_SOCKTYPE
套接字类型不受支持
EAI_SYSTEM
errno:返回系统错误
IFF_802_1Q_VLAN
802.1Q VLAN设备
IFF_ALLMULTI
接收所有组播数据包
IFF_ALTPHYS
使用备用物理连接
IFF_AUTOMEDIA
自动媒体选择活动
IFF_BONDING
绑定主机或从机
IFF_BRIDGE_PORT
设备用作网桥端口
IFF_BROADCAST
广播地址有效
IFF_CANTCHANGE
标志不可更改
IFF_CANTCONFIG
使用ioctl(2)无法配置
IFF_DEBUG
打开调试
IFF_DISABLE_NETPOLL
在运行时禁用netpoll
IFF_DONT_BRIDGE
不允许桥接此以太网
IFF_DORMANT
使用者信号休眠
IFF_DRV_OACTIVE
tx硬件队列已满
IFF_DRV_RUNNING
资源分配
IFF_DYING
界面正在收敛
IFF_DYNAMIC
具有更改地址的拨号设备
IFF_EBRIDGE
以太网桥接设备
IFF_ECHO
回送发送数据包
IFF_ISATAP
ISATAP interface (RFC4214)
IFF_LINK0
每个链路层定义了位0
IFF_LINK1
每个链路层定义位1
IFF_LINK2
每个链路层定义位2
IFF_LIVE_ADDR_CHANGE
硬件地址在运行时发生变化
IFF_LOOPBACK
回环网
IFF_LOWER_UP
驱动器发出L1信号
IFF_MACVLAN_PORT
设备用作macvlan端口
IFF_MASTER
负载平衡器的主人
IFF_MASTER_8023AD
绑定主机,802.3ad。
IFF_MASTER_ALB
结合主人,平衡alb。
IFF_MASTER_ARPMON
绑定大师,ARP mon在使用中
IFF_MONITOR
用户请求的监视器模式
IFF_MULTICAST
支持多播式
IFF_NOARP
没有地址解析协议
IFF_NOTRAILERS
避免使用拖车设备
IFF_OACTIVE
传输正在进行中
IFF_OVS_DATAPATH
设备用作Open vSwitch数据路径端口
IFF_POINTOPOINT
点对点链接
IFF_PORTSEL
可以设置媒体类型
IFF_PPROMISC
用户请求的promisc模式
IFF_PROMISC
接收所有数据包
IFF_RENAMING
界面正在重命名
IFF_ROUTE
路由条目已安装
IFF_RUNNING
资源分配
IFF_SIMPLEX
无法接收自己的传输
IFF_SLAVE
负载均衡器的从属者
IFF_SLAVE_INACTIVE
bonding slave not the curr. active
IFF_SLAVE_NEEDARP
需要ARPs进行验证
IFF_SMART
接口管理自己的路由
IFF_STATICARP
静态ARP
IFF_SUPP_NOFCS
发送自定义的FCS
IFF_TEAM_PORT
用作团队端口
IFF_TX_SKB_SHARING
在传输上共享skbs
IFF_UNICAST_FLT
单播过滤
IFF_UP
界面已启动
IFF_VOLATILE
易失标志
IFF_WAN_HDLC
WAN HDLC设备
IFF_XMIT_DST_RELEASE
dev_hard_start_xmit()被允许释放skb-> dst
IFNAMSIZ
最大接口名称大小
IF_NAMESIZE
最大接口名称大小
INADDR_ALLHOSTS_GROUP
该子集上所有系统的多播组
INADDR_ANY
绑定到INADDR_ANY的套接字接收来自所有接口的数据包并从默认IP地址发送数据包
INADDR_BROADCAST
网络广播地址
INADDR_LOOPBACK
环回地址
INADDR_MAX_LOCAL_GROUP
最后一个本地网络多播组
INADDR_NONE
用于匹配无效IP地址的位掩码
INADDR_UNSPEC_GROUP
保留的多播组
INET6_ADDRSTRLEN
IPv6地址字符串的最大长度
INET_ADDRSTRLEN
IPv4地址字符串的最大长度
IPPORT_RESERVED
绑定或连接的默认最小地址
IPPORT_USERRESERVED
绑定或连接的默认最大地址
IPPROTO_AH
IP6身份验证标头
IPPROTO_BIP IPPROTO_DSTOPTS
IP6目标选项
IPPROTO_EGP
外部网关协议
IPPROTO_EON
ISO cnlp
IPPROTO_ESP
IP6封装的安全负载
IPPROTO_FRAGMENT
IP6分段头
IPPROTO_GGP
网关协议网关
IPPROTO_HELLO
“hello”路由协议
IPPROTO_HOPOPTS
IP6逐跳选项
IPPROTO_ICMP
控制消息协议
IPPROTO_ICMPV6
ICMP6
IPPROTO_IDP
XNS IDP
IPPROTO_IGMP
组管理协议
IPPROTO_IP
IP虚拟协议
IPPROTO_IPV6
IP6头部
IPPROTO_MAX
最大恒定IPPROTO
IPPROTO_ND
Sun网盘协议
IPPROTO_NONE
IP6没有下一个标题
IPPROTO_PUP
PARC通用分组协议
IPPROTO_RAW
原始IP数据包
IPPROTO_ROUTING
IP6路由头
IPPROTO_TCP
TCP
IPPROTO_TP
ISO传输协议类4
IPPROTO_UDP
UDP
IPPROTO_XTP
Xpress传输协议
IPV6_CHECKSUM
原始套接字的校验和偏移量
IPV6_DONTFRAG
不要分组数据包
IPV6_DSTOPTS
目的地选项
IPV6_HOPLIMIT
跳跃限制
IPV6_HOPOPTS
逐跳选项
IPV6_JOIN_GROUP
加入小组成员资格
IPV6_LEAVE_GROUP
留下组员资格
IPV6_MULTICAST_HOPS
IP6组播跳数
IPV6_MULTICAST_IF
IP6多播接口
IPV6_MULTICAST_LOOP
IP6组播环回
IPV6_NEXTHOP
下一跳地址
IPV6_PATHMTU
检索当前路径MTU
IPV6_PKTINFO
用数据报接收数据包信息
IPV6_RECVDSTOPTS
接收所有IP6选项以进行响应
IPV6_RECVHOPLIMIT
用数据报接收跳数限制
IPV6_RECVHOPOPTS
接收逐跳选项
IPV6_RECVPATHMTU
用数据报接收当前路径MTU
IPV6_RECVPKTINFO
接收目标IP地址和传入界面
IPV6_RECVRTHDR
接收路由头
IPV6_RECVTCLASS
接收流量类别
IPV6_RTHDR
允许删除粘性路由头
IPV6_RTHDRDSTOPTS
允许删除粘性目标选项标题
IPV6_RTHDR_TYPE_0
路由头部类型0
IPV6_TCLASS
指定流量类别
IPV6_UNICAST_HOPS
IP6单播跳数
IPV6_USE_MIN_MTU
使用最小的MTU大小
IPV6_V6ONLY
仅将IPv6绑定到通配符绑定
IPX_TYPE IP_ADD_MEMBERSHIP
添加多播组成员资格
IP_ADD_SOURCE_MEMBERSHIP
添加多播组成员资格
IP_BLOCK_SOURCE
阻止具有给定源地址的IPv4多播数据包
IP_DEFAULT_MULTICAST_LOOP
默认组播环回
IP_DEFAULT_MULTICAST_TTL
Default multicast TTL
IP_DONTFRAG
不要分组数据包
IP_DROP_MEMBERSHIP
删除多播组成员资格
IP_DROP_SOURCE_MEMBERSHIP
删除多播组成员资格
IP_FREEBIND
允许绑定到不存在的IP地址
IP_HDRINCL
标题包含在数据中
IP_IPSEC_POLICY
IPsec安全策略
IP_MAX_MEMBERSHIPS
套接字可以加入的最大组播组数量
IP_MINTTL
允许接收数据包的最小TTL
IP_MSFILTER
多播源过滤
IP_MTU
套接字的最大传输单位
IP_MTU_DISCOVER
MT路径发现
IP_MULTICAST_IF
IP组播接口
IP_MULTICAST_LOOP
IP组播环回
IP_MULTICAST_TTL
IP组播TTL
IP_ONESBCAST
强制传出的广播数据报具有无向广播地址
IP_OPTIONS
IP选项包含在数据包中
IP_PASSSEC
用数据报检索安全上下文
IP_PKTINFO
用数据报接收数据包信息
IP_PKTOPTIONS
用数据报接收数据包选项
IP_PMTUDISC_DO
始终发送DF帧
IP_PMTUDISC_DONT
永远不要发送DF帧
IP_PMTUDISC_WANT
使用每条路线提示
IP_PORTRANGE
为未指定端口号的套接字设置端口范围
IP_RECVDSTADDR
用数据报接收IP目标地址
IP_RECVERR
启用扩展可靠的错误消息传递
IP_RECVIF
用数据报接收接口信息
IP_RECVOPTS
用数据报接收所有IP选项
IP_RECVRETOPTS
接收所有IP选项以进行响应
IP_RECVSLLA
用数据报接收链路层地址
IP_RECVTOS
接收传入数据包的TOS
IP_RECVTTL
用数据报接收IP TTL
IP_RETOPTS
IP选项包含在数据报中
IP_ROUTER_ALERT
通知转接路由器更仔细地检查IP数据包的内容
IP_SENDSRCADDR
传出UDP数据报的源地址
IP_TOS
IP服务类型
IP_TRANSPARENT
透明代理
IP_TTL
IP生存时间
IP_UNBLOCK_SOURCE
使用给定源地址取消阻止IPv4组播数据包
IP_XFRM_POLICY LOCAL_CONNWAIT
连接块直到被接受
LOCAL_CREDS
将凭据传递给接收方
LOCAL_PEERCRED
检索对等证书
MCAST_BLOCK_SOURCE
阻止来自此源的多播数据包
MCAST_EXCLUDE
独有的组播源过滤器
MCAST_INCLUDE
包含多播源过滤器
MCAST_JOIN_GROUP
加入一个多播组
MCAST_JOIN_SOURCE_GROUP
加入一个组播源组
MCAST_LEAVE_GROUP
保留一个多播组
MCAST_LEAVE_SOURCE_GROUP
保留多播源组
MCAST_MSFILTER
多播源过滤
MCAST_UNBLOCK_SOURCE
取消阻止来自此源的组播数据包
MSG_COMPAT
记录结束
MSG_CONFIRM
确认路径有效性
MSG_CTRUNC
控制数据在交付之前丢失
MSG_DONTROUTE
发送时不使用路由表
MSG_DONTWAIT
该消息应该是非阻塞的
MSG_EOF
数据完成连接
MSG_EOR
数据完成记录
MSG_ERRQUEUE
从错误队列获取消息
MSG_FASTOPEN
减少握手过程的步骤
MSG_FIN MSG_FLUSH
开始保留序列。转储到so_temp
MSG_HAVEMORE
数据准备好被读取
MSG_HOLD
在so_temp中保存片段
MSG_MORE
发件人将发送更多
MSG_NOSIGNAL
不要生成SIGPIPE
MSG_OOB
处理带外数据
MSG_PEEK
查看收到的消息
MSG_PROXY
等待完整的请求
MSG_RCVMORE
数据保留在当前数据包中
MSG_RST MSG_SEND
在so_temp中发送数据包
MSG_SYN MSG_TRUNC
交货前丢弃数据
MSG_WAITALL
等待完整的请求或错误
NI_DGRAM
指定的服务是数据报服务(查找UDP端口)
NI_MAXHOST
主机名的最大长度
NI_MAXSERV
服务名称的最大长度
NI_NAMEREQD
名字是必需的
NI_NOFQDN
本地主机不需要FQDN,只返回本地部分
NI_NUMERICHOST
返回一个数字地址
NI_NUMERICSERV
将服务名称作为数字字符串返回
PF_APPLETALK
AppleTalk协议
PF_ATM
异步传输模式
PF_AX25
AX.25 protocol
PF_CCITT
CCITT(现在的ITU-T)协议
PF_CHAOS
MIT CHAOS协议
PF_CNT
计算机网络技术
PF_COIP
面向连接的IP
PF_DATAKIT
Datakit协议
PF_DEC
DECnet协议
PF_DLI
DEC直接数据链路接口协议
PF_ECMA
欧洲电脑制造商协议
PF_HYLINK
NSC Hyperchannel协议
PF_IMPLINK
ARPANET IMP协议
PF_INET
IPv4协议
PF_INET6
IPv6协议
PF_IPX
IPX协议
PF_ISDN
综合业务数字网络
PF_ISO
ISO开放系统互连协议
PF_KEY PF_LAT
局域传输协议
PF_LINK
链路层接口
PF_LOCAL
主机内部协议
PF_MAX
此平台的最大地址族
PF_NATM
本地ATM访问
PF_NDRV
网络驱动程序原始访问
PF_NETBIOS
NetBIOS
PF_NETGRAPH
Netgraph套接字
PF_NS
XEROX NS协议
PF_OSI
ISO开放系统互连协议
PF_PACKET
直接链接层访问
PF_PIP PF_PPP
点对点协议
PF_PUP
PARC通用分组协议
PF_ROUTE
内部路由协议
PF_RTIP PF_SIP
简单的Internet协议
PF_SNA
IBM SNA协议
PF_SYSTEM PF_UNIX
UNIX套接字
PF_UNSPEC
未指定协议,任何受支持的地址系列
PF_XTP
eXpress传输协议
SCM_BINTIME
时间戳(二进制时间)
SCM_CREDENTIALS
发件人的凭据
SCM_CREDS
流程凭证
SCM_RIGHTS
访问权
SCM_TIMESTAMP
时间戳(timeval)
SCM_TIMESTAMPING
时间戳(timespec list)(Linux 2.6.30)
SCM_TIMESTAMPNS
Timespec (timespec)
SCM_UCRED
用户凭据
SCM_WIFI_STATUS
Wifi status (Linux 3.3)
SHUT_RD
关闭套接字的读取侧
SHUT_RDWR
关闭套接字的两侧
SHUT_WR
关闭套接字的写入侧
SOCK_DGRAM
数据报套接字提供无连接,不可靠的消息
SOCK_PACKET
设备级数据包访问
SOCK_RAW
原始套接字为直接访问或实现网络协议提供低级访问
SOCK_RDM
可靠的数据报套接字提供可靠的消息传递
SOCK_SEQPACKET
顺序数据包套接字为数据报提供顺序,可靠的双向连接
SOCK_STREAM
流套接字为字节流提供有序的,可靠的双向连接
SOL_ATALK
AppleTalk套接字选项
SOL_AX25
AX.25插座选项
SOL_IP
IP套接字选项
SOL_IPX
IPX套接字选项
SOL_SOCKET
套接字级选项
SOL_TCP
TCP套接字选项
SOL_UDP
UDP套接字选项
SOMAXCONN
可能为套接字排队的最大连接请求
SOPRI_BACKGROUND
后台套接字优先
SOPRI_INTERACTIVE
交互式套接字优先
SOPRI_NORMAL
正常的套接字优先
SO_ACCEPTCONN
Socket已经调用了listen()
SO_ACCEPTFILTER
有一个接受过滤器
SO_ALLZONES
绕过区域边界
SO_ATTACH_FILTER
附加接受过滤器
SO_BINDTODEVICE
只从给定接口发送数据包
SO_BINTIME
接收数据报的时间戳(bintime)
SO_BPF_EXTENSIONS
支持查询的BPF扩展(Linux 3.14)
SO_BROADCAST
允许发送广播消息
SO_BUSY_POLL
为低延迟轮询设置阈值(微秒)(Linux 3.11)
SO_DEBUG
调试信息记录
SO_DETACH_FILTER
分离接受过滤器
SO_DOMAIN
给出的socket()(Linux 2.6.32)
SO_DONTROUTE
使用接口地址
SO_DONTTRUNC
保留未读数据
SO_ERROR
获取并清除错误状态
SO_GET_FILTER
获取由SO_ATTACH_FILTER设置的过滤器(Linux 3.8)
SO_KEEPALIVE
保持连接活着
SO_LINGER
如果数据存在,则关闭
SO_LOCK_FILTER
锁定连接到插座的过滤器(Linux 3.9)
SO_MAC_EXEMPT
未标记同行的强制访问控制豁免
SO_MARK
设置标记路由标记(Linux 2.6.25)
SO_MAX_PACING_RATE
限制传输层计算的速率。每秒字节数
SO_NKE
安装套接字级网络内核扩展
SO_NOFCS
设置套接字的netns(Linux 3.4)
SO_NOSIGPIPE
不要在EPIPE上SIGPIPE
SO_NO_CHECK
禁用校验和
SO_NREAD
获取第一个数据包字节数
SO_OOBINLINE
在线接收收到的带外数据
SO_PASSCRED
接收SCM_CREDENTIALS消息
SO_PASSSEC
切换安全上下文传递(Linux 2.6.18)
SO_PEEK_OFF
设置窥视偏移量(Linux 3.4)
SO_PEERCRED
连接到此套接字的外部进程的凭据
SO_PEERNAME
连接用户的名称
SO_PEERSEC
获取安全凭证(Linux 2.6.2)
SO_PRIORITY
此套接字上所有数据包的协议定义优先级
SO_PROTOCOL
给出的socket()(Linux 2.6.32)
SO_RCVBUF
接收缓冲区大小
SO_RCVBUFFORCE
接收缓冲区大小,无rmem_max限制(Linux 2.6.14)
SO_RCVLOWAT
接收低水位标志
SO_RCVTIMEO
接收超时
SO_RECVUCRED
用数据报接收用户证书
SO_REUSEADDR
允许本地地址重用
SO_REUSEPORT
允许本地地址和端口重用
SO_RXQ_OVFL
切换cmsg丢弃的数据包数量(Linux 2.6.33)
SO_SECURITY_AUTHENTICATION SO_SECURITY_ENCRYPTION_NETWORK SO_SECURITY_ENCRYPTION_TRANSPORT SO_SELECT_ERR_QUEUE
使用select选择()检测套接字错误队列(Linux 3.10)
SO_SNDBUF
发送缓冲区大小
SO_SNDBUFFORCE
发送无wmem_max限制的缓冲区大小(Linux 2.6.14)
SO_SNDLOWAT
发送低水位标志
SO_SNDTIMEO
发送超时
SO_TIMESTAMP
接收数据报的时间戳(timeval)
SO_TIMESTAMPING
传入和传出数据包的时间标记(Linux 2.6.30)
SO_TIMESTAMPNS
接收数据报的纳秒时间戳(timespec)
SO_TYPE
获取套接字类型
SO_USELOOPBACK
尽可能旁路硬件
SO_WANTMORE
在更多数据准备就绪时给出提示
SO_WANTOOBFLAG
在接收MSG_FLAG时需要OOB数据
SO_WIFI_STATUS
切换cmsg为wifi状态(Linux 3.3)
TCP_CONGESTION
TCP拥塞控制算法(Linux 2.6.13,glibc 2.6)
TCP_COOKIE_TRANSACTIONS
TCP Cookie事务(Linux 2.6.33,glibc 2.18)
TCP_CORK
不要发送部分帧(Linux 2.2,glibc 2.2)
TCP_DEFER_ACCEPT
数据准备就绪之前不要通知监听套接字(Linux 2.4,glibc 2.2)
TCP_FASTOPEN
减少握手过程的步骤(Linux 3.7,glibc 2.18)
TCP_INFO
检索有关此套接字的信息(Linux 2.4,glibc 2.2)
TCP_KEEPCNT
丢弃连接前允许的最大Keepalive探测数(Linux 2.4,glibc 2.2)
TCP_KEEPIDLE
Keepalive探测器发送前的空闲时间(Linux 2.4,glibc 2.2)
TCP_KEEPINTVL
Keepalive探测器之间的时间间隔(Linux 2.4,glibc 2.2)
TCP_LINGER2
孤儿FIN_WAIT2套接字的生命周期(Linux 2.4,glibc 2.2)
TCP_MAXSEG
设置最大片段大小
TCP_MD5SIG
使用MD5摘要(RFC2385,Linux 2.6.20,glibc 2.7)
TCP_NODELAY
不要延迟发送来合并数据包
TCP_NOOPT
不要使用TCP选项
TCP_NOPUSH
不要推最后一块写
TCP_QUEUE_SEQ
修复模式的队列顺序(Linux 3.5,glibc 2.18)
TCP_QUICKACK
启用quickack模式(Linux 2.4.4,glibc 2.3)
TCP_REPAIR
修复模式(Linux 3.5,glibc 2.18)
TCP_REPAIR_OPTIONS
修复模式选项(Linux 3.5,glibc 2.18)
TCP_REPAIR_QUEUE
队列修复模式(Linux 3.5,glibc 2.18)
TCP_SYNCNT
连接丢失前的SYN重传次数(Linux 2.4,glibc 2.2)
TCP_THIN_DUPACK
针对瘦流量少的重复确认处理(Linux 2.6.34,glibc 2.18)
TCP_THIN_LINEAR_TIMEOUTS
少流量的线性超时(Linux 2.6.34,glibc 2.18)
TCP_TIMESTAMP
TCP timestamp (Linux 3.9, glibc 2.18)
TCP_USER_TIMEOUT
TCP连接中断前的最大超时(Linux 2.6.37,glibc 2.18)
TCP_WINDOW_CLAMP
限制广告窗口的大小(Linux 2.4,glibc 2.2)
UDP_CORK
不要发送部分帧(Linux 2.5.44,glibc 2.11)
公共类方法
accept_loop(*sockets) { |socket, client_addrinfo| ... } Show source
为每个通过给定套接字接受的连接生成套接字和客户端地址。
参数是套接字列表。单个参数应该是套接字或套接字数组。
该方法依次生成块。这意味着下一个连接在块返回之前不被接受。因此,并发机制(例如线程)应该一次用于为多个客户端提供服务。
# File ext/socket/lib/socket.rb, line 784
def self.accept_loop(*sockets) # :yield: socket, client_addrinfo
sockets.flatten!(1)
if sockets.empty?
raise ArgumentError, "no sockets"
end
loop {
readable, _, _ = IO.select(sockets)
readable.each {|r|
sock, addr = r.accept_nonblock(exception: false)
next if sock == :wait_readable
yield sock, addr
}
}
end
getaddrinfo(nodename, servname[, family[, socktype[, protocol[, flags, reverse_lookup]]]]) → array Show source
获取nodename:servname的地址信息。
家庭应该是一个地址族,例如:INET,:INET6等。
socktype应该是一个套接字类型,例如::STREAM,:DGRAM,:RAW等。
协议应该是家族中定义的协议,并且该家族默认为0。
标志应该是Socket :: AI_ *常量的按位或。
Socket.getaddrinfo("www.ruby-lang.org", "http", nil, :STREAM)
#=> [["AF_INET", 80, "carbon.ruby-lang.org", "221.186.184.68", 2, 1, 6]] # PF_INET/SOCK_STREAM/IPPROTO_TCP
Socket.getaddrinfo("localhost", nil)
#=> [["AF_INET", 0, "localhost", "127.0.0.1", 2, 1, 6], # PF_INET/SOCK_STREAM/IPPROTO_TCP
# ["AF_INET", 0, "localhost", "127.0.0.1", 2, 2, 17], # PF_INET/SOCK_DGRAM/IPPROTO_UDP
# ["AF_INET", 0, "localhost", "127.0.0.1", 2, 3, 0]] # PF_INET/SOCK_RAW/IPPROTO_IP
reverse_lookup指示第三个元素的形式,并且必须是下面的一个。如果省略reverse_lookup,则默认值为nil
。
+true+, +:hostname+: hostname is obtained from numeric address using reverse lookup, which may take a time.
+false+, +:numeric+: hostname is same as numeric address.
+nil+: obey to the current +do_not_reverse_lookup+ flag.
如果Addrinfo对象是首选的,请使用Addrinfo.getaddrinfo。
static VALUE
sock_s_getaddrinfo(int argc, VALUE *argv)
{
VALUE host, port, family, socktype, protocol, flags, ret, revlookup;
struct addrinfo hints;
struct rb_addrinfo *res;
int norevlookup;
rb_scan_args(argc, argv, "25", &host, &port, &family, &socktype, &protocol, &flags, &revlookup);
MEMZERO(&hints, struct addrinfo, 1);
hints.ai_family = NIL_P(family) ? PF_UNSPEC : rsock_family_arg(family);
if (!NIL_P(socktype)) {
hints.ai_socktype = rsock_socktype_arg(socktype);
}
if (!NIL_P(protocol)) {
hints.ai_protocol = NUM2INT(protocol);
}
if (!NIL_P(flags)) {
hints.ai_flags = NUM2INT(flags);
}
if (NIL_P(revlookup) || !rsock_revlookup_flag(revlookup, &norevlookup)) {
norevlookup = rsock_do_not_reverse_lookup;
}
res = rsock_getaddrinfo(host, port, &hints, 0);
ret = make_addrinfo(res, norevlookup);
rb_freeaddrinfo(res);
return ret;
}
gethostbyaddr(address_string , address_family) → hostent Show source
获取地址的主机信息。
p Socket.gethostbyaddr([221,186,184,68].pack("CCCC"))
#=> ["carbon.ruby-lang.org", [], 2, "\xDD\xBA\xB8D"]
static VALUE
sock_s_gethostbyaddr(int argc, VALUE *argv)
{
VALUE addr, family;
struct hostent *h;
char **pch;
VALUE ary, names;
int t = AF_INET;
rb_scan_args(argc, argv, "11", &addr, &family);
StringValue(addr);
if (!NIL_P(family)) {
t = rsock_family_arg(family);
}
#ifdef AF_INET6
else if (RSTRING_LEN(addr) == 16) {
t = AF_INET6;
}
#endif
h = gethostbyaddr(RSTRING_PTR(addr), RSTRING_SOCKLEN(addr), t);
if (h == NULL) {
#ifdef HAVE_HSTRERROR
extern int h_errno;
rb_raise(rb_eSocket, "%s", (char*)hstrerror(h_errno));
#else
rb_raise(rb_eSocket, "host not found");
#endif
}
ary = rb_ary_new();
rb_ary_push(ary, rb_str_new2(h->h_name));
names = rb_ary_new();
rb_ary_push(ary, names);
if (h->h_aliases != NULL) {
for (pch = h->h_aliases; *pch; pch++) {
rb_ary_push(names, rb_str_new2(*pch));
}
}
rb_ary_push(ary, INT2NUM(h->h_addrtype));
#ifdef h_addr
for (pch = h->h_addr_list; *pch; pch++) {
rb_ary_push(ary, rb_str_new(*pch, h->h_length));
}
#else
rb_ary_push(ary, rb_str_new(h->h_addr, h->h_length));
#endif
return ary;
}
gethostbyname(hostname) → official_hostname, alias_hostnames, address_family, *address_list()
获取主机名的主机信息。
p Socket.gethostbyname("hal") #=> ["localhost", ["hal"], 2, "\x7F\x00\x00\x01"]
static VALUE
sock_s_gethostbyname(VALUE obj, VALUE host)
{
struct rb_addrinfo *res =
rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, AI_CANONNAME);
return rsock_make_hostent(host, res, sock_sockaddr);
}
gethostname → hostname Show source
返回主机名。
p Socket.gethostname #=> "hal"
请注意,不能保证能够使用gethostbyname,getaddrinfo等转换为IP地址。如果您需要本地IP地址,请使用:: ip_address_list。
static VALUE
sock_gethostname(VALUE obj)
{
#if defined(NI_MAXHOST)
# define RUBY_MAX_HOST_NAME_LEN NI_MAXHOST
#elif defined(HOST_NAME_MAX)
# define RUBY_MAX_HOST_NAME_LEN HOST_NAME_MAX
#else
# define RUBY_MAX_HOST_NAME_LEN 1024
#endif
long len = RUBY_MAX_HOST_NAME_LEN;
VALUE name;
name = rb_str_new(0, len);
while (gethostname(RSTRING_PTR(name), len) < 0) {
int e = errno;
switch (e) {
case ENAMETOOLONG:
#ifdef __linux__
case EINVAL:
/* glibc before version 2.1 uses EINVAL instead of ENAMETOOLONG */
#endif
break;
default:
rb_syserr_fail(e, "gethostname(3)");
}
rb_str_modify_expand(name, len);
len += len;
}
rb_str_resize(name, strlen(RSTRING_PTR(name)));
return name;
}
getifaddrs → ifaddr1, ...()
返回一组接口地址。数组的一个元素是Socket :: Ifaddr的一个实例。
该方法可用于查找启用多播的接口:
pp Socket.getifaddrs.reject {|ifaddr|
!ifaddr.addr.ip? || (ifaddr.flags & Socket::IFF_MULTICAST == 0)
}.map {|ifaddr| [ifaddr.name, ifaddr.ifindex, ifaddr.addr] }
#=> [["eth0", 2, #<Addrinfo: 221.186.184.67>],
# ["eth0", 2, #<Addrinfo: fe80::216:3eff:fe95:88bb%eth0>]]
GNU / Linux上的示例结果:
pp Socket.getifaddrs
#=> [#<Socket::Ifaddr lo UP,LOOPBACK,RUNNING,0x10000 PACKET[protocol=0 lo hatype=772 HOST hwaddr=00:00:00:00:00:00]>,
# #<Socket::Ifaddr eth0 UP,BROADCAST,RUNNING,MULTICAST,0x10000 PACKET[protocol=0 eth0 hatype=1 HOST hwaddr=00:16:3e:95:88:bb] broadcast=PACKET[protocol=0 eth0 hatype=1 HOST hwaddr=ff:ff:ff:ff:ff:ff]>,
# #<Socket::Ifaddr sit0 NOARP PACKET[protocol=0 sit0 hatype=776 HOST hwaddr=00:00:00:00]>,
# #<Socket::Ifaddr lo UP,LOOPBACK,RUNNING,0x10000 127.0.0.1 netmask=255.0.0.0>,
# #<Socket::Ifaddr eth0 UP,BROADCAST,RUNNING,MULTICAST,0x10000 221.186.184.67 netmask=255.255.255.240 broadcast=221.186.184.79>,
# #<Socket::Ifaddr lo UP,LOOPBACK,RUNNING,0x10000 ::1 netmask=ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff>,
# #<Socket::Ifaddr eth0 UP,BROADCAST,RUNNING,MULTICAST,0x10000 fe80::216:3eff:fe95:88bb%eth0 netmask=ffff:ffff:ffff:ffff::>]
FreeBSD上的示例结果:
pp Socket.getifaddrs
#=> [#<Socket::Ifaddr usbus0 UP,0x10000 LINK[usbus0]>,
# #<Socket::Ifaddr re0 UP,BROADCAST,RUNNING,MULTICAST,0x800 LINK[re0 3a:d0:40:9a:fe:e8]>,
# #<Socket::Ifaddr re0 UP,BROADCAST,RUNNING,MULTICAST,0x800 10.250.10.18 netmask=255.255.255.? (7 bytes for 16 bytes sockaddr_in) broadcast=10.250.10.255>,
# #<Socket::Ifaddr re0 UP,BROADCAST,RUNNING,MULTICAST,0x800 fe80:2::38d0:40ff:fe9a:fee8 netmask=ffff:ffff:ffff:ffff::>,
# #<Socket::Ifaddr re0 UP,BROADCAST,RUNNING,MULTICAST,0x800 2001:2e8:408:10::12 netmask=UNSPEC>,
# #<Socket::Ifaddr plip0 POINTOPOINT,MULTICAST,0x800 LINK[plip0]>,
# #<Socket::Ifaddr lo0 UP,LOOPBACK,RUNNING,MULTICAST LINK[lo0]>,
# #<Socket::Ifaddr lo0 UP,LOOPBACK,RUNNING,MULTICAST ::1 netmask=ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff>,
# #<Socket::Ifaddr lo0 UP,LOOPBACK,RUNNING,MULTICAST fe80:4::1 netmask=ffff:ffff:ffff:ffff::>,
# #<Socket::Ifaddr lo0 UP,LOOPBACK,RUNNING,MULTICAST 127.0.0.1 netmask=255.?.?.? (5 bytes for 16 bytes sockaddr_in)>]
static VALUE
socket_s_getifaddrs(VALUE self)
{
return rsock_getifaddrs();
}
getnameinfo(sockaddr , flags) → hostname, servicename()
获取sockaddr的名称信息。
sockaddr应该是以下之一。
- 打包的sockaddr字符串,例如:: sockaddr_in(80,“127.0.0.1”)
- 3-elements array such as “AF_INET”, 80, “127.0.0.1”
- 4个元素的数组,例如[“AF_INET”,80,忽略,“127.0.0.1”]
标志应该是Socket :: NI_ *常量的按位OR。
注意:最后一种形式与IPSocket#addr和IPSocket#peeraddr兼容。
Socket.getnameinfo(Socket.sockaddr_in(80, "127.0.0.1")) #=> ["localhost", "www"]
Socket.getnameinfo(["AF_INET", 80, "127.0.0.1"]) #=> ["localhost", "www"]
Socket.getnameinfo(["AF_INET", 80, "localhost", "127.0.0.1"]) #=> ["localhost", "www"]
如果Addrinfo对象是首选的,请使用Addrinfo#getnameinfo。
Socket.getservbyname("smtp") #=> 25
Socket.getservbyname("shell") #=> 514
Socket.getservbyname("syslog", "udp") #=> 514
static VALUE
sock_s_getservbyname(int argc, VALUE *argv)
{
VALUE service, proto;
struct servent *sp;
long port;
const char *servicename, *protoname = "tcp";
rb_scan_args(argc, argv, "11", &service, &proto);
StringValue(service);
if (!NIL_P(proto)) StringValue(proto);
servicename = StringValueCStr(service);
if (!NIL_P(proto)) protoname = StringValueCStr(proto);
sp = getservbyname(servicename, protoname);
if (sp) {
port = ntohs(sp->s_port);
}
else {
char *end;
port = STRTOUL(servicename, &end, 0);
if (*end != '\0') {
rb_raise(rb_eSocket, "no such service %s/%s", servicename, protoname);
}
}
return INT2FIX(port);
}
getservbyport(port [, protocol_name]) => service
获得一个端口号端口。
如果没有给出protocol_name,则假定为“tcp”。
Socket.getservbyport(80) #=> "www"
Socket.getservbyport(514, "tcp") #=> "shell"
Socket.getservbyport(514, "udp") #=> "syslog"
static VALUE
sock_s_getservbyport(int argc, VALUE *argv)
{
VALUE port, proto;
struct servent *sp;
long portnum;
const char *protoname = "tcp";
rb_scan_args(argc, argv, "11", &port, &proto);
portnum = NUM2LONG(port);
if (portnum != (uint16_t)portnum) {
const char *s = portnum > 0 ? "big" : "small";
rb_raise(rb_eRangeError, "integer %ld too %s to convert into `int16_t'", portnum, s);
}
if (!NIL_P(proto)) protoname = StringValueCStr(proto);
sp = getservbyport((int)htons((uint16_t)portnum), protoname);
if (!sp) {
rb_raise(rb_eSocket, "no such service for port %d/%s", (int)portnum, protoname);
}
return rb_tainted_str_new2(sp->s_name);
}
ip_address_list => array
以数组形式返回本地IP地址。
该数组包含Addrinfo对象。
pp Socket.ip_address_list
#=> [#<Addrinfo: 127.0.0.1>,
#<Addrinfo: 192.168.0.128>,
#<Addrinfo: ::1>,
...]
static VALUE
socket_s_ip_address_list(VALUE self)
{
#if defined(HAVE_GETIFADDRS)
struct ifaddrs *ifp = NULL;
struct ifaddrs *p;
int ret;
VALUE list;
ret = getifaddrs(&ifp);
if (ret == -1) {
rb_sys_fail("getifaddrs");
}
list = rb_ary_new();
for (p = ifp; p; p = p->ifa_next) {
if (p->ifa_addr != NULL && IS_IP_FAMILY(p->ifa_addr->sa_family)) {
struct sockaddr *addr = p->ifa_addr;
#if defined(AF_INET6) && defined(__sun)
/*
* OpenIndiana SunOS 5.11 getifaddrs() returns IPv6 link local
* address with sin6_scope_id == 0.
* So fill it from the interface name (ifa_name).
*/
struct sockaddr_in6 addr6;
if (addr->sa_family == AF_INET6) {
socklen_t len = (socklen_t)sizeof(struct sockaddr_in6);
memcpy(&addr6, addr, len);
addr = (struct sockaddr *)&addr6;
if (IN6_IS_ADDR_LINKLOCAL(&addr6.sin6_addr) &&
addr6.sin6_scope_id == 0) {
unsigned int ifindex = if_nametoindex(p->ifa_name);
if (ifindex != 0) {
addr6.sin6_scope_id = ifindex;
}
}
}
#endif
rb_ary_push(list, sockaddr_obj(addr, sockaddr_len(addr)));
}
}
freeifaddrs(ifp);
return list;
#elif defined(SIOCGLIFCONF) && defined(SIOCGLIFNUM) && !defined(__hpux)
/* Solaris if_tcp(7P) */
/* HP-UX has SIOCGLIFCONF too. But it uses different struct */
int fd = -1;
int ret;
struct lifnum ln;
struct lifconf lc;
const char *reason = NULL;
int save_errno;
int i;
VALUE list = Qnil;
lc.lifc_buf = NULL;
fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd == -1)
rb_sys_fail("socket(2)");
memset(&ln, 0, sizeof(ln));
ln.lifn_family = AF_UNSPEC;
ret = ioctl(fd, SIOCGLIFNUM, &ln);
if (ret == -1) {
reason = "SIOCGLIFNUM";
goto finish;
}
memset(&lc, 0, sizeof(lc));
lc.lifc_family = AF_UNSPEC;
lc.lifc_flags = 0;
lc.lifc_len = sizeof(struct lifreq) * ln.lifn_count;
lc.lifc_req = xmalloc(lc.lifc_len);
ret = ioctl(fd, SIOCGLIFCONF, &lc);
if (ret == -1) {
reason = "SIOCGLIFCONF";
goto finish;
}
list = rb_ary_new();
for (i = 0; i < ln.lifn_count; i++) {
struct lifreq *req = &lc.lifc_req[i];
if (IS_IP_FAMILY(req->lifr_addr.ss_family)) {
if (req->lifr_addr.ss_family == AF_INET6 &&
IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)(&req->lifr_addr))->sin6_addr) &&
((struct sockaddr_in6 *)(&req->lifr_addr))->sin6_scope_id == 0) {
struct lifreq req2;
memcpy(req2.lifr_name, req->lifr_name, LIFNAMSIZ);
ret = ioctl(fd, SIOCGLIFINDEX, &req2);
if (ret == -1) {
reason = "SIOCGLIFINDEX";
goto finish;
}
((struct sockaddr_in6 *)(&req->lifr_addr))->sin6_scope_id = req2.lifr_index;
}
rb_ary_push(list, sockaddr_obj((struct sockaddr *)&req->lifr_addr, req->lifr_addrlen));
}
}
finish:
save_errno = errno;
if (lc.lifc_buf != NULL)
xfree(lc.lifc_req);
if (fd != -1)
close(fd);
errno = save_errno;
if (reason)
rb_syserr_fail(save_errno, reason);
return list;
#elif defined(SIOCGIFCONF)
int fd = -1;
int ret;
#define EXTRA_SPACE ((int)(sizeof(struct ifconf) + sizeof(union_sockaddr)))
char initbuf[4096+EXTRA_SPACE];
char *buf = initbuf;
int bufsize;
struct ifconf conf;
struct ifreq *req;
VALUE list = Qnil;
const char *reason = NULL;
int save_errno;
fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd == -1)
rb_sys_fail("socket(2)");
bufsize = sizeof(initbuf);
buf = initbuf;
retry:
conf.ifc_len = bufsize;
conf.ifc_req = (struct ifreq *)buf;
/* fprintf(stderr, "bufsize: %d\n", bufsize); */
ret = ioctl(fd, SIOCGIFCONF, &conf);
if (ret == -1) {
reason = "SIOCGIFCONF";
goto finish;
}
/* fprintf(stderr, "conf.ifc_len: %d\n", conf.ifc_len); */
if (bufsize - EXTRA_SPACE < conf.ifc_len) {
if (bufsize < conf.ifc_len) {
/* NetBSD returns required size for all interfaces. */
bufsize = conf.ifc_len + EXTRA_SPACE;
}
else {
bufsize = bufsize << 1;
}
if (buf == initbuf)
buf = NULL;
buf = xrealloc(buf, bufsize);
goto retry;
}
close(fd);
fd = -1;
list = rb_ary_new();
req = conf.ifc_req;
while ((char*)req < (char*)conf.ifc_req + conf.ifc_len) {
struct sockaddr *addr = &req->ifr_addr;
if (IS_IP_FAMILY(addr->sa_family)) {
rb_ary_push(list, sockaddr_obj(addr, sockaddr_len(addr)));
}
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
# ifndef _SIZEOF_ADDR_IFREQ
# define _SIZEOF_ADDR_IFREQ(r) \
(sizeof(struct ifreq) + \
(sizeof(struct sockaddr) < (r).ifr_addr.sa_len ? \
(r).ifr_addr.sa_len - sizeof(struct sockaddr) : \
0))
# endif
req = (struct ifreq *)((char*)req + _SIZEOF_ADDR_IFREQ(*req));
#else
req = (struct ifreq *)((char*)req + sizeof(struct ifreq));
#endif
}
finish:
save_errno = errno;
if (buf != initbuf)
xfree(buf);
if (fd != -1)
close(fd);
errno = save_errno;
if (reason)
rb_syserr_fail(save_errno, reason);
return list;
#undef EXTRA_SPACE
#elif defined(_WIN32)
typedef struct ip_adapter_unicast_address_st {
unsigned LONG_LONG dummy0;
struct ip_adapter_unicast_address_st *Next;
struct {
struct sockaddr *lpSockaddr;
int iSockaddrLength;
} Address;
int dummy1;
int dummy2;
int dummy3;
long dummy4;
long dummy5;
long dummy6;
} ip_adapter_unicast_address_t;
typedef struct ip_adapter_anycast_address_st {
unsigned LONG_LONG dummy0;
struct ip_adapter_anycast_address_st *Next;
struct {
struct sockaddr *lpSockaddr;
int iSockaddrLength;
} Address;
} ip_adapter_anycast_address_t;
typedef struct ip_adapter_addresses_st {
unsigned LONG_LONG dummy0;
struct ip_adapter_addresses_st *Next;
void *dummy1;
ip_adapter_unicast_address_t *FirstUnicastAddress;
ip_adapter_anycast_address_t *FirstAnycastAddress;
void *dummy2;
void *dummy3;
void *dummy4;
void *dummy5;
void *dummy6;
BYTE dummy7[8];
DWORD dummy8;
DWORD dummy9;
DWORD dummy10;
DWORD IfType;
int OperStatus;
DWORD dummy12;
DWORD dummy13[16];
void *dummy14;
} ip_adapter_addresses_t;
typedef ULONG (WINAPI *GetAdaptersAddresses_t)(ULONG, ULONG, PVOID, ip_adapter_addresses_t *, PULONG);
HMODULE h;
GetAdaptersAddresses_t pGetAdaptersAddresses;
ULONG len;
DWORD ret;
ip_adapter_addresses_t *adapters;
VALUE list;
h = LoadLibrary("iphlpapi.dll");
if (!h)
rb_notimplement();
pGetAdaptersAddresses = (GetAdaptersAddresses_t)GetProcAddress(h, "GetAdaptersAddresses");
if (!pGetAdaptersAddresses) {
FreeLibrary(h);
rb_notimplement();
}
ret = pGetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, &len);
if (ret != ERROR_SUCCESS && ret != ERROR_BUFFER_OVERFLOW) {
errno = rb_w32_map_errno(ret);
FreeLibrary(h);
rb_sys_fail("GetAdaptersAddresses");
}
adapters = (ip_adapter_addresses_t *)ALLOCA_N(BYTE, len);
ret = pGetAdaptersAddresses(AF_UNSPEC, 0, NULL, adapters, &len);
if (ret != ERROR_SUCCESS) {
errno = rb_w32_map_errno(ret);
FreeLibrary(h);
rb_sys_fail("GetAdaptersAddresses");
}
list = rb_ary_new();
for (; adapters; adapters = adapters->Next) {
ip_adapter_unicast_address_t *uni;
ip_adapter_anycast_address_t *any;
if (adapters->OperStatus != 1) /* 1 means IfOperStatusUp */
continue;
for (uni = adapters->FirstUnicastAddress; uni; uni = uni->Next) {
#ifndef INET6
if (uni->Address.lpSockaddr->sa_family == AF_INET)
#else
if (IS_IP_FAMILY(uni->Address.lpSockaddr->sa_family))
#endif
rb_ary_push(list, sockaddr_obj(uni->Address.lpSockaddr, uni->Address.iSockaddrLength));
}
for (any = adapters->FirstAnycastAddress; any; any = any->Next) {
#ifndef INET6
if (any->Address.lpSockaddr->sa_family == AF_INET)
#else
if (IS_IP_FAMILY(any->Address.lpSockaddr->sa_family))
#endif
rb_ary_push(list, sockaddr_obj(any->Address.lpSockaddr, any->Address.iSockaddrLength));
}
}
FreeLibrary(h);
return list;
#endif
}
new(domain, socktype [, protocol]) => socket
创建一个新的套接字对象。
域应该是一个通信域,例如::INET,:INET6,:UNIX等。
socktype应该是一个套接字类型,例如::STREAM,:DGRAM,:RAW等。
协议是可选的,应该是在域中定义的协议。如果没有给出协议,则在内部使用0。
Socket.new(:INET, :STREAM) # TCP socket
Socket.new(:INET, :DGRAM) # UDP socket
Socket.new(:UNIX, :STREAM) # UNIX stream socket
Socket.new(:UNIX, :DGRAM) # UNIX datagram socket
static VALUE
sock_initialize(int argc, VALUE *argv, VALUE sock)
{
VALUE domain, type, protocol;
int fd;
int d, t;
rb_scan_args(argc, argv, "21", &domain, &type, &protocol);
if (NIL_P(protocol))
protocol = INT2FIX(0);
setup_domain_and_type(domain, &d, type, &t);
fd = rsock_socket(d, t, NUM2INT(protocol));
if (fd < 0) rb_sys_fail("socket(2)");
return rsock_init_sock(sock, fd);
}
pack_sockaddr_in(port, host) => sockaddrclick to toggle source
将端口和主机打包为AF_INET/AF_INET6 sockaddr字符串。
Socket.sockaddr_in(80, "127.0.0.1")
#=> "\x02\x00\x00P\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"
Socket.sockaddr_in(80, "::1")
#=> "\n\x00\x00P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00"
static VALUE
sock_s_pack_sockaddr_in(VALUE self, VALUE port, VALUE host)
{
struct rb_addrinfo *res = rsock_addrinfo(host, port, AF_UNSPEC, 0, 0);
VALUE addr = rb_str_new((char*)res->ai->ai_addr, res->ai->ai_addrlen);
rb_freeaddrinfo(res);
OBJ_INFECT(addr, port);
OBJ_INFECT(addr, host);
return addr;
}
pack_sockaddr_un(path) => sockaddr
将路径打包为AF_UNIX sockaddr字符串。
Socket.sockaddr_un("/tmp/sock") #=> "\x01\x00/tmp/sock\x00\x00..."
static VALUE
sock_s_pack_sockaddr_un(VALUE self, VALUE path)
{
struct sockaddr_un sockaddr;
VALUE addr;
StringValue(path);
INIT_SOCKADDR_UN(&sockaddr, sizeof(struct sockaddr_un));
if (sizeof(sockaddr.sun_path) < (size_t)RSTRING_LEN(path)) {
rb_raise(rb_eArgError, "too long unix socket path (%"PRIuSIZE" bytes given but %"PRIuSIZE" bytes max)",
(size_t)RSTRING_LEN(path), sizeof(sockaddr.sun_path));
}
memcpy(sockaddr.sun_path, RSTRING_PTR(path), RSTRING_LEN(path));
addr = rb_str_new((char*)&sockaddr, rsock_unix_sockaddr_len(path));
OBJ_INFECT(addr, path);
return addr;
}
pair(domain, type, protocol) => [socket1, socket2]click to toggle source
创建一对相互连接的插座。
域应该是一个通信域,例如::INET,:INET6,:UNIX等。
socktype应该是一个套接字类型,例如::STREAM,:DGRAM,:RAW等。
协议应该是在域中定义的协议,对于域默认为0。
s1, s2 = Socket.pair(:UNIX, :STREAM, 0)
s1.send "a", 0
s1.send "b", 0
s1.close
p s2.recv(10) #=> "ab"
p s2.recv(10) #=> ""
p s2.recv(10) #=> ""
s1, s2 = Socket.pair(:UNIX, :DGRAM, 0)
s1.send "a", 0
s1.send "b", 0
p s2.recv(10) #=> "a"
p s2.recv(10) #=> "b"
sockaddr_in(port, host) => sockaddr
将端口和主机打包为AF_INET / AF_INET6 sockaddr字符串。
Socket.sockaddr_in(80, "127.0.0.1")
#=> "\x02\x00\x00P\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"
Socket.sockaddr_in(80, "::1")
#=> "\n\x00\x00P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00"
static VALUE
sock_s_pack_sockaddr_in(VALUE self, VALUE port, VALUE host)
{
struct rb_addrinfo *res = rsock_addrinfo(host, port, AF_UNSPEC, 0, 0);
VALUE addr = rb_str_new((char*)res->ai->ai_addr, res->ai->ai_addrlen);
rb_freeaddrinfo(res);
OBJ_INFECT(addr, port);
OBJ_INFECT(addr, host);
return addr;
}
sockaddr_un(path) => sockaddr
将路径打包为AF_UNIX sockaddr字符串。
Socket.sockaddr_un("/tmp/sock") #=> "\x01\x00/tmp/sock\x00\x00..."
static VALUE
sock_s_pack_sockaddr_un(VALUE self, VALUE path)
{
struct sockaddr_un sockaddr;
VALUE addr;
StringValue(path);
INIT_SOCKADDR_UN(&sockaddr, sizeof(struct sockaddr_un));
if (sizeof(sockaddr.sun_path) < (size_t)RSTRING_LEN(path)) {
rb_raise(rb_eArgError, "too long unix socket path (%"PRIuSIZE" bytes given but %"PRIuSIZE" bytes max)",
(size_t)RSTRING_LEN(path), sizeof(sockaddr.sun_path));
}
memcpy(sockaddr.sun_path, RSTRING_PTR(path), RSTRING_LEN(path));
addr = rb_str_new((char*)&sockaddr, rsock_unix_sockaddr_len(path));
OBJ_INFECT(addr, path);
return addr;
}
socketpair(domain, type, protocol) => [socket1, socket2]click to toggle source
创建一对相互连接的插座。
域应该是一个通信域,例如::INET,:INET6,:UNIX等。
socktype应该是一个套接字类型,例如::STREAM,:DGRAM,:RAW等。
协议应该是在域中定义的协议,对于域默认为0。
s1, s2 = Socket.pair(:UNIX, :STREAM, 0)
s1.send "a", 0
s1.send "b", 0
s1.close
p s2.recv(10) #=> "ab"
p s2.recv(10) #=> ""
p s2.recv(10) #=> ""
s1, s2 = Socket.pair(:UNIX, :DGRAM, 0)
s1.send "a", 0
s1.send "b", 0
p s2.recv(10) #=> "a"
p s2.recv(10) #=> "b"
VALUE
rsock_sock_s_socketpair(int argc, VALUE *argv, VALUE klass)
{
VALUE domain, type, protocol;
int d, t, p, sp[2];
int ret;
VALUE s1, s2, r;
rb_scan_args(argc, argv, "21", &domain, &type, &protocol);
if (NIL_P(protocol))
protocol = INT2FIX(0);
setup_domain_and_type(domain, &d, type, &t);
p = NUM2INT(protocol);
ret = rsock_socketpair(d, t, p, sp);
if (ret < 0) {
rb_sys_fail("socketpair(2)");
}
s1 = rsock_init_sock(rb_obj_alloc(klass), sp[0]);
s2 = rsock_init_sock(rb_obj_alloc(klass), sp[1]);
r = rb_assoc_new(s1, s2);
if (rb_block_given_p()) {
return rb_ensure(pair_yield, r, io_close, s1);
}
return r;
}
tcp(host, port, local_host=nil, local_port=nil, [opts]) {|socket| ... }
tcp(host, port, local_host=nil, local_port=nil, [opts])
使用TCP / IP创建一个连接到主机:端口的新套接字对象。
如果给出local_host:local_port,则套接字绑定到它。
可选的最后一个参数opts是由散列表示的选项。 opts可能有以下选项:
:connect_timeout
指定以秒为单位的超时。
如果给出了块,则使用套接字调用该块。该块的值将返回。此方法返回时,套接字将关闭。
如果没有给出块,则返回套接字。
Socket.tcp("www.ruby-lang.org", 80) {|sock|
sock.print "GET / HTTP/1.0\r\nHost: www.ruby-lang.org\r\n\r\n"
sock.close_write
puts sock.read
}
# File socket/lib/socket.rb, line 607
def self.tcp(host, port, local_host = nil, local_port = nil, connect_timeout: nil) # :yield: socket
last_error = nil
ret = nil
local_addr_list = nil
if local_host != nil || local_port != nil
local_addr_list = Addrinfo.getaddrinfo(local_host, local_port, nil, :STREAM, nil)
end
Addrinfo.foreach(host, port, nil, :STREAM) {|ai|
if local_addr_list
local_addr = local_addr_list.find {|local_ai| local_ai.afamily == ai.afamily }
next unless local_addr
else
local_addr = nil
end
begin
sock = local_addr ?
ai.connect_from(local_addr, timeout: connect_timeout) :
ai.connect(timeout: connect_timeout)
rescue SystemCallError
last_error = $!
next
end
ret = sock
break
}
unless ret
if last_error
raise last_error
else
raise SocketError, "no appropriate local address"
end
end
if block_given?
begin
yield ret
ensure
ret.close
end
else
ret
end
end
tcp_server_loop(host=nil, port)click to toggle source
在端口上创建一个TCP / IP服务器并为每个接受的连接调用该块。使用套接字和client_address作为Addrinfo对象调用该块。
如果指定了主机,则将其与端口一起用于确定服务器地址。
块返回时套接字未关闭。所以应用程序应该明确关闭它。
该方法依次调用该块。这意味着下一个连接在块返回之前不被接受。因此,并发机制(例如线程)应该一次用于为多个客户端提供服务。
请注意,Addrinfo.getaddrinfo用于确定服务器套接字地址。当Addrinfo.getaddrinfo返回两个或更多地址时,例如IPv4和IPv6地址,都会使用它们。:: 如果至少可以使用一个套接字,则tcp_server_loop会成功。
# Sequential echo server.
# It services only one client at a time.
Socket.tcp_server_loop(16807) {|sock, client_addrinfo|
begin
IO.copy_stream(sock, sock)
ensure
sock.close
end
}
# Threaded echo server
# It services multiple clients at a time.
# Note that it may accept connections too much.
Socket.tcp_server_loop(16807) {|sock, client_addrinfo|
Thread.new {
begin
IO.copy_stream(sock, sock)
ensure
sock.close
end
}
}
tcp_server_sockets(host=nil, port)
为主机和端口创建TCP / IP服务器套接字。 主机是可选的。
如果没有给出任何块,它将返回一个侦听套接字数组。
如果给出了一个块,则使用套接字调用该块。该块的值将返回。此方法返回时,套接字将关闭。
如果端口为0,则动态选择实际端口号。但是,结果中的所有套接字都具有相同的端口号。
# tcp_server_sockets returns two sockets.
sockets = Socket.tcp_server_sockets(1296)
p sockets #=> [#<Socket:fd 3>, #<Socket:fd 4>]
# The sockets contains IPv6 and IPv4 sockets.
sockets.each {|s| p s.local_address }
#=> #<Addrinfo: [::]:1296 TCP>
# #<Addrinfo: 0.0.0.0:1296 TCP>
# IPv6 and IPv4 socket has same port number, 53114, even if it is chosen dynamically.
sockets = Socket.tcp_server_sockets(0)
sockets.each {|s| p s.local_address }
#=> #<Addrinfo: [::]:53114 TCP>
# #<Addrinfo: 0.0.0.0:53114 TCP>
# The block is called with the sockets.
Socket.tcp_server_sockets(0) {|sockets|
p sockets #=> [#<Socket:fd 3>, #<Socket:fd 4>]
}
# File socket/lib/socket.rb, line 740
def self.tcp_server_sockets(host=nil, port)
if port == 0
sockets = tcp_server_sockets_port0(host)
else
last_error = nil
sockets = []
begin
Addrinfo.foreach(host, port, nil, :STREAM, nil, Socket::AI_PASSIVE) {|ai|
begin
s = ai.listen
rescue SystemCallError
last_error = $!
next
end
sockets << s
}
if sockets.empty?
raise last_error
end
rescue Exception
sockets.each(&:close)
raise
end
end
if block_given?
begin
yield sockets
ensure
sockets.each(&:close)
end
else
sockets
end
end
udp_server_loop(port) {|msg, msg_src| ... }
udp_server_loop(host, port) {|msg, msg_src| ... }
在端口上创建UDP/IP服务器,并为每个到达的消息调用块。该消息及其源信息调用该块。
此方法使用端口在内部分配套接字。如果 指定了主机,则将其与端口一起用于确定服务器地址。
该味精是一个字符串。
该msg_src是一个套接字:: UDPSource对象。它用于回复。
# UDP/IP echo server.
Socket.udp_server_loop(9261) {|msg, msg_src|
msg_src.reply msg
}
# File socket/lib/socket.rb, line 1009
def self.udp_server_loop(host=nil, port, &b) # :yield: message, message_source
udp_server_sockets(host, port) {|sockets|
udp_server_loop_on(sockets, &b)
}
end
udp_server_loop_on(sockets) {|msg, msg_src| ... }
在给定的套接字上运行UDP / IP服务器循环。
:: udp_server_sockets的返回值适用于参数。
它会为每条收到的消息调用块。
# File socket/lib/socket.rb, line 982
def self.udp_server_loop_on(sockets, &b) # :yield: msg, msg_src
loop {
readable, _, _ = IO.select(sockets)
udp_server_recv(readable, &b)
}
end
udp_server_recv(sockets) {|msg, msg_src| ... }
接收来自给定套接字的 UDP / IP数据包。对于每个接收到的数据包,该块被调用。
该块接收msg和msg_src。msg是一个字符串,它是接收到的数据包的有效载荷。msg_src是一个用于回复的 Socket :: UDPSource对象。
:: udp_server_loop可以使用这个方法实现,如下所示。
udp_server_sockets(host, port) {|sockets|
loop {
readable, _, _ = IO.select(sockets)
udp_server_recv(readable) {|msg, msg_src| ... }
}
}
# File socket/lib/socket.rb, line 955
def self.udp_server_recv(sockets)
sockets.each {|r|
msg, sender_addrinfo, _, *controls = r.recvmsg_nonblock(exception: false)
next if msg == :wait_readable
ai = r.local_address
if ai.ipv6? and pktinfo = controls.find {|c| c.cmsg_is?(:IPV6, :PKTINFO) }
ai = Addrinfo.udp(pktinfo.ipv6_pktinfo_addr.ip_address, ai.ip_port)
yield msg, UDPSource.new(sender_addrinfo, ai) {|reply_msg|
r.sendmsg reply_msg, 0, sender_addrinfo, pktinfo
}
else
yield msg, UDPSource.new(sender_addrinfo, ai) {|reply_msg|
r.send reply_msg, 0, sender_addrinfo
}
end
}
end
udp_server_sockets([host, ] port)
为UDP服务器创建UDP / IP套接字。
如果没有给出块,它将返回一个套接字数组。
如果给出了一个块,则使用套接字调用该块。该块的值将返回。此方法返回时,套接字将关闭。
如果端口为零,则选择某个端口。但所选端口用于所有套接字。
# UDP/IP echo server
Socket.udp_server_sockets(0) {|sockets|
p sockets.first.local_address.ip_port #=> 32963
Socket.udp_server_loop_on(sockets) {|msg, msg_src|
msg_src.reply msg
}
}
# File socket/lib/socket.rb, line 868
def self.udp_server_sockets(host=nil, port)
last_error = nil
sockets = []
ipv6_recvpktinfo = nil
if defined? Socket::AncillaryData
if defined? Socket::IPV6_RECVPKTINFO # RFC 3542
ipv6_recvpktinfo = Socket::IPV6_RECVPKTINFO
elsif defined? Socket::IPV6_PKTINFO # RFC 2292
ipv6_recvpktinfo = Socket::IPV6_PKTINFO
end
end
local_addrs = Socket.ip_address_list
ip_list = []
Addrinfo.foreach(host, port, nil, :DGRAM, nil, Socket::AI_PASSIVE) {|ai|
if ai.ipv4? && ai.ip_address == "0.0.0.0"
local_addrs.each {|a|
next unless a.ipv4?
ip_list << Addrinfo.new(a.to_sockaddr, :INET, :DGRAM, 0);
}
elsif ai.ipv6? && ai.ip_address == "::" && !ipv6_recvpktinfo
local_addrs.each {|a|
next unless a.ipv6?
ip_list << Addrinfo.new(a.to_sockaddr, :INET6, :DGRAM, 0);
}
else
ip_list << ai
end
}
if port == 0
sockets = ip_sockets_port0(ip_list, false)
else
ip_list.each {|ip|
ai = Addrinfo.udp(ip.ip_address, port)
begin
s = ai.bind
rescue SystemCallError
last_error = $!
next
end
sockets << s
}
if sockets.empty?
raise last_error
end
end
sockets.each {|s|
ai = s.local_address
if ipv6_recvpktinfo && ai.ipv6? && ai.ip_address == "::"
s.setsockopt(:IPV6, ipv6_recvpktinfo, 1)
end
}
if block_given?
begin
yield sockets
ensure
sockets.each(&:close) if sockets
end
else
sockets
end
end
unix(path)
使用UNIX套接字套接字创建一个连接到路径的新套接字。
如果给出了块,则使用套接字调用该块。该块的值将返回。此方法返回时,套接字将关闭。
如果没有给出块,则返回套接字。
# talk to /tmp/sock socket.
Socket.unix("/tmp/sock") {|sock|
t = Thread.new { IO.copy_stream(sock, STDOUT) }
IO.copy_stream(STDIN, sock)
t.join
}
# File socket/lib/socket.rb, line 1059
def self.unix(path) # :yield: socket
addr = Addrinfo.unix(path)
sock = addr.connect
if block_given?
begin
yield sock
ensure
sock.close
end
else
sock
end
end
unix_server_loop(path)
在路径上创建一个UNIX套接字服务器。它调用每个被接受的套接字的块。
如果指定了主机,则将其与端口一起用于确定服务器端口。
块返回时套接字未关闭。所以应用程序应该关闭它。
如果该文件是套接字文件并且该文件由应用程序的用户拥有,则该方法首先删除由path指向的套接字文件。只有在路径目录未被恶意用户更改时才是安全的。所以不要使用/ tmp/恶意用户目录/套接字。请注意,假设/tmp具有粘滞位,/tmp/socket和/tmp/your-private-directory/socket是安全的。
# Sequential echo server.
# It services only one client at a time.
Socket.unix_server_loop("/tmp/sock") {|sock, client_addrinfo|
begin
IO.copy_stream(sock, sock)
ensure
sock.close
end
}
# File socket/lib/socket.rb, line 1146
def self.unix_server_loop(path, &b) # :yield: socket, client_addrinfo
unix_server_socket(path) {|serv|
accept_loop(serv, &b)
}
end
unix_server_socket(path)
在路径上创建一个UNIX服务器套接字
如果没有给定的块,它将返回一个监听套接字。
如果给出了一个块,则使用套接字调用该块,并返回块值。当该块退出时,套接字将被关闭并且套接字文件被删除。
socket = Socket.unix_server_socket("/tmp/s")
p socket #=> #<Socket:fd 3>
p socket.local_address #=> #<Addrinfo: /tmp/s SOCK_STREAM>
Socket.unix_server_socket("/tmp/sock") {|s|
p s #=> #<Socket:fd 3>
p s.local_address #=> # #<Addrinfo: /tmp/sock SOCK_STREAM>
}
# File socket/lib/socket.rb, line 1089
def self.unix_server_socket(path)
unless unix_socket_abstract_name?(path)
begin
st = File.lstat(path)
rescue Errno::ENOENT
end
if st&.socket? && st.owned?
File.unlink path
end
end
s = Addrinfo.unix(path).listen
if block_given?
begin
yield s
ensure
s.close
unless unix_socket_abstract_name?(path)
File.unlink path
end
end
else
s
end
end
unpack_sockaddr_in(sockaddr) => [port, ip_address]click to toggle source
将sockaddr解包到端口和ip_address中。
sockaddr应该是AF_INET / AF_INET6的字符串或addrinfo。
sockaddr = Socket.sockaddr_in(80, "127.0.0.1")
p sockaddr #=> "\x02\x00\x00P\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"
p Socket.unpack_sockaddr_in(sockaddr) #=> [80, "127.0.0.1"]
static VALUE
sock_s_unpack_sockaddr_in(VALUE self, VALUE addr)
{
struct sockaddr_in * sockaddr;
VALUE host;
sockaddr = (struct sockaddr_in*)SockAddrStringValuePtr(addr);
if (RSTRING_LEN(addr) <
(char*)&((struct sockaddr *)sockaddr)->sa_family +
sizeof(((struct sockaddr *)sockaddr)->sa_family) -
(char*)sockaddr)
rb_raise(rb_eArgError, "too short sockaddr");
if (((struct sockaddr *)sockaddr)->sa_family != AF_INET
#ifdef INET6
&& ((struct sockaddr *)sockaddr)->sa_family != AF_INET6
#endif
) {
#ifdef INET6
rb_raise(rb_eArgError, "not an AF_INET/AF_INET6 sockaddr");
#else
rb_raise(rb_eArgError, "not an AF_INET sockaddr");
#endif
}
host = rsock_make_ipaddr((struct sockaddr*)sockaddr, RSTRING_SOCKLEN(addr));
OBJ_INFECT(host, addr);
return rb_assoc_new(INT2NUM(ntohs(sockaddr->sin_port)), host);
}
unpack_sockaddr_un(sockaddr) => pathclick to toggle source
将sockaddr解包到路径中。
sockaddr应该是AF_UNIX的字符串或addrinfo。
sockaddr = Socket.sockaddr_un("/tmp/sock")
p Socket.unpack_sockaddr_un(sockaddr) #=> "/tmp/sock"
static VALUE
sock_s_unpack_sockaddr_un(VALUE self, VALUE addr)
{
struct sockaddr_un * sockaddr;
VALUE path;
sockaddr = (struct sockaddr_un*)SockAddrStringValuePtr(addr);
if (RSTRING_LEN(addr) <
(char*)&((struct sockaddr *)sockaddr)->sa_family +
sizeof(((struct sockaddr *)sockaddr)->sa_family) -
(char*)sockaddr)
rb_raise(rb_eArgError, "too short sockaddr");
if (((struct sockaddr *)sockaddr)->sa_family != AF_UNIX) {
rb_raise(rb_eArgError, "not an AF_UNIX sockaddr");
}
if (sizeof(struct sockaddr_un) < (size_t)RSTRING_LEN(addr)) {
rb_raise(rb_eTypeError, "too long sockaddr_un - %ld longer than %d",
RSTRING_LEN(addr), (int)sizeof(struct sockaddr_un));
}
path = rsock_unixpath_str(sockaddr, RSTRING_SOCKLEN(addr));
OBJ_INFECT(path, addr);
return path;
}
公共实例方法
accept => [client_socket, client_addrinfo]click to toggle source
接受下一个连接。返回一个新的Socket对象和Addrinfo对象。
serv = Socket.new(:INET, :STREAM, 0)
serv.listen(5)
c = Socket.new(:INET, :STREAM, 0)
c.connect(serv.connect_address)
p serv.accept #=> [#<Socket:fd 6>, #<Addrinfo: 127.0.0.1:48555 TCP>]
static VALUE
sock_accept(VALUE sock)
{
rb_io_t *fptr;
VALUE sock2;
union_sockaddr buf;
socklen_t len = (socklen_t)sizeof buf;
GetOpenFile(sock, fptr);
sock2 = rsock_s_accept(rb_cSocket,fptr->fd,&buf.addr,&len);
return rb_assoc_new(sock2, rsock_io_socket_addrinfo(sock2, &buf.addr, len));
}
accept_nonblock([options]) => [client_socket, client_addrinfo]
在为基础文件描述符设置O_NONBLOCK后,使用accept(2)接受传入连接。它返回一个包含为输入连接,接受套接字阵列client_socket和addrinfo中,client_addrinfo。
示例
# In one script, start this first
require 'socket'
include Socket::Constants
socket = Socket.new(AF_INET, SOCK_STREAM, 0)
sockaddr = Socket.sockaddr_in(2200, 'localhost')
socket.bind(sockaddr)
socket.listen(5)
begin # emulate blocking accept
client_socket, client_addrinfo = socket.accept_nonblock
rescue IO::WaitReadable, Errno::EINTR
IO.select([socket])
retry
end
puts "The client said, '#{client_socket.readline.chomp}'"
client_socket.puts "Hello from script one!"
socket.close
# In another script, start this second
require 'socket'
include Socket::Constants
socket = Socket.new(AF_INET, SOCK_STREAM, 0)
sockaddr = Socket.sockaddr_in(2200, 'localhost')
socket.connect(sockaddr)
socket.puts "Hello from script 2."
puts "The server said, '#{socket.readline.chomp}'"
socket.close
如果对accept_nonblock的调用 失败,请参阅#accept以获取可能引发的异常。
#accept_nonblock可能引发与accept(2)失败相对应的任何错误,包括Errno :: EWOULDBLOCK。
如果例外是Errno :: EWOULDBLOCK,Errno :: EAGAIN,Errno :: ECONNABORTED或Errno :: EPROTO,则它由IO :: WaitReadable扩展。所以IO :: WaitReadable可以用来解救重试accept_nonblock的异常。
通过指定关键字参数异常来false
,你可以指出#accept_nonblock应该不会引发IO :: WaitReadable异常,但返回的符号 :wait_readable
来代替。
请参阅
- #accept
# File ext/socket/lib/socket.rb, line 577
def accept_nonblock(exception: true)
__accept_nonblock(exception)
end
bind(local_sockaddr)→0
绑定到给定的本地地址。
参数
local_sockaddr
-struct
包含在字符串或Addrinfo对象中的sockaddr
示例
require 'socket'
# use Addrinfo
socket = Socket.new(:INET, :STREAM, 0)
socket.bind(Addrinfo.tcp("127.0.0.1", 2222))
p socket.local_address #=> #<Addrinfo: 127.0.0.1:2222 TCP>
# use struct sockaddr
include Socket::Constants
socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
socket.bind( sockaddr )
基于Unix的例外
在基于unix的系统上,如果绑定调用失败,则可能会引发以下系统异常:
- Errno :: EACCES - 指定的sockaddr受保护,当前用户无权绑定它
- Errno :: EADDRINUSE - 指定的sockaddr已被使用
- Errno :: EADDRNOTAVAIL - 指定的sockaddr不可从本地机器获得
- Errno :: EAFNOSUPPORT - 指定的sockaddr不是调用系列的有效地址
socket
- Errno :: EBADF - 指定的sockaddr不是有效的文件描述符
- Errno :: EFAULT - 不能访问sockaddr参数
- Errno :: EINVAL -
socket
已经绑定到一个地址,协议不支持绑定到新的sockaddr或socket
已关闭。
- Errno :: EINVAL - 地址长度不是地址系列的有效长度
- Errno :: ENAMETOOLONG - 解析的路径名长度超过了PATH_MAX
- Errno :: ENOBUFS - 没有可用的缓冲空间
- Errno :: ENOSR - 没有足够的STREAMS资源可用于完成操作
- Errno :: ENOTSOCK -
socket
不涉及套接字
- Errno :: EOPNOTSUPP -
socket
不支持绑定到地址的套接字类型
如果调用的地址族socket
是Socket :: AF_UNIX,那么在基于unix的系统上,如果绑定调用失败,则可能会引发以下异常:
- 错误号:: EACCES -搜索权限被拒绝的前缀路径的组件或写访问
socket
被拒绝
- Errno :: EDESTADDRREQ - sockaddr参数是一个空指针
- Errno :: EISDIR - 与Errno :: EDESTADDRREQ相同
- Errno :: EIO - 发生I / O错误
- Errno :: ELOOP - 在翻译sockaddr中的路径名时遇到太多符号链接
- Errno :: ENAMETOOLLONG - 路径名的一个组件超过了NAME_MAX个字符,或者整个路径名超过了PATH_MAX个字符
- Errno :: ENOENT - 路径名的一个组件不会命名现有文件,或路径名是空字符串
- Errno :: ENOTDIR - sockaddr中路径名的路径前缀的组件不是目录
- Errno :: EROFS - 名称将驻留在只读文件系统上Windows例外在Windows系统中,如果调用绑定失败,则可能会引发以下系统异常:
- Errno :: ENETDOWN-网络已关闭
- Errno :: EACCES - 尝试将数据报套接字连接到广播地址失败
- Errno :: EADDRINUSE - 套接字的本地地址已被使用
- Errno :: EADDRNOTAVAIL - 指定的地址不是此计算机的有效地址
- Errno :: EFAULT - 套接字的内部地址或地址长度参数太小或者不是用户空间的有效部分
- Errno :: EINVAL -
socket
已经绑定到一个地址
- Errno :: ENOBUFS - 没有可用的缓冲空间
- Errno :: ENOTSOCK - 该
socket
参数并不涉及socket
参见
- 绑定基于Unix系统的手册页
- 连接函数在微软的Winsock函数参考中
static VALUE
sock_bind(VALUE sock, VALUE addr)
{
VALUE rai;
rb_io_t *fptr;
SockAddrStringValueWithAddrinfo(addr, rai);
GetOpenFile(sock, fptr);
if (bind(fptr->fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_SOCKLEN(addr)) < 0)
rsock_sys_fail_raddrinfo_or_sockaddr("bind(2)", addr, rai);
return INT2FIX(0);
}
connect(remote_sockaddr) => 0
在remote_sockaddr
为基础文件描述符设置O_NONBLOCK之后,请求在给定的连接上进行连接。如果成功则返回0,否则引发异常。
参数
remote_sockaddr
-struct
包含在字符串或Addrinfo对象中的sockaddr
例:
# Pull down Google's web page
require 'socket'
include Socket::Constants
socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
sockaddr = Socket.pack_sockaddr_in( 80, 'www.google.com' )
socket.connect( sockaddr )
socket.write( "GET / HTTP/1.0\r\n\r\n" )
results = socket.read
基于Unix的例外
在基于Unix系统的系统上,如果连接呼叫失败,可能会引发以下系统异常:
- 错误号:: EACCES -搜索权限被拒绝的前缀路径的组件或写访问
socket
被拒绝
- Errno :: EADDRINUSE - sockaddr已在使用中
- Errno :: EADDRNOTAVAIL - 指定的sockaddr不可从本地机器获得
- Errno :: EAFNOSUPPORT - 指定的sockaddr不是指定地址族的有效地址
socket
- Errno :: EALREADY - 指定套接字的连接已在进行中
- Errno :: EBADF - 这
socket
不是有效的文件描述符
- Errno :: ECONNREFUSED - 目标sockaddr没有监听连接拒绝连接请求
- Errno :: ECONNRESET - 远程主机重置连接请求
- Errno :: EFAULT - 无法访问sockaddr
- Errno :: EHOSTUNREACH - 目标主机无法访问(可能是因为主机关闭或远程路由器无法访问它)
- Errno :: EINPROGRESS - O_NONBLOCK被设置为
socket
并且连接不能立即建立; 连接将异步建立
- Errno :: EINTR--试图建立连接被传递被捕获的信号中断; 连接将异步建立
- Errno :: EISCONN - 指定
socket
的已连接
- Errno :: EINVAL - 用于sockaddr的地址长度不是地址族的有效长度,或者sockaddr中存在无效的族
- Errno :: ENAMETOOLONG - 解析的路径名长度超过了PATH_MAX
- Errno :: ENETDOWN - 用于到达目的地的本地接口已关闭
- Errno :: ENETUNREACH - 没有路由到网络
- Errno :: ENOBUFS - 没有可用的缓冲空间
- Errno :: ENOSR - 没有足够的STREAMS资源可用于完成操作
- Errno :: ENOTSOCK -
socket
参数没有引用套接字
- Errno :: EOPNOTSUPP - 呼叫
socket
正在收听,无法连接
- Errno :: EPROTOTYPE - sockaddr具有与绑定到指定对等地址的套接字不同的类型
- Errno :: ETIMEDOUT - 在建立连接之前尝试连接超时。如果调用的地址族
socket
为AF_UNIX,则在基于unix的系统中,如果调用连接失败,可能会引发以下异常:
- Errno :: EIO - 从文件系统读取或写入文件系统时发生I / O错误
- Errno :: ELOOP - 在翻译sockaddr中的路径名时遇到太多符号链接
- Errno :: ENAMETOOLLONG - 路径名的一个组件超过了NAME_MAX个字符,或者整个路径名超过了PATH_MAX个字符
- Errno :: ENOENT - 路径名的一个组件不会命名现有文件,或路径名是空字符串
- Errno :: ENOTDIR - sockaddr中路径名的路径前缀的组件不是目录
Windows例外
在Windows系统上,如果连接呼叫失败,可能会引发以下系统异常:
- Errno :: ENETDOWN - 网络已关闭
- Errno :: EADDRINUSE - 套接字的本地地址已被使用
- Errno :: EINTR - 套接字被取消
- Errno :: EINPROGRESS - 阻塞套接字正在进行中,或者服务提供者仍在处理回调函数。或者正在进行非阻塞连接呼叫
socket
。
- Errno::EALREADY - see Errno::EINVAL
- Errno :: EADDRNOTAVAIL - 远程地址不是有效地址,例如ADDR_ANY TODO检查ADDRANY TO INADDR_ANY
- Errno :: EAFNOSUPPORT - 指定系列中的地址不能与此一起使用
socket
- Errno :: ECONNREFUSED - 目标sockaddr没有监听连接拒绝连接请求
- Errno :: EFAULT - 套接字的内部地址或地址长度参数太小或者不是用户空间地址的有效部分
- Errno :: EINVAL - 这
socket
是一个监听套接字
- Errno :: EISCONN -
socket
已连接
- Errno :: ENETUNREACH - 此时无法从此主机访问网络
- Errno :: EHOSTUNREACH - 没有路由到网络
- Errno :: ENOBUFS - 没有可用的缓冲空间
- Errno :: ENOTSOCK -
socket
参数没有引用套接字
- Errno :: ETIMEDOUT - 在建立连接之前尝试连接超时。
- Errno :: EWOULDBLOCK - 套接字被标记为非阻塞,并且连接无法立即完成
- Errno :: EACCES - 尝试将数据报套接字连接到广播地址失败
看到
- 在基于Unix的系统上连接手册页
- 连接函数在微软的Winsock函数参考中
static VALUE
sock_connect(VALUE sock, VALUE addr)
{
VALUE rai;
rb_io_t *fptr;
int fd, n;
SockAddrStringValueWithAddrinfo(addr, rai);
addr = rb_str_new4(addr);
GetOpenFile(sock, fptr);
fd = fptr->fd;
n = rsock_connect(fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_SOCKLEN(addr), 0);
if (n < 0) {
rsock_sys_fail_raddrinfo_or_sockaddr("connect(2)", addr, rai);
}
return INT2FIX(n);
}
connect_nonblock(remote_sockaddr,options)→0显示源文件
在remote_sockaddr
为基础文件描述符设置O_NONBLOCK之后,请求在给定的连接上进行连接。如果成功则返回0,否则引发异常。
参数
# +remote_sockaddr+ - the +struct+ sockaddr contained in a string or Addrinfo object
例:
# Pull down Google's web page
require 'socket'
include Socket::Constants
socket = Socket.new(AF_INET, SOCK_STREAM, 0)
sockaddr = Socket.sockaddr_in(80, 'www.google.com')
begin # emulate blocking connect
socket.connect_nonblock(sockaddr)
rescue IO::WaitWritable
IO.select(nil, [socket]) # wait 3-way handshake completion
begin
socket.connect_nonblock(sockaddr) # check connection failure
rescue Errno::EISCONN
end
end
socket.write("GET / HTTP/1.0\r\n\r\n")
results = socket.read
如果对connect_nonblock的调用失败,请参阅#connect以了解可能会抛出的异常。
#connect_nonblock可能引发与连接(2)失败相对应的任何错误,包括Errno :: EINPROGRESS。
如果异常是Errno :: EINPROGRESS,则由IO :: WaitWritable进行扩展。所以IO :: WaitWritable可以用来解救重试connect_nonblock的异常。
通过指定关键字参数异常来false
,你可以指出#connect_nonblock应该不会引发IO :: WaitWritable异常,但返回的符号:wait_writable
来代替。
看到
# Socket#connect
# File ext/socket/lib/socket.rb, line 1196
def connect_nonblock(addr, exception: true)
__connect_nonblock(addr, exception)
end
ipv6only!()显示源文件
如果IPV6_V6ONLY可用,请启用套接字选项IPV6_V6ONLY。
# File ext/socket/lib/socket.rb, line 448
def ipv6only!
if defined? Socket::IPV6_V6ONLY
self.setsockopt(:IPV6, :V6ONLY, 1)
end
end
listen(int)→0
监听连接,使用指定int
的积压。只有在类型为SOCK_STREAM或SOCK_SEQPACKET 的情况下才会调用侦听socket
。
参数
backlog
- 等待连接队列的最大长度。
示例1
require 'socket'
include Socket::Constants
socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
socket.bind( sockaddr )
socket.listen( 5 )
示例2(在任意端口上侦听,仅限基于unix的系统)
require 'socket'
include Socket::Constants
socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
socket.listen( 1 )
基于Unix的例外
在基于unix的系统上,上面的工作将会sockaddr
生效,因为在地址ADDR_ANY上创建了一个新的 结构体,用于由内核传递的任意端口号。它不会在Windows上运行,因为Windows要求socket
通过调用约束绑定,才可以听。
如果积压量超过了实现相关的最大队列长度,则将使用实现的最大队列长度。
在基于unix的系统上,如果侦听呼叫失败,则可能会引发以下系统异常:
- Errno :: EBADF - 套接字参数不是有效的文件描述符
- Errno :: EDESTADDRREQ - 套接字未绑定到本地地址,且协议不支持侦听未绑定的套接字
- Errno :: EINVAL - 套接字已经连接
- Errno :: ENOTSOCK - 套接字参数不引用套接字
- Errno :: EOPNOTSUPP - 套接字协议不支持listen
- Errno :: EACCES - 调用过程没有适当的权限
- Errno :: EINVAL - 套接字已关闭
- Errno :: ENOBUFS - 系统中可用资源不足以完成callWindows异常在Windows系统中,如果侦听呼叫失败,则可能会引发以下系统异常:
- Errno :: ENETDOWN - 网络已关闭
- Errno :: EADDRINUSE - 套接字的本地地址已被使用。这通常发生在绑定执行过程中,但如果绑定调用是部分通配符地址(涉及ADDR_ANY),并且在调用收听时需要提交特定地址
- Errno :: EINPROGRESS - 正在进行Windows套接字1.1调用,或者服务提供者仍在处理回调函数
- Errno :: EINVAL -
socket
尚未绑定调用绑定。
- Errno :: EISCONN -
socket
已连接
- Errno :: EMFILE - 不再有套接字描述符可用
- Errno :: ENOBUFS - 没有可用的缓冲空间
- Errno :: ENOTSOC -
socket
不是套接字
- Errno :: EOPNOTSUPP - 引用
socket
不是支持listen方法的类型
看到
- 在基于Unix的系统上收听手册页面
- 在Microsoft的Winsock函数参考中监听函数
VALUE
rsock_sock_listen(VALUE sock, VALUE log)
{
rb_io_t *fptr;
int backlog;
backlog = NUM2INT(log);
GetOpenFile(sock, fptr);
if (listen(fptr->fd, backlog) < 0)
rb_sys_fail("listen(2)");
return INT2FIX(0);
}
recvfrom(maxlen) → mesg, sender_addrinfo()
recvfrom(maxlen, flags) → mesg, sender_addrinfo
最多可接收来自maxlen字节socket
。标志是零个或多个MSG_
选项。结果的第一个元素mesg是收到的数据。第二个元素sender_addrinfo包含发件人的特定于协议的地址信息。
参数
maxlen
- 从套接字接收的最大字节数
flags
- 零个或多个MSG_
选项
例
# In one file, start this first
require 'socket'
include Socket::Constants
socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
socket.bind( sockaddr )
socket.listen( 5 )
client, client_addrinfo = socket.accept
data = client.recvfrom( 20 )[0].chomp
puts "I only received 20 bytes '#{data}'"
sleep 1
socket.close
# In another file, start this second
require 'socket'
include Socket::Constants
socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
socket.connect( sockaddr )
socket.puts "Watch this get cut short!"
socket.close
基于Unix的例外
在基于unix的系统上,如果对recvfrom的调用失败,则可能会引发以下系统异常:
- Errno :: EAGAIN -
socket
文件描述符被标记为O_NONBLOCK,并且没有数据等待接收; 或者MSG_OOB被设置,并且没有带外数据可用,并且socket
文件描述符被标记为O_NONBLOCK,或者socket
不支持阻塞来等待带外数据
- Errno :: EWOULDBLOCK - 参见Errno :: EAGAIN
- Errno :: EBADF - 这
socket
不是有效的文件描述符
- Errno :: ECONNRESET - 一个连接被同伴强行关闭
- Errno :: EFAULT - 无法访问或写入套接字的内部缓冲区,地址或地址长度
- Errno :: EINTR - 在任何数据可用之前信号中断recvfrom
- Errno :: EINVAL - MSG_OOB标志被设置,并且没有带外数据可用
- Errno :: EIO - 从文件系统读取或写入文件系统时发生I / O错误
- Errno :: ENOBUFS - 系统中没有足够的资源来执行操作
- Errno :: ENOMEM - 内存不足以满足请求
- Errno :: ENOSR - 没有足够的STREAMS资源可用于完成操作
- Errno :: ENOTCONN - 在未连接的连接模式套接字上尝试接收数据
- Errno :: ENOTSOCK -
socket
不涉及套接字
- Errno :: EOPNOTSUPP - 此套接字类型不支持指定的标志
- Errno :: ETIMEDOUT - 在连接建立期间连接超时或由于活动连接上的传输超时Windows异常在Windows系统中,如果对recvfrom的调用失败,可能会引发以下系统异常:
- Errno :: ENETDOWN - 网络已关闭
- Errno :: EFAULT - 内部缓冲区和from参数
socket
不是用户地址空间的一部分,或者内部的fromlen参数太小而不能容纳对等地址
- Errno :: EINTR - (阻塞)调用被内部调用WinSock函数WSACancelBlockingCall取消
- Errno :: EINPROGRESS - 阻塞的Windows套接字1.1调用正在进行中,或者服务提供者仍在处理回调函数
- Errno :: EINVAL -
socket
尚未绑定调用绑定或指定了未知标志,或者已为启用了SO_OOBINLINE的套接字指定了MSG_OOB,或者(对于仅字节流式套接字),on上的内部len参数socket
为零或否定的
- Errno :: EISCONN -
socket
已连接。对于面向连接或无连接的套接字,连接的套接字不允许对recvfrom的调用。
- Errno :: ENETRESET - 由于保持活动状态活动在操作正在进行时检测到故障,连接已中断。
- Errno :: EOPNOTSUPP - MSG_OOB已指定,但
socket
不是流式,如类型SOCK_STREAM。OOB数据在与之相关的通信域中不受支持socket
,或者socket
是单向的,并且仅支持发送操作
- Errno :: ESHUTDOWN -
socket
已关闭。在调用shutdown之后,无法在套接字上调用recvfrom。
- Errno :: EWOULDBLOCK -
socket
被标记为非阻塞,并且会阻止对recvfrom的调用。
- Errno :: EMSGSIZE - 消息太大而无法放入指定的缓冲区并被截断。
- Errno :: ETIMEDOUT - 由于网络故障或另一端的系统不通知而连接断开
- Errno :: ECONNRESET - 虚拟电路由远程端执行硬性或异常关闭而重置。应用程序应关闭套接字; 它不再可用。在UDP数据报套接字上,此错误指示先前的发送操作导致ICMP端口不可到达消息。
static VALUE
sock_recvfrom(int argc, VALUE *argv, VALUE sock)
{
return rsock_s_recvfrom(sock, argc, argv, RECV_SOCKET);
}
recvfrom_nonblock(maxlen [,flags [,outbuf,opts]])→mesg,sender_addrinfo()
在为基础文件描述符设置了O_NONBLOCK后,接收使用recvfrom(2)时的maxlen字节socket
。标志是零个或多个MSG_
选项。结果的第一个元素mesg是收到的数据。第二个元素sender_addrinfo包含发件人的特定于协议的地址信息。
当recvfrom(2)返回0时,#recvfrom_nonblock返回一个空字符串作为数据。含义取决于套接字:TCP上的EOF,UDP上的空数据包等。
参数
maxlen
- 从套接字接收的最大字节数
flags
- 零个或多个MSG_
选项
outbuf
- 目标字符串缓冲区
opts
- 关键字散列,支持exception: false
例
# In one file, start this first
require 'socket'
include Socket::Constants
socket = Socket.new(AF_INET, SOCK_STREAM, 0)
sockaddr = Socket.sockaddr_in(2200, 'localhost')
socket.bind(sockaddr)
socket.listen(5)
client, client_addrinfo = socket.accept
begin # emulate blocking recvfrom
pair = client.recvfrom_nonblock(20)
rescue IO::WaitReadable
IO.select([client])
retry
end
data = pair[0].chomp
puts "I only received 20 bytes '#{data}'"
sleep 1
socket.close
# In another file, start this second
require 'socket'
include Socket::Constants
socket = Socket.new(AF_INET, SOCK_STREAM, 0)
sockaddr = Socket.sockaddr_in(2200, 'localhost')
socket.connect(sockaddr)
socket.puts "Watch this get cut short!"
socket.close
如果对recvfrom_nonblock的调用失败,请参阅#recvfrom了解可能会抛出的异常。
#recvfrom_nonblock可能引发对应于recvfrom(2)失败的错误,包括Errno :: EWOULDBLOCK。
如果该异常是Errno :: EWOULDBLOCK或Errno :: EAGAIN,则它由IO :: WaitReadable扩展。所以IO :: WaitReadable可以用来解救重试recvfrom_nonblock的异常。
通过指定关键字参数异常来false
,你可以指出#recvfrom_nonblock应该不会引发IO :: WaitReadable异常,但返回的符号:wait_readable
来代替。
参见
- #recvfrom#
sysaccept => [client_socket_fd, client_addrinfo]
接受传入连接,返回包含传入连接(整数)文件描述符的数组,client_socket_fd和Addrinfo,client_addrinfo。
示例
# In one script, start this first
require 'socket'
include Socket::Constants
socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
socket.bind( sockaddr )
socket.listen( 5 )
client_fd, client_addrinfo = socket.sysaccept
client_socket = Socket.for_fd( client_fd )
puts "The client said, '#{client_socket.readline.chomp}'"
client_socket.puts "Hello from script one!"
socket.close
# In another script, start this second
require 'socket'
include Socket::Constants
socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
socket.connect( sockaddr )
socket.puts "Hello from script 2."
puts "The server said, '#{socket.readline.chomp}'"
socket.close
如果对sysaccept的调用失败,请参阅#accept了解可能会抛出的异常。
请参阅
- #accept
static VALUE
sock_sysaccept(VALUE sock)
{
rb_io_t *fptr;
VALUE sock2;
union_sockaddr buf;
socklen_t len = (socklen_t)sizeof buf;
GetOpenFile(sock, fptr);
sock2 = rsock_s_accept(0,fptr->fd,&buf.addr,&len);
return rb_assoc_new(sock2, rsock_io_socket_addrinfo(sock2, &buf.addr, len));
}
本文档系腾讯云开发者社区成员共同维护,如有问题请联系 cloudcommunity@tencent.com