* ext/socket/lib/socket.rb (Socket.tcp_server_sockets): extracted from
Socket.tcp_server_loop. (Socket.accept_loop): ditto. (Socket.unix_server_socket): extracted from Socket.unix_server_loop. (Socket.unix_server_loop): use Socket.accept_loop. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@21992 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
2df1053c1d
commit
13a468db17
@ -1,3 +1,11 @@
|
|||||||
|
Tue Feb 3 08:35:12 2009 Tanaka Akira <akr@fsij.org>
|
||||||
|
|
||||||
|
* ext/socket/lib/socket.rb (Socket.tcp_server_sockets): extracted from
|
||||||
|
Socket.tcp_server_loop.
|
||||||
|
(Socket.accept_loop): ditto.
|
||||||
|
(Socket.unix_server_socket): extracted from Socket.unix_server_loop.
|
||||||
|
(Socket.unix_server_loop): use Socket.accept_loop.
|
||||||
|
|
||||||
Tue Feb 3 08:21:05 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
Tue Feb 3 08:21:05 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||||
|
|
||||||
* test/ruby/test_readpartial.rb (make_pipe): readpartial does not
|
* test/ruby/test_readpartial.rb (make_pipe): readpartial does not
|
||||||
|
@ -161,7 +161,7 @@ end
|
|||||||
class Socket
|
class Socket
|
||||||
# enable the socket option IPV6_V6ONLY if IPV6_V6ONLY is available.
|
# enable the socket option IPV6_V6ONLY if IPV6_V6ONLY is available.
|
||||||
def ipv6only!
|
def ipv6only!
|
||||||
if Socket.const_defined?(:IPV6_V6ONLY)
|
if defined? Socket::IPV6_V6ONLY
|
||||||
self.setsockopt(:IPV6, :V6ONLY, 1)
|
self.setsockopt(:IPV6, :V6ONLY, 1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -226,6 +226,71 @@ class Socket
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# creates TCP server sockets for _host_ and _port_.
|
||||||
|
# _host_ is optional.
|
||||||
|
#
|
||||||
|
# It returns an array of listening sockets.
|
||||||
|
#
|
||||||
|
# # 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>
|
||||||
|
#
|
||||||
|
def self.tcp_server_sockets(host=nil, port)
|
||||||
|
last_error = nil
|
||||||
|
sockets = []
|
||||||
|
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
|
||||||
|
sockets
|
||||||
|
ensure
|
||||||
|
if $!
|
||||||
|
sockets.each {|s|
|
||||||
|
s.close if !s.closed?
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# yield socket and client address for each a connection accepted via given sockets.
|
||||||
|
#
|
||||||
|
# The arguments are a list of sockets.
|
||||||
|
# The individual argument should be a socket or an array of sockets.
|
||||||
|
#
|
||||||
|
# This method yields the block sequentially.
|
||||||
|
# It means that the next connection is not accepted until the block returns.
|
||||||
|
# So concurrent mechanism, thread for example, should be used to service multiple clients at a time.
|
||||||
|
#
|
||||||
|
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|
|
||||||
|
begin
|
||||||
|
sock, addr = r.accept_nonblock
|
||||||
|
rescue Errno::EWOULDBLOCK
|
||||||
|
next
|
||||||
|
end
|
||||||
|
yield sock, addr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
# creates a TCP server on _port_ and calls the block for each connection accepted.
|
# creates a TCP server on _port_ and calls the block for each connection accepted.
|
||||||
# The block is called with a socket and a client_address as an AddrInfo object.
|
# The block is called with a socket and a client_address as an AddrInfo object.
|
||||||
#
|
#
|
||||||
@ -267,37 +332,16 @@ class Socket
|
|||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
def self.tcp_server_loop(host=nil, port) # :yield: socket, client_addrinfo
|
def self.tcp_server_loop(host=nil, port, &b) # :yield: socket, client_addrinfo
|
||||||
last_error = nil
|
sockets = tcp_server_sockets(host, port)
|
||||||
sockets = []
|
accept_loop(sockets, &b)
|
||||||
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
|
|
||||||
loop {
|
|
||||||
readable, _, _ = IO.select(sockets)
|
|
||||||
readable.each {|r|
|
|
||||||
begin
|
|
||||||
sock, addr = r.accept_nonblock
|
|
||||||
rescue Errno::EWOULDBLOCK
|
|
||||||
next
|
|
||||||
end
|
|
||||||
yield sock, addr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ensure
|
ensure
|
||||||
|
if sockets
|
||||||
sockets.each {|s|
|
sockets.each {|s|
|
||||||
s.close if !s.closed?
|
s.close if !s.closed?
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# creates a new socket connected to path using UNIX socket socket.
|
# creates a new socket connected to path using UNIX socket socket.
|
||||||
#
|
#
|
||||||
@ -328,6 +372,25 @@ class Socket
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# creates UNIX server sockets on _path_
|
||||||
|
#
|
||||||
|
# It returns a listening socket.
|
||||||
|
#
|
||||||
|
# socket = Socket.unix_server_socket("/tmp/s")
|
||||||
|
# p socket #=> #<Socket:fd 3>
|
||||||
|
# p socket.local_address #=> #<AddrInfo: /tmp/s SOCK_STREAM>
|
||||||
|
#
|
||||||
|
def self.unix_server_socket(path)
|
||||||
|
begin
|
||||||
|
st = File.lstat(path)
|
||||||
|
rescue Errno::ENOENT
|
||||||
|
end
|
||||||
|
if st && st.socket? && st.owned?
|
||||||
|
File.unlink path
|
||||||
|
end
|
||||||
|
AddrInfo.unix(path).listen
|
||||||
|
end
|
||||||
|
|
||||||
# creates a UNIX socket server on _path_.
|
# creates a UNIX socket server on _path_.
|
||||||
# It calls the block for each socket accepted.
|
# It calls the block for each socket accepted.
|
||||||
#
|
#
|
||||||
@ -352,19 +415,9 @@ class Socket
|
|||||||
# end
|
# end
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
def self.unix_server_loop(path) # :yield: socket, client_addrinfo
|
def self.unix_server_loop(path, &b) # :yield: socket, client_addrinfo
|
||||||
begin
|
serv = unix_server_socket(path)
|
||||||
st = File.lstat(path)
|
accept_loop(serv, &b)
|
||||||
rescue Errno::ENOENT
|
|
||||||
end
|
|
||||||
if st && st.socket? && st.owned?
|
|
||||||
File.unlink path
|
|
||||||
end
|
|
||||||
serv = AddrInfo.unix(path).listen
|
|
||||||
loop {
|
|
||||||
sock, addr = serv.accept
|
|
||||||
yield sock, addr
|
|
||||||
}
|
|
||||||
ensure
|
ensure
|
||||||
serv.close if serv && !serv.closed?
|
serv.close if serv && !serv.closed?
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user