Vous êtes sur la page 1sur 10

Chapter (

Server LiIecycIe
A server socket Iistens Ior connections rather than initiating them. The typicaI
IiIecycIe Iooks something Iike this:
. create
z. bind
{. Iisten
(. accept
,. cIose
We covered = in the previous chapter, now we'II continue on with the rest oI the Iist.
Servers Bind Servers Bind
The second step in the IiIecycIe oI a server socket is to bind bind to a port where it wiII
Iisten Ior connections.
26
!"#$%&"'()**&+'",)(%!-,
-&./)-& 0'$#1&+0
2 4)-'+5 #-&6+& 6 (&7 89: '$#1&+!
'$#1&+ ; <$#1&+!(&7=>?@A85 ><8BACDE
2 9-&6+& 6 9 '+-/#+ +$ F$G% +F& 6%%-&'' H$- G)'+&()(I!
6%%- ; <$#1&+!*6#1J'$#16%%-J)(=KKLM5 0N!N!N!N0E
2 O)(% +$ )+!
'$#1&+!,)(%=6%%-E
This is a Iow-IeveI impIementation that shows how to bind a TCP socket to a IocaI
port. In Iact it's aImost identicaI to the C source code you wouId write to accompIish
the same thing.
This particuIar socket has now cIaimed port ((S on the IocaI host. Other sockets wiII
not be abIe to bind to this port, doing so wouId resuIt in an Errno::EADDRINUSE
exception being raised. CIient sockets wiII be abIe to connect to this socket using
this port number, once a Iew more steps have been compIeted.
II you run that code bIock you'II notice that it exits immediateIy. The code works but
doesn't yet do enough to actuaIIy Iisten Ior a connection. Keep reading to see how to
put the server in Iisten mode.
So a server binds to a speciIic, agreed-upon port number which a cIient socket can
then connect to.
OI course, Ruby provides syntactic sugar so that you never have to actuaIIy use
Socket.addr_in or Socket=bind directIy. But beIore Iearning the syntactic sugar it's
important that we see how to do things the hard way.
27
What port shouId I bind to? What port shouId I bind to?
This is an important consideration Ior anyone writing a server. ShouId you
pick a random port number? How can you teII iI some other program has
aIready 'cIaimed' a port as their own?
In terms oI what's possibIe, any port Irom -6,,,{, !"# be used, but there are
important conventions to consider beIore picking a port.
The Iirst ruIe: don't try to use a port in the o-oz( range don't try to use a port in the o-oz( range. These are
considered 'weII-known' ports and are reserved Ior system use. A Iew
exampIes: HTTP traIIic happens on port So, SMTP traIIic happens on port z,,
rsync happens on port S;{. Binding to these ports typicaIIy requires root
access.
The second ruIe: don't use a port in the (,,ooo-6,,,{, range don't use a port in the (,,ooo-6,,,{, range. These are the
ephemeraI ports. They're typicaIIy used by services that don't operate on a
predeIined port number but need ports Ior temporary purposes. They're aIso
an integraI part oI the connection negotiation process we'II see in the next
section. Picking a port above this number might cause conIIicts Ior some oI
your users.
Besides that, any port Irom oz,-(S,,,, is Iair game Ior your uses any port Irom oz,-(S,,,, is Iair game Ior your uses. II you're
pIanning on cIaiming one oI those ports as $%& port Ior your server then you
shouId have a Iook at the IANA Iist oI registered ports
z
and make sure that it
doesn't conIIict with some other popuIar server program out there.
z.https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.txt
28
Binding to Loopback Addresses
One thing to be wary oI when deveIoping your appIications: iI you bind to the
Ioopback host address z;.o.o. then your server socket wiII onIy be abIe to handIe
connections that come Irom that exact same host.
II you want to be abIe to handIe connections Irom "#' host then you shouId bind to
the o.o.o.o address.
!"#$%&"'()**&+'"G$$*,6#1J,)(%)(I!-,
-&./)-& 0'$#1&+0
2 8F)' '$#1&+ 7)GG $(GP ,& 6,G& +$ F6(%G& #$((&#+)$(' H-$Q
2 #G)&(+' $( +F& MRS!N!N!M F$'+!
G$#6GJ'$#1&+ ; <$#1&+!(&7=>?@A85 ><8BACDE
G$#6GJ6%%- ; <$#1&+!*6#1J'$#16%%-J)(=KKLM5 0MRS!N!N!M0E
G$#6GJ'$#1&+!,)(%=G$#6GJ6%%-E
2 8F)' '$#1&+ 7)GG ,& 6,G& +$ F6(%G& #$((&#+)$(' H-$Q 6(P
2 #G)&(+ $( 6(P F$'+!
-&Q$+&J'$#1&+ ; <$#1&+!(&7=>?@A85 ><8BACDE
-&Q$+&J6%%- ; <$#1&+!*6#1J'$#16%%-J)(=KKLM5 0N!N!N!N0E
-&Q$+&J'$#1&+!,)(%=-&Q$+&J6%%-E
Servers Listen Servers Listen
AIter creating a socket, and binding to a port, the socket needs to be toId to Iisten Ior
incoming connections.
29
!"#$%&"'()**&+'"G)'+&(!-,
-&./)-& 0'$#1&+0
2 9-&6+& 6 '$#1&+ 6(% ,)(% )+ +$ *$-+ KKLM!
'$#1&+ ; <$#1&+!(&7=>?@A85 ><8BACDE
6%%- ; <$#1&+!*6#1J'$#16%%-J)(=KKLM5 0N!N!N!N0E
'$#1&+!,)(%=6%%-E
2 8&GG )+ +$ G)'+&( H$- )(#$Q)(I #$((&#+)$('!
'$#1&+!G)'+&(=TE
The onIy addition to the code Irom the Iast chapter is a caII to Iisten on the socket.
II you run that code snippet it stiII exits immediateIy. There's one more step in the
IiIecycIe oI a server socket required beIore it can process connections. That's covered
in the next chapter. First, more about Iisten.
The Listen Queue
You may have noticed that we passed an integer argument to the Iisten method. This
number represents the maximum number oI pending connections your server socket
is wiIIing to toIerate. This Iist oI pending connections is caIIed the Iisten queue the Iisten queue.
Let's say that your server is busy processing a cIient connection, when any new
cIient connections arrive they'II be put into the Iisten queue. II a new cIient
connection arrives and the Iisten queue is IuII then an instance oI
Errno::ECONNREFUSED wiII be raised Ior the cIient.
30
How big shouId the Iisten queue be? How big shouId the Iisten queue be?
OK, so the size oI the Iisten queue Iooks a bit Iike a magic number. Why
wouIdn't we want to set that number to o,ooo? Why wouId we ever want to
reIuse a connection? AII good questions.
First, we shouId taIk about Iimits. You can get the current maximum aIIowed
Iisten queue size by inspecting Socket::SOMAXCONN at runtime. On my Mac this
number is zS. So I'm not abIe to use a number Iarger than that. The root
user is abIe to increase this Iimit at the system IeveI Ior servers that need it.
UItimateIy you don't want to have connections waiting in your Iisten queue
because that means that users oI your service are having to wait Ior their
responses.
Let's say you're running a server and you're getting oI reports oI
Errno::ECONNREFUSED. That's #($ an indication that you need to increase the
size oI your Iisten queue. That wouId be acceptabIe onIy as a temporary
soIution. Rather this wouId be an indication that you need more server
instances or that you need a diIIerent architecture. See the Iast part oI this
book Ior tips on the second part.
So the size oI the Iisten queue depends on your needs and your Iimits.
CeneraIIy you don't want to be reIusing connections, so you can set it to the
maximum aIIowed queue size using server.Iisten(Socket::SOMAXCONN) .
31
Servers Accept Servers Accept
FinaIIy we get to the part oI the IiIecycIe where the server is actuaIIy abIe to handIe
an incoming connection. It does this with the accept method. Here's how we can
create a Iistening socket and receive the Iirst connection:
!"#$%&"'()**&+'"6##&*+!-,
-&./)-& 0'$#1&+0
2 9-&6+& +F& '&-U&- '$#1&+!
'&-U&- ; <$#1&+!(&7=>?@A85 ><8BACDE
6%%- ; <$#1&+!*6#1J'$#16%%-J)(=KKLM5 0N!N!N!N0E
'&-U&-!,)(%=6%%-E
'&-U&-!G)'+&(=<$#1&+>><VDCW9V@@E
2 C##&*+ 6 #$((&#+)$(!
#$((&#+)$(5 J ; '&-U&-!6##&*+
Now iI you run that code you'II notice that it )(&*#+$ return immediateIy! That's right,
the accept method wiII bIock untiI a connection arrives. Let's give it one using netcat:
X &#F$ $F6) Y (# G$#6GF$'+ KKLM
When you run these snippets you shouId see the nc() program and the Ruby
program exit successIuIIy. It may not be the most epic IinaIe ever, but it's prooI that
everything is connected and working properIy. Congrats!
32
Accept is blocking
The accept caII is a bIocking caII. It wiII bIock the current thread indeIiniteIy untiI it
receives a new connection.
Remember the Iisten queue we taIked about in the Iast chapter? accept simpIy
pops the next pending connection oII oI that queue. II none are avaiIabIe it
waits Ior one to be pushed onto it.
Accept returns an Array
In the exampIe above I assigned two vaIues Irom one caII to accept . The accept method
actuaIIy returns an Array. The Array contains two eIements: Iirst, the connection,
and second, an AddrinIo object. This represents the IocaI address oI that connection.
33
AddrinIo AddrinIo
AddrinIo is a Ruby cIass that represents a host and port number. It wraps up
an endpoint representation niceIy. You'II see it as part oI the standard Socket
interIace in a Iew pIaces.
You can construct one oI these using something Iike AddrinIo.tcp('IocaIhost', ((S) .
Some useIuI methods are =ip_address and =ip_port . Have a Iook at s ri AddrinIo Ior
more.
Let's begin by taking a cIoser Iook at the connection and addr returned Irom =accept .
34
Thanks For Reading!
This was a sampIe oI ,(-./#0 ,/$% 234 5(!.&$*.
II you haven't aIready, visit http://workingwithtcpsockets.com/ to be notiIied when
it's ready.
Jesse (@jstorimer)
186

Vous aimerez peut-être aussi