Class Socket
provides access to the underlying operating
system socket implementations. It can be used to provide more operating
system specific functionality than the protocol-specific socket classes but
at the expense of greater complexity. In particular, the class handles
addresses using +struct sockaddr+ structures packed into Ruby strings,
which can be a joy to manipulate.
Ruby's implementation of Socket
causes an exception to be
raised based on the error generated by the system dependent implementation.
This is why the methods are documented in a way that isolate Unix-based
system exceptions from Windows based exceptions. If more information on
particular exception is needed please refer to the Unix manual pages or
the Windows WinSock reference.
Zach Dennis
Sam Roberts
Programming Ruby from The Pragmatic Bookshelf.
Much material in this documentation is taken with permission from
Programming Ruby from The Pragmatic Bookshelf.
Return address information for host
and port
. The
remaining arguments are hints that limit the address information returned.
This method corresponds closely to the POSIX.1g getaddrinfo() definition.
host
is a host name or an address string (dotted decimal for
IPv4, or a hex string for IPv6) for which to return information. A nil is
also allowed, its meaning depends on flags
, see below.
service
is a service name (“http”, “ssh”, …), or a port
number (80, 22, …), see ::getservbyname for more
information. A nil is also allowed, meaning zero.
family
limits the output to a specific address family, one of
the Socket::AF_* constants. Socket::AF_INET (IPv4) and Socket::AF_INET6
(IPv6) are the most commonly used families. You will usually pass either
nil or Socket::AF_UNSPEC, allowing the IPv6 information to be returned
first if host
is reachable via IPv6, and IPv4 information
otherwise. The two strings “AF_INET” or “AF_INET6” are also allowed, they
are converted to their respective Socket::AF_* constants.
socktype
limits the output to a specific type of socket, one
of the Socket::SOCK_* constants. Socket::SOCK_STREAM (for TCP) and
Socket::SOCK_DGRAM (for UDP) are the most commonly used socket types. If
nil, then information for all types of sockets supported by
service
will be returned. You will usually know what type of
socket you intend to create, and should pass that socket type in.
protocol
limits the output to a specific protocol numpber, one
of the Socket::IPPROTO_* constants. It is usually implied by the socket
type (Socket::SOCK_STREAM => Socket::IPPROTO_TCP, …), if you pass other
than nil you already know what this is for.
flags
is one of the Socket::AI_* constants. They mean:
Socket::AI_PASSIVE: when set, if host
is nil the 'any'
address will be returned, Socket::INADDR_ANY or 0 for IPv4, “0::0” or “::”
for IPv6. This address is suitable for use by servers that will bind their
socket and do a passive listen, thus the name of the flag. Otherwise the
local or loopback address will be returned, this is “127.0.0.1” for IPv4
and “::1' for IPv6.
…
Returns an array of arrays, where each subarray contains:
address family, a string like “AF_INET” or “AF_INET6”
port number, the port number for service
host name, either a canonical name for host
, or it's
address in presentation format if the address could not be looked up.
host IP, the address of host
in presentation format
address family, as a numeric value (one of the Socket::AF_* constants).
socket type, as a numeric value (one of the Socket::SOCK_* constants).
protocol number, as a numeric value (one of the Socket::IPPROTO_* constants).
The first four values are identical to what is commonly returned as an address array, see IPSocket for more information.
Not all input combinations are valid, and while there are many combinations, only a few cases are common.
A typical client will call getaddrinfo with the host
and
service
it wants to connect to. It knows that it will attempt
to connect with either TCP or UDP, and specifies socktype
accordingly. It loops through all returned addresses, and try to connect to
them in turn:
addrinfo = Socket::getaddrinfo('www.example.com', 'www', nil, Socket::SOCK_STREAM) addrinfo.each do |af, port, name, addr| begin sock = TCPSocket.new(addr, port) # ... exit 1 rescue end end
With UDP you don't know if connect suceeded, but if communication fails, the next address can be tried.
A typical server will call getaddrinfo with a host
of nil, the
service
it listens to, and a flags
of
Socket::AI_PASSIVE. It will listen for connections on the first returned
address:
addrinfo = Socket::getaddrinfo(nil, 'www', nil, Socket::SOCK_STREAM, nil, Socket::AI_PASSIVE) af, port, name, addr = addrinfo.first sock = TCPServer(addr, port) while( client = s.accept ) # ... end
static VALUE sock_s_getaddrinfo(argc, argv) int argc; VALUE *argv; { VALUE host, port, family, socktype, protocol, flags, ret; char hbuf[1024], pbuf[1024]; char *hptr, *pptr, *ap; struct addrinfo hints, *res; int error; host = port = family = socktype = protocol = flags = Qnil; rb_scan_args(argc, argv, "24", &host, &port, &family, &socktype, &protocol, &flags); if (NIL_P(host)) { hptr = NULL; } else { strncpy(hbuf, StringValuePtr(host), sizeof(hbuf)); hbuf[sizeof(hbuf) - 1] = '\0'; hptr = hbuf; } if (NIL_P(port)) { pptr = NULL; } else if (FIXNUM_P(port)) { snprintf(pbuf, sizeof(pbuf), "%ld", FIX2LONG(port)); pptr = pbuf; } else { strncpy(pbuf, StringValuePtr(port), sizeof(pbuf)); pbuf[sizeof(pbuf) - 1] = '\0'; pptr = pbuf; } MEMZERO(&hints, struct addrinfo, 1); if (NIL_P(family)) { hints.ai_family = PF_UNSPEC; } else if (FIXNUM_P(family)) { hints.ai_family = FIX2INT(family); } else if ((ap = StringValuePtr(family)) != 0) { if (strcmp(ap, "AF_INET") == 0) { hints.ai_family = PF_INET; } #ifdef INET6 else if (strcmp(ap, "AF_INET6") == 0) { hints.ai_family = PF_INET6; } #endif } if (!NIL_P(socktype)) { hints.ai_socktype = NUM2INT(socktype); } if (!NIL_P(protocol)) { hints.ai_protocol = NUM2INT(protocol); } if (!NIL_P(flags)) { hints.ai_flags = NUM2INT(flags); } error = getaddrinfo(hptr, pptr, &hints, &res); if (error) { rb_raise(rb_eSocket, "getaddrinfo: %s", gai_strerror(error)); } ret = make_addrinfo(res); freeaddrinfo(res); return ret; }
static VALUE sock_s_gethostbyaddr(argc, argv) int argc; VALUE *argv; { VALUE addr, type; struct hostent *h; struct sockaddr *sa; char **pch; VALUE ary, names; int t = AF_INET; rb_scan_args(argc, argv, "11", &addr, &type); sa = (struct sockaddr*)StringValuePtr(addr); if (!NIL_P(type)) { t = NUM2INT(type); } #ifdef INET6 else if (RSTRING(addr)->len == 16) { t = AF_INET6; } #endif h = gethostbyaddr(RSTRING(addr)->ptr, RSTRING(addr)->len, 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; }
Resolve host
and return name and address information for it,
similarly to gethostbyname(3). host
can be a domain name or
the presentation format of an address.
Returns an array of information similar to that found in a +struct hostent+:
- cannonical name: the cannonical name for host in the DNS, or a string representing the address - aliases: an array of aliases for the canonical name, there may be no aliases - address family: usually one of Socket::AF_INET or Socket::AF_INET6 - address: a string, the binary value of the +struct sockaddr+ for this name, in the indicated address family - ...: if there are multiple addresses for this host, a series of strings/+struct sockaddr+s may follow, not all necessarily in the same address family. Note that the fact that they may not be all in the same address family is a departure from the behaviour of gethostbyname(3).
Note: I believe that the fact that the multiple addresses returned are not necessarily in the same address family may be a bug, since if this function actually called gethostbyname(3), ALL the addresses returned in the trailing address list (h_addr_list from struct hostent) would be of the same address family! Examples from my system, OS X 10.3:
["localhost", [], 30, "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001", "\177\000\000\001"] and ["ensemble.local", [], 30, "\376\200\000\004\000\000\000\000\002\003\223\377\376\255\010\214", "\300\250{\232" ]
Similar information can be returned by ::getaddrinfo if called as:
Socket.getaddrinfo(+host+, 0, Socket::AF_UNSPEC, Socket::SOCK_STREAM, nil, Socket::AI_CANONNAME)
Socket.gethostbyname "example.com" => ["example.com", [], 2, "\300\000\"\246"]
This name has no DNS aliases, and a single IPv4 address.
Socket.gethostbyname "smtp.telus.net" => ["smtp.svc.telus.net", ["smtp.telus.net"], 2, "\307\271\334\371"]
This name is an an alias so the canonical name is returned, as well as the alias and a single IPv4 address.
Socket.gethostbyname "localhost" => ["localhost", [], 30, "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001", "\177\000\000\001"]
This machine has no aliases, returns an IPv6 address, and has an additional IPv4 address.
host
can also be an IP address in presentation format, in
which case a reverse lookup is done on the address:
Socket.gethostbyname("127.0.0.1") => ["localhost", [], 2, "\177\000\000\001"] Socket.gethostbyname("192.0.34.166") => ["www.example.com", [], 2, "\300\000\"\246"]
See: ::getaddrinfo
static VALUE sock_s_gethostbyname(obj, host) VALUE obj, host; { rb_secure(3); return make_hostent(host, sock_addrinfo(host, Qnil, SOCK_STREAM, AI_CANONNAME), sock_sockaddr); }
static VALUE sock_gethostname(obj) VALUE obj; { char buf[1024]; rb_secure(3); if (gethostname(buf, (int)sizeof buf - 1) < 0) rb_sys_fail("gethostname"); buf[sizeof buf - 1] = '\0'; return rb_str_new2(buf); }
static VALUE sock_s_getnameinfo(argc, argv) int argc; VALUE *argv; { VALUE sa, af = Qnil, host = Qnil, port = Qnil, flags, tmp; char *hptr, *pptr; char hbuf[1024], pbuf[1024]; int fl; struct addrinfo hints, *res = NULL, *r; int error; struct sockaddr_storage ss; struct sockaddr *sap; char *ap; sa = flags = Qnil; rb_scan_args(argc, argv, "11", &sa, &flags); fl = 0; if (!NIL_P(flags)) { fl = NUM2INT(flags); } tmp = rb_check_string_type(sa); if (!NIL_P(tmp)) { sa = tmp; if (sizeof(ss) < RSTRING(sa)->len) { rb_raise(rb_eTypeError, "sockaddr length too big"); } memcpy(&ss, RSTRING(sa)->ptr, RSTRING(sa)->len); if (RSTRING(sa)->len != SA_LEN((struct sockaddr*)&ss)) { rb_raise(rb_eTypeError, "sockaddr size differs - should not happen"); } sap = (struct sockaddr*)&ss; goto call_nameinfo; } tmp = rb_check_array_type(sa); if (!NIL_P(tmp)) { sa = tmp; MEMZERO(&hints, struct addrinfo, 1); if (RARRAY(sa)->len == 3) { af = RARRAY(sa)->ptr[0]; port = RARRAY(sa)->ptr[1]; host = RARRAY(sa)->ptr[2]; } else if (RARRAY(sa)->len >= 4) { af = RARRAY(sa)->ptr[0]; port = RARRAY(sa)->ptr[1]; host = RARRAY(sa)->ptr[3]; if (NIL_P(host)) { host = RARRAY(sa)->ptr[2]; } else { /* * 4th element holds numeric form, don't resolve. * see ipaddr(). */ #ifdef AI_NUMERICHOST /* AIX 4.3.3 doesn't have AI_NUMERICHOST. */ hints.ai_flags |= AI_NUMERICHOST; #endif } } else { rb_raise(rb_eArgError, "array size should be 3 or 4, %ld given", RARRAY(sa)->len); } /* host */ if (NIL_P(host)) { hptr = NULL; } else { strncpy(hbuf, StringValuePtr(host), sizeof(hbuf)); hbuf[sizeof(hbuf) - 1] = '\0'; hptr = hbuf; } /* port */ if (NIL_P(port)) { strcpy(pbuf, "0"); pptr = NULL; } else if (FIXNUM_P(port)) { snprintf(pbuf, sizeof(pbuf), "%ld", NUM2LONG(port)); pptr = pbuf; } else { strncpy(pbuf, StringValuePtr(port), sizeof(pbuf)); pbuf[sizeof(pbuf) - 1] = '\0'; pptr = pbuf; } hints.ai_socktype = (fl & NI_DGRAM) ? SOCK_DGRAM : SOCK_STREAM; /* af */ if (NIL_P(af)) { hints.ai_family = PF_UNSPEC; } else if (FIXNUM_P(af)) { hints.ai_family = FIX2INT(af); } else if ((ap = StringValuePtr(af)) != 0) { if (strcmp(ap, "AF_INET") == 0) { hints.ai_family = PF_INET; } #ifdef INET6 else if (strcmp(ap, "AF_INET6") == 0) { hints.ai_family = PF_INET6; } #endif } error = getaddrinfo(hptr, pptr, &hints, &res); if (error) goto error_exit_addr; sap = res->ai_addr; } else { rb_raise(rb_eTypeError, "expecting String or Array"); } call_nameinfo: error = getnameinfo(sap, SA_LEN(sap), hbuf, sizeof(hbuf), pbuf, sizeof(pbuf), fl); if (error) goto error_exit_name; if (res) { for (r = res->ai_next; r; r = r->ai_next) { char hbuf2[1024], pbuf2[1024]; sap = r->ai_addr; error = getnameinfo(sap, SA_LEN(sap), hbuf2, sizeof(hbuf2), pbuf2, sizeof(pbuf2), fl); if (error) goto error_exit_name; if (strcmp(hbuf, hbuf2) != 0|| strcmp(pbuf, pbuf2) != 0) { freeaddrinfo(res); rb_raise(rb_eSocket, "sockaddr resolved to multiple nodename"); } } freeaddrinfo(res); } return rb_assoc_new(rb_str_new2(hbuf), rb_str_new2(pbuf)); error_exit_addr: if (res) freeaddrinfo(res); rb_raise(rb_eSocket, "getaddrinfo: %s", gai_strerror(error)); error_exit_name: if (res) freeaddrinfo(res); rb_raise(rb_eSocket, "getnameinfo: %s", gai_strerror(error)); }
name
is a service name (“ftp”, “telnet”, …) and proto is a
protocol name (“udp”, “tcp”, …). '/etc/services' (or your
system's equivalent) is searched for a service for name
and proto
, and the port number is returned.
Note that unlike ::getaddrinfo,
proto
may not be specified using the Socket::SOCK_* constants,
a string must must be used.
static VALUE sock_s_getservbyaname(argc, argv) int argc; VALUE *argv; { VALUE service, proto; struct servent *sp; int port; rb_scan_args(argc, argv, "11", &service, &proto); if (NIL_P(proto)) proto = rb_str_new2("tcp"); StringValue(service); StringValue(proto); sp = getservbyname(StringValueCStr(service), StringValueCStr(proto)); if (sp) { port = ntohs(sp->s_port); } else { char *s = RSTRING(service)->ptr; char *end; port = strtoul(s, &end, 0); if (*end != '\0') { rb_raise(rb_eSocket, "no such service %s/%s", s, RSTRING(proto)->ptr); } } return INT2FIX(port); }
static VALUE sock_initialize(sock, domain, type, protocol) VALUE sock, domain, type, protocol; { int fd; int d, t; rb_secure(3); setup_domain_and_type(domain, &d, type, &t); fd = ruby_socket(d, t, NUM2INT(protocol)); if (fd < 0) rb_sys_fail("socket(2)"); return init_sock(sock, fd); }
static VALUE sock_s_pack_sockaddr_in(self, port, host) VALUE self, port, host; { struct addrinfo *res = sock_addrinfo(host, port, 0, 0); VALUE addr = rb_str_new((char*)res->ai_addr, res->ai_addrlen); freeaddrinfo(res); OBJ_INFECT(addr, port); OBJ_INFECT(addr, host); return addr; }
static VALUE sock_s_pack_sockaddr_un(self, path) VALUE self, path; { struct sockaddr_un sockaddr; char *sun_path; VALUE addr; MEMZERO(&sockaddr, struct sockaddr_un, 1); sockaddr.sun_family = AF_UNIX; sun_path = StringValueCStr(path); if (sizeof(sockaddr.sun_path) <= strlen(sun_path)) { rb_raise(rb_eArgError, "too long unix socket path (max: %dbytes)", (int)sizeof(sockaddr.sun_path)-1); } strncpy(sockaddr.sun_path, sun_path, sizeof(sockaddr.sun_path)-1); addr = rb_str_new((char*)&sockaddr, sizeof(sockaddr)); OBJ_INFECT(addr, path); return addr; }
static VALUE sock_s_socketpair(klass, domain, type, protocol) VALUE klass, domain, type, protocol; { #if defined HAVE_SOCKETPAIR int d, t, p, sp[2]; int ret; setup_domain_and_type(domain, &d, type, &t); p = NUM2INT(protocol); ret = socketpair(d, t, p, sp); if (ret < 0 && (errno == EMFILE || errno == ENFILE)) { rb_gc(); ret = socketpair(d, t, p, sp); } if (ret < 0) { rb_sys_fail("socketpair(2)"); } return rb_assoc_new(init_sock(rb_obj_alloc(klass), sp[0]), init_sock(rb_obj_alloc(klass), sp[1])); #else rb_notimplement(); #endif }
static VALUE sock_s_pack_sockaddr_in(self, port, host) VALUE self, port, host; { struct addrinfo *res = sock_addrinfo(host, port, 0, 0); VALUE addr = rb_str_new((char*)res->ai_addr, res->ai_addrlen); freeaddrinfo(res); OBJ_INFECT(addr, port); OBJ_INFECT(addr, host); return addr; }
static VALUE sock_s_pack_sockaddr_un(self, path) VALUE self, path; { struct sockaddr_un sockaddr; char *sun_path; VALUE addr; MEMZERO(&sockaddr, struct sockaddr_un, 1); sockaddr.sun_family = AF_UNIX; sun_path = StringValueCStr(path); if (sizeof(sockaddr.sun_path) <= strlen(sun_path)) { rb_raise(rb_eArgError, "too long unix socket path (max: %dbytes)", (int)sizeof(sockaddr.sun_path)-1); } strncpy(sockaddr.sun_path, sun_path, sizeof(sockaddr.sun_path)-1); addr = rb_str_new((char*)&sockaddr, sizeof(sockaddr)); OBJ_INFECT(addr, path); return addr; }
static VALUE sock_s_socketpair(klass, domain, type, protocol) VALUE klass, domain, type, protocol; { #if defined HAVE_SOCKETPAIR int d, t, p, sp[2]; int ret; setup_domain_and_type(domain, &d, type, &t); p = NUM2INT(protocol); ret = socketpair(d, t, p, sp); if (ret < 0 && (errno == EMFILE || errno == ENFILE)) { rb_gc(); ret = socketpair(d, t, p, sp); } if (ret < 0) { rb_sys_fail("socketpair(2)"); } return rb_assoc_new(init_sock(rb_obj_alloc(klass), sp[0]), init_sock(rb_obj_alloc(klass), sp[1])); #else rb_notimplement(); #endif }
static VALUE sock_s_unpack_sockaddr_in(self, addr) VALUE self, addr; { struct sockaddr_in * sockaddr; VALUE host; sockaddr = (struct sockaddr_in*)StringValuePtr(addr); 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 = make_ipaddr((struct sockaddr*)sockaddr); OBJ_INFECT(host, addr); return rb_assoc_new(INT2NUM(ntohs(sockaddr->sin_port)), host); }
static VALUE sock_s_unpack_sockaddr_un(self, addr) VALUE self, addr; { struct sockaddr_un * sockaddr; char *sun_path; VALUE path; sockaddr = (struct sockaddr_un*)StringValuePtr(addr); if (((struct sockaddr *)sockaddr)->sa_family != AF_UNIX) { rb_raise(rb_eArgError, "not an AF_UNIX sockaddr"); } if (sizeof(struct sockaddr_un) < RSTRING(addr)->len) { rb_raise(rb_eTypeError, "too long sockaddr_un - %ld longer than %d", RSTRING(addr)->len, sizeof(struct sockaddr_un)); } sun_path = unixpath(sockaddr, RSTRING(addr)->len); if (sizeof(struct sockaddr_un) == RSTRING(addr)->len && sun_path == sockaddr->sun_path && sun_path + strlen(sun_path) == RSTRING(addr)->ptr + RSTRING(addr)->len) { rb_raise(rb_eArgError, "sockaddr_un.sun_path not NUL terminated"); } path = rb_str_new2(sun_path); OBJ_INFECT(path, addr); return path; }
Accepts an incoming connection returning an array containing a new Socket object and a string holding the
struct
sockaddr information about the caller.
# 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, client_sockaddr = socket.accept puts "The client said, '#{client.readline.chomp}'" client.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
On unix-based based systems the following system exceptions may be raised if the call to accept fails:
Errno::EAGAIN - O_NONBLOCK is set for the socket
file
descriptor and no connections are parent to be accepted
Errno::EWOULDBLOCK - same as Errno::EAGAIN
Errno::EBADF - the socket
is not a valid file descriptor
Errno::ECONNABORTED - a connection has been aborted
Errno::EFAULT - the socket's internal address or address length parameter cannot be access or written
Errno::EINTR - the accept method was interrupted by a signal that was caught before a valid connection arrived
Errno::EINVAL - the socket
is not accepting connections
Errno::EMFILE - OPEN_MAX file descriptors are currently open in the calling process
Errno::ENOBUFS - no buffer space is available
Errno::ENOMEM - there was insufficient memory available to complete the operation
Errno::ENOSR - there was insufficient STREAMS resources available to complete the operation
Errno::ENFILE - the maximum number of file descriptors in the system are already open
Errno::ENOTSOCK - the socket
does not refer to a socket
Errno::EOPNOTSUPP - the socket type for the calling socket
does not support accept connections
Errno::EPROTO - a protocol error has occurred
On Windows systems the following system exceptions may be raised if the call to accept fails:
Errno::ECONNRESET - an incoming connection was indicated, but was terminated by the remote peer prior to accepting the connection
Errno::EFAULT - the socket's internal address or address length parameter is too small or is not a valid part of the user space address
Errno::EINVAL - the listen method was not invoked prior to calling accept
Errno::EINPROGRESS - a blocking Windows Sockets 1.1 call is in progress or the service provider is still processing a callback function
Errno::EMFILE - the queue is not empty, upong etry to accept and there are no socket descriptors available
Errno::ENETDOWN - the network is down
Errno::ENOBUFS - no buffer space is available
Errno::ENOTSOCK - socket
is not a socket
Errno::EOPNOTSUPP - socket
is not a type that supports
connection-oriented service.
Errno::EWOULDBLOCK - socket
is marked as nonblocking and no
connections are present to be accepted
accept manual pages on unix-based systems
accept function in Microsoft's Winsock functions reference
static VALUE sock_accept(sock) VALUE sock; { OpenFile *fptr; VALUE sock2; char buf[1024]; socklen_t len = sizeof buf; GetOpenFile(sock, fptr); sock2 = s_accept(rb_cSocket,fileno(fptr->f),(struct sockaddr*)buf,&len); return rb_assoc_new(sock2, rb_str_new(buf, len)); }
Accepts an incoming connection using accept(2) after O_NONBLOCK is set for
the underlying file descriptor. It returns an array containg the accpeted
socket for the incoming connection, client_socket, and a string
that contains the struct
sockaddr information about the
caller, client_sockaddr.
# 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 client_socket, client_sockaddr = socket.accept_nonblock rescue Errno::EAGAIN, Errno::ECONNABORTED, Errno::EPROTO, 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
Refer to #accept for the exceptions that may be thrown if the call to accept_nonblock fails.
#accept_nonblock may raise any error corresponding to accept(2) failure, including Errno::EAGAIN.
static VALUE sock_accept_nonblock(sock) VALUE sock; { OpenFile *fptr; VALUE sock2; char buf[1024]; socklen_t len = sizeof buf; GetOpenFile(sock, fptr); sock2 = s_accept_nonblock(rb_cSocket, fptr, (struct sockaddr *)buf, &len); return rb_assoc_new(sock2, rb_str_new(buf, len)); }
Binds to the given struct
sockaddr.
server_sockaddr
- the struct
sockaddr contained
in a string
require 'socket' include Socket::Constants socket = Socket.new( AF_INET, SOCK_STREAM, 0 ) sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' ) socket.bind( sockaddr )
On unix-based based systems the following system exceptions may be raised if the call to bind fails:
Errno::EACCES - the specified sockaddr is protected and the current user does not have permission to bind to it
Errno::EADDRINUSE - the specified sockaddr is already in use
Errno::EADDRNOTAVAIL - the specified sockaddr is not available from the local machine
Errno::EAFNOSUPPORT - the specified sockaddr isnot a valid address
for the family of the calling socket
Errno::EBADF - the sockaddr specified is not a valid file descriptor
Errno::EFAULT - the sockaddr argument cannot be accessed
Errno::EINVAL - the socket
is already bound to an address, and
the protocol does not support binding to the new sockaddr or the
socket
has been shut down.
Errno::EINVAL - the address length is not a valid length for the address family
Errno::ENAMETOOLONG - the pathname resolved had a length which exceeded PATH_MAX
Errno::ENOBUFS - no buffer space is available
Errno::ENOSR - there were insufficient STREAMS resources available to complete the operation
Errno::ENOTSOCK - the socket
does not refer to a socket
Errno::EOPNOTSUPP - the socket type of the socket
does not
support binding to an address
On unix-based based systems if the address family of the calling
socket
is Socket::AF_UNIX the follow exceptions may be raised
if the call to bind fails:
Errno::EACCES - search permission is denied for a component of the prefix
path or write access to the socket
is denided
Errno::EDESTADDRREQ - the sockaddr argument is a null pointer
Errno::EISDIR - same as Errno::EDESTADDRREQ
Errno::EIO - an i/o error occurred
Errno::ELOOP - too many symbolic links were encountered in translating the pathname in sockaddr
Errno::ENAMETOOLLONG - a component of a pathname exceeded NAME_MAX characters, or an entired pathname exceeded PATH_MAX characters
Errno::ENOENT - a component of the pathname does not name an existing file or the pathname is an empty string
Errno::ENOTDIR - a component of the path prefix of the pathname in sockaddr is not a directory
Errno::EROFS - the name would reside on a read only filesystem
On Windows systems the following system exceptions may be raised if the call to bind fails:
Errno::ENETDOWN– the network is down
Errno::EACCES - the attempt to connect the datagram socket to the broadcast address failed
Errno::EADDRINUSE - the socket's local address is already in use
Errno::EADDRNOTAVAIL - the specified address is not a valid address for this computer
Errno::EFAULT - the socket's internal address or address length parameter is too small or is not a valid part of the user space addressed
Errno::EINVAL - the socket
is already bound to an address
Errno::ENOBUFS - no buffer space is available
Errno::ENOTSOCK - the socket
argument does not refer to a
socket
bind manual pages on unix-based systems
bind function in Microsoft's Winsock functions reference
static VALUE sock_bind(sock, addr) VALUE sock, addr; { OpenFile *fptr; StringValue(addr); GetOpenFile(sock, fptr); if (bind(fileno(fptr->f), (struct sockaddr*)RSTRING(addr)->ptr, RSTRING(addr)->len) < 0) rb_sys_fail("bind(2)"); return INT2FIX(0); }
Requests a connection to be made on the given server_sockaddr
.
Returns 0 if successful, otherwise an exception is raised.
server_sockaddr
- the struct
sockaddr contained
in a string
# 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
On unix-based systems the following system exceptions may be raised if the call to connect fails:
Errno::EACCES - search permission is denied for a component of the prefix
path or write access to the socket
is denided
Errno::EADDRINUSE - the sockaddr is already in use
Errno::EADDRNOTAVAIL - the specified sockaddr is not available from the local machine
Errno::EAFNOSUPPORT - the specified sockaddr is not a valid
address for the address family of the specified socket
Errno::EALREADY - a connection is already in progress for the specified socket
Errno::EBADF - the socket
is not a valid file descriptor
Errno::ECONNREFUSED - the target sockaddr was not listening for connections refused the connection request
Errno::ECONNRESET - the remote host reset the connection request
Errno::EFAULT - the sockaddr cannot be accessed
Errno::EHOSTUNREACH - the destination host cannot be reached (probably because the host is down or a remote router cannot reach it)
Errno::EINPROGRESS - the O_NONBLOCK is set for the socket
and
the connection cnanot be immediately established; the connection will be
established asynchronously
Errno::EINTR - the attempt to establish the connection was interrupted by delivery of a signal that was caught; the connection will be established asynchronously
Errno::EISCONN - the specified socket
is already connected
Errno::EINVAL - the address length used for the sockaddr is not a valid length for the address family or there is an invalid family in sockaddr
Errno::ENAMETOOLONG - the pathname resolved had a length which exceeded PATH_MAX
Errno::ENETDOWN - the local interface used to reach the destination is down
Errno::ENETUNREACH - no route to the network is present
Errno::ENOBUFS - no buffer space is available
Errno::ENOSR - there were insufficient STREAMS resources available to complete the operation
Errno::ENOTSOCK - the socket
argument does not refer to a
socket
Errno::EOPNOTSUPP - the calling socket
is listening and cannot
be connected
Errno::EPROTOTYPE - the sockaddr has a different type than the socket bound to the specified peer address
Errno::ETIMEDOUT - the attempt to connect time out before a connection was made.
On unix-based systems if the address family of the calling
socket
is AF_UNIX the follow exceptions may be raised if the
call to connect fails:
Errno::EIO - an i/o error occured while reading from or writing to the file system
Errno::ELOOP - too many symbolic links were encountered in translating the pathname in sockaddr
Errno::ENAMETOOLLONG - a component of a pathname exceeded NAME_MAX characters, or an entired pathname exceeded PATH_MAX characters
Errno::ENOENT - a component of the pathname does not name an existing file or the pathname is an empty string
Errno::ENOTDIR - a component of the path prefix of the pathname in sockaddr is not a directory
On Windows systems the following system exceptions may be raised if the call to connect fails:
Errno::ENETDOWN - the network is down
Errno::EADDRINUSE - the socket's local address is already in use
Errno::EINTR - the socket was cancelled
Errno::EINPROGRESS - a blocking socket is in progress or the service
provider is still processing a callback function. Or a nonblocking connect
call is in progress on the socket
.
Errno::EALREADY - see Errno::EINVAL
Errno::EADDRNOTAVAIL - the remote address is not a valid address, such as ADDR_ANY TODO check ADDRANY TO INADDR_ANY
Errno::EAFNOSUPPORT - addresses in the specified family cannot be used with
with this socket
Errno::ECONNREFUSED - the target sockaddr was not listening for connections refused the connection request
Errno::EFAULT - the socket's internal address or address length parameter is too small or is not a valid part of the user space address
Errno::EINVAL - the socket
is a listening socket
Errno::EISCONN - the socket
is already connected
Errno::ENETUNREACH - the network cannot be reached from this host at this time
Errno::EHOSTUNREACH - no route to the network is present
Errno::ENOBUFS - no buffer space is available
Errno::ENOTSOCK - the socket
argument does not refer to a
socket
Errno::ETIMEDOUT - the attempt to connect time out before a connection was made.
Errno::EWOULDBLOCK - the socket is marked as nonblocking and the connection cannot be completed immediately
Errno::EACCES - the attempt to connect the datagram socket to the broadcast address failed
connect manual pages on unix-based systems
connect function in Microsoft's Winsock functions reference
static VALUE sock_connect(sock, addr) VALUE sock, addr; { OpenFile *fptr; int fd; StringValue(addr); addr = rb_str_new4(addr); GetOpenFile(sock, fptr); fd = fileno(fptr->f); if (ruby_connect(fd, (struct sockaddr*)RSTRING(addr)->ptr, RSTRING(addr)->len, 0) < 0) { rb_sys_fail("connect(2)"); } return INT2FIX(0); }
Requests a connection to be made on the given server_sockaddr
after O_NONBLOCK is set for the underlying file descriptor. Returns 0 if
successful, otherwise an exception is raised.
server_sockaddr
- the struct
sockaddr contained
in a string
# 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 socket.connect_nonblock(sockaddr) rescue Errno::EINPROGRESS IO.select(nil, [socket]) begin socket.connect_nonblock(sockaddr) rescue Errno::EISCONN end end socket.write("GET / HTTP/1.0\r\n\r\n") results = socket.read
Refer to #connect for the exceptions that may be thrown if the call to connect_nonblock fails.
#connect_nonblock may raise any error corresponding to connect(2) failure, including Errno::EINPROGRESS.
static VALUE sock_connect_nonblock(sock, addr) VALUE sock, addr; { OpenFile *fptr; int n; StringValue(addr); addr = rb_str_new4(addr); GetOpenFile(sock, fptr); rb_io_set_nonblock(fptr); n = connect(fileno(fptr->f), (struct sockaddr*)RSTRING(addr)->ptr, RSTRING(addr)->len); if (n < 0) { rb_sys_fail("connect(2)"); } return INT2FIX(n); }
Listens for connections, using the specified int
as the
backlog. A call to listen only applies if the socket
is of type SOCK_STREAM or SOCK_SEQPACKET.
backlog
- the maximum length of the queue for pending
connections.
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 )
require 'socket' include Socket::Constants socket = Socket.new( AF_INET, SOCK_STREAM, 0 ) socket.listen( 1 )
On unix based systems the above will work because a new
sockaddr
struct is created on the address ADDR_ANY, for an
arbitrary port number as handed off by the kernel. It will not work on
Windows, because Windows requires that the socket
is bound by
calling bind before it can listen.
If the backlog amount exceeds the implementation-dependent maximum queue length, the implementation's maximum queue length will be used.
On unix-based based systems the following system exceptions may be raised if the call to listen fails:
Errno::EBADF - the socket argument is not a valid file descriptor
Errno::EDESTADDRREQ - the socket is not bound to a local address, and the protocol does not support listening on an unbound socket
Errno::EINVAL - the socket is already connected
Errno::ENOTSOCK - the socket argument does not refer to a socket
Errno::EOPNOTSUPP - the socket protocol does not support listen
Errno::EACCES - the calling process does not have approriate privileges
Errno::EINVAL - the socket has been shut down
Errno::ENOBUFS - insufficient resources are available in the system to complete the call
On Windows systems the following system exceptions may be raised if the call to listen fails:
Errno::ENETDOWN - the network is down
Errno::EADDRINUSE - the socket's local address is already in use. This usually occurs during the execution of bind but could be delayed if the call to bind was to a partially wildcard address (involving ADDR_ANY) and if a specific address needs to be commmitted at the time of the call to listen
Errno::EINPROGRESS - a Windows Sockets 1.1 call is in progress or the service provider is still processing a callback function
Errno::EINVAL - the socket
has not been bound with a call to
bind.
Errno::EISCONN - the socket
is already connected
Errno::EMFILE - no more socket descriptors are available
Errno::ENOBUFS - no buffer space is available
Errno::ENOTSOC - socket
is not a socket
Errno::EOPNOTSUPP - the referenced socket
is not a type that
supports the listen method
listen manual pages on unix-based systems
listen function in Microsoft's Winsock functions reference
static VALUE sock_listen(sock, log) VALUE sock, log; { OpenFile *fptr; int backlog; rb_secure(4); backlog = NUM2INT(log); GetOpenFile(sock, fptr); if (listen(fileno(fptr->f), backlog) < 0) rb_sys_fail("listen(2)"); return INT2FIX(0); }
Receives up to maxlen bytes from socket
.
flags is zero or more of the MSG_
options. The first
element of the results, mesg, is the data received. The second
element, sender_sockaddr, contains protocol-specific information
on the sender.
maxlen
- the number of bytes to receive from the socket
flags
- zero or more of the MSG_
options
# 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_sockaddr = 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
On unix-based based systems the following system exceptions may be raised if the call to recvfrom fails:
Errno::EAGAIN - the socket
file descriptor is marked as
O_NONBLOCK and no data is waiting to be received; or MSG_OOB is set and no
out-of-band data is available and either the socket
file
descriptor is marked as O_NONBLOCK or the socket
does not
support blocking to wait for out-of-band-data
Errno::EWOULDBLOCK - see Errno::EAGAIN
Errno::EBADF - the socket
is not a valid file descriptor
Errno::ECONNRESET - a connection was forcibly closed by a peer
Errno::EFAULT - the socket's internal buffer, address or address length cannot be accessed or written
Errno::EINTR - a signal interupted recvfrom before any data was available
Errno::EINVAL - the MSG_OOB flag is set and no out-of-band data is available
Errno::EIO - an i/o error occurred while reading from or writing to the filesystem
Errno::ENOBUFS - insufficient resources were available in the system to perform the operation
Errno::ENOMEM - insufficient memory was available to fulfill the request
Errno::ENOSR - there were insufficient STREAMS resources available to complete the operation
Errno::ENOTCONN - a receive is attempted on a connection-mode socket that is not connected
Errno::ENOTSOCK - the socket
does not refer to a socket
Errno::EOPNOTSUPP - the specified flags are not supported for this socket type
Errno::ETIMEDOUT - the connection timed out during connection establishment or due to a transmission timeout on an active connection
On Windows systems the following system exceptions may be raised if the call to recvfrom fails:
Errno::ENETDOWN - the network is down
Errno::EFAULT - the internal buffer and from parameters on
socket
are not part of the user address space, or the internal
fromlen parameter is too small to accomodate the peer address
Errno::EINTR - the (blocking) call was cancelled by an internal call to the WinSock function WSACancelBlockingCall
Errno::EINPROGRESS - a blocking Windows Sockets 1.1 call is in progress or the service provider is still processing a callback function
Errno::EINVAL - socket
has not been bound with a call to
bind, or an unknown flag was specified, or MSG_OOB was specified
for a socket with SO_OOBINLINE enabled, or (for byte stream-style sockets
only) the internal len parameter on socket
was zero or
negative
Errno::EISCONN - socket
is already connected. The call to
recvfrom is not permitted with a connected socket on a socket that
is connetion oriented or connectionless.
Errno::ENETRESET - the connection has been broken due to the keep-alive activity detecting a failure while the operation was in progress.
Errno::EOPNOTSUPP - MSG_OOB was specified, but socket
is not
stream-style such as type SOCK_STREAM. OOB data is not supported in the
communication domain associated with socket
, or
socket
is unidirectional and supports only send operations
Errno::ESHUTDOWN - socket
has been shutdown. It is not
possible to call recvfrom on a socket after shutdown has
been invoked.
Errno::EWOULDBLOCK - socket
is marked as nonblocking and a
call to recvfrom would block.
Errno::EMSGSIZE - the message was too large to fit into the specified buffer and was truncated.
Errno::ETIMEDOUT - the connection has been dropped, because of a network failure or because the system on the other end went down without notice
Errno::ECONNRESET - the virtual circuit was reset by the remote side executing a hard or abortive close. The application should close the socket; it is no longer usable. On a UDP-datagram socket this error indicates a previous send operation resulted in an ICMP Port Unreachable message.
static VALUE sock_recvfrom(argc, argv, sock) int argc; VALUE *argv; VALUE sock; { return s_recvfrom(sock, argc, argv, RECV_SOCKET); }
Receives up to maxlen bytes from socket
using
recvfrom(2) after O_NONBLOCK is set for the underlying file descriptor.
flags is zero or more of the MSG_
options. The first
element of the results, mesg, is the data received. The second
element, sender_sockaddr, contains protocol-specific information
on the sender.
When recvfrom(2) returns 0, #recvfrom_nonblock returns an empty string as data. The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc.
maxlen
- the number of bytes to receive from the socket
flags
- zero or more of the MSG_
options
# 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_sockaddr = socket.accept begin pair = client.recvfrom_nonblock(20) rescue Errno::EAGAIN 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
Refer to #recvfrom for the exceptions that may be thrown if the call to recvfrom_nonblock fails.
#recvfrom_nonblock may raise any error corresponding to recvfrom(2) failure, including Errno::EAGAIN.
static VALUE sock_recvfrom_nonblock(int argc, VALUE *argv, VALUE sock) { return s_recvfrom_nonblock(sock, argc, argv, RECV_SOCKET); }
Accepts an incoming connection returnings an array containg the (integer)
file descriptor for the incoming connection, client_socket_fd, and
a string that contains the struct
sockaddr information about
the caller, client_sockaddr.
# 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_sockaddr = 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
Refer to #accept for the exceptions that may be thrown if the call to sysaccept fails.
static VALUE sock_sysaccept(sock) VALUE sock; { OpenFile *fptr; VALUE sock2; char buf[1024]; socklen_t len = sizeof buf; GetOpenFile(sock, fptr); sock2 = s_accept(0,fileno(fptr->f),(struct sockaddr*)buf,&len); return rb_assoc_new(sock2, rb_str_new(buf, len)); }