Socket e$B$r;H$C$F$$$k$H!"@8@.$9$k$H$3$m$,e(B TCPSocket e$BEy$KHf$Y$Fe(B
e$BITJX$J$N$G!"0J2<$N$h$&$J%a%=%C%I$r$D$1$F$b$$$$$G$7$g$&$+!#e(B
Socket.tcp(host, port, local_host=nil, local_port=nil) {|socket| … }
Socket.tcp_server_loop(host=nil, port) {|socket, client_addrinfo| …
}
Socket.unix(path) {|socket| … }
Socket.unix_server_loop(path) {|socket, client_addrinfo| … }
Socket.tcp e$B$He(B Socket.unix e$B$Oe(B
TCPSocket.open e$B$He(B UNIXSocket.open e$B$KBP1~$7$^$9!#e(B
Socket.tcp_server_loop e$B$He(B Socket.unix_server_loop e$B$Oe(B
TCPServer.open, UNIXServer.open e$B$K2C$($F!"e(Baccept e$B$9$k%k!<%We(B
e$B$^$GF~$C$F$$$^$9!#e(B
accept e$B$^$G9T$&$N$O!"e(BTCPServer.open e$BFb$G!“e(Bgetaddrinfo
e$B$,JV$7e(B
e$B$?$9$Y$F$N%”%I%l%9$r07$&$?$a$G$9!#%5!<%P%=%1%C%H$r8F=P85$KJVe(B
e$B$9e(B TCPServer.open e$B$N7A$@$H!“e(BIPv4 e$B$He(B IPv6
e$B$rJ,$1$F07$&$3$H$,e(B
e$B$G$-$^$;$s!#JL!9$K%=%1%C%H$r:n$C$FJ,$1$F07$&$H$$$&$N$,e(B
RFC 4038 e$B$N$A&$a$J$h$&$G$9!#$J$!”>-MhE*$K$O!"0z?t$r3HD%$7e(B
e$B$Fe(B port e$B$rJ#?t;XDj$G$-$k$H$+$7$F$b$$$$$+$b$7$l$^$;$s!#e(B
e$B$“$H!“e(BSocket.unix_server_loop e$B$O4{B8$N%=%1%C%H%U%!%$%k$re(B
(owner e$B$N8!::$r$7$?>e$Ge(B) e$B>C$9$h$&$K$7$F$”$j$^$9!#e(Bone liner
e$B$G%F%9%H$9$k$H$-$K$O$=$C$A$N$[$&$,JXMx$G$9$7!”$^$8$a$K%5!<%Pe(B
e$B$r=q$/$J$i$I$&$;B>$N%5!<%P$,@8$-$F$$$k$+$I$&$+$OJL$N<jCJ$G3Ne(B
e$BG’$7$J$1$l$P$J$i$:!"B>$K%5!<%P$,$$$J$$>u67$G8F$S=P$9$H$9$l$Pe(B
e$B>C$7$A$c$C$FLdBj$J$$$H;W$&$N$G!#e(B
e$B<BAu$Oe(B Ruby e$B$G=q$$$F$"$j$^$9$N$G!"e(Bsocket.rb
e$B$N?7@_$K$J$j$^$9!#e(B
% svn diff --diff-cmd diff -x ‘-u -p’
Index: ext/socket/lib/socket.rb
— ext/socket/lib/socket.rb (revision 0)
+++ ext/socket/lib/socket.rb (revision 0)
@@ -0,0 +1,262 @@
+require ‘socket.so’
+
+class AddrInfo
AddrInfo.getaddrinfo.
-
-
Example:
-
-
AddrInfo.foreach(nil, 80) {|x| p x }
-
#=> #<AddrInfo: 127.0.0.1:80 TCP (:80)>
-
# #<AddrInfo: 127.0.0.1:80 UDP (:80)>
-
# #<AddrInfo: [::1]:80 TCP (:80)>
-
# #<AddrInfo: [::1]:80 UDP (:80)>
-
- def self.foreach(nodename, service, family=nil, socktype=nil,
protocol=nil, flags=nil, &block) - AddrInfo.getaddrinfo(nodename, service, family, socktype, protocol,
flags).each(&block) - end
+end
+class Socket
-
creates a new socket object connected to host:port using TCP.
-
-
If local_host:local_port is given,
-
the socket is bound to it.
-
-
If a block is given, the block is called with the socket.
-
The value of the block is returned.
-
The socket is closed when this method returns.
-
-
If no block is given, the socket is returned.
-
-
Example:
-
-
Socket.tcp(“www.ruby-lang.org”, 80) {|sock|
-
sock.print “GET / HTTP/1.0\r\n\r\n”
-
sock.close_write
-
print sock.read
-
}
-
- def self.tcp(host, port, local_host=nil, local_port=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).each {|ai|
-
begin -
sock = self.new(ai.pfamily, ai.socktype, ai.protocol) -
rescue SystemCallError -
last_error = $! -
next -
end -
if local_addr_list -
if local_addr = local_addr_list.find {|local_ai|
local_ai.afamily == ai.afamily }
-
begin -
sock.bind(local_addr) -
rescue SystemCallError -
last_error = $! -
next -
end -
else -
next -
end -
end -
begin -
sock.connect(ai) -
rescue SystemCallError -
last_error = $! -
sock.close -
next -
end -
ret = sock -
break - }
- if !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 if !ret.closed? -
end - else
-
ret - end
- end
-
creates a TCP server on port and calls the block for each
connection accepted.
AddrInfo object.
server addresses.
-
-
The socket is not closed when the block returns.
-
So application should close it explicitly.
-
-
This method calls the block sequentially.
-
It means that the next connection is not accepted until the block
returns.
service multiple clients at a time.
socket addresses.
-
When AddrInfo.getaddrinfo returns two or more addresses,
-
IPv4 and IPv6 address for example,
-
all of them are used.
-
Socket.tcp_server_loop succeeds if one socket can be used at least.
-
-
Example:
-
-
# 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.
-
Socket.tcp_server_loop(16807) {|sock, client_addrinfo|
-
Thread.new {
-
begin
-
IO.copy_stream(sock, sock)
-
ensure
-
sock.close
-
end
-
}
-
}
-
- def self.tcp_server_loop(host=nil, port) # :yield: socket,
client_addrinfo - last_error = nil
- sockets = []
- AddrInfo.foreach(host, port, nil, :STREAM, nil, Socket::AI_PASSIVE)
{|ai| -
begin -
s = self.new(ai.pfamily, ai.socktype, ai.protocol) -
rescue SystemCallError -
last_error = $! -
next -
end -
sockets << s -
s.setsockopt(:SOCKET, :REUSEADDR, 1) -
s.setsockopt(:IPV6, :V6ONLY, 1) if ai.ipv6? -
begin -
s.bind(ai) -
rescue SystemCallError -
last_error = $! -
next -
end -
begin -
s.listen(5) -
rescue SystemCallError -
last_error = $! -
next -
end - }
- if sockets.empty?
-
raise last_error - end
- loop {
-
readable, _, _ = IO.select(sockets) -
readable.each {|r| -
begin -
sock, addr = r.accept_nonblock -
rescue Errno::EWOULDBLOCK -
next -
end -
yield sock, addr -
} - }
- ensure
- sockets.each {|s|
-
s.close if !s.closed? - }
- end
-
creates a new socket connected to path using UNIX socket socket.
-
-
If a block is given, the block is called with the socket.
-
The value of the block is returned.
-
The socket is closed when this method returns.
-
-
If no block is given, the socket is returned.
-
-
Example:
-
-
# 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
-
}
-
- def self.unix(path) # :yield: socket
- addr = AddrInfo.unix(path)
- sock = self.new(:UNIX, :STREAM, 0)
- begin
-
sock.connect(addr) - ensure
-
sock.close if $! - end
- if block_given?
-
begin -
yield sock -
ensure -
sock.close if !sock.closed? -
end - else
-
sock - end
- end
-
creates a UNIX socket server on path.
-
It calls the block for each socket accepted.
-
-
If host is specified, it is used with port to determine the
server ports.
-
-
The socket is not closed when the block returns.
-
So application should close it.
-
-
This method deletes the socket file pointed by path at first if
-
the file is a socket file and it is owned by the user of the
application.
-
-
Example:
-
-
# 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
-
}
-
- def self.unix_server_loop(path) # :yield: socket, client_addrinfo
- begin
-
st = File.lstat(path) - rescue Errno::ENOENT
- end
- if st && st.socket? && st.owned?
-
File.unlink path - end
- serv = self.new(:UNIX, :STREAM, 0)
- serv.bind(AddrInfo.unix(path))
- serv.listen(5)
- loop {
-
sock, addr = serv.accept -
yield sock, addr - }
- ensure
- serv.close if serv && !serv.closed?
- end
+end
+