Foundations of Python Network Programming

(WallPaper) #1

Chapter 3 ■ tCp


48


You can verify this by running Listing 3-1 in server mode, as shown previously, and trying to connect with a client
from another machine.


$ python tcp_sixteen.py client 192.168.5.130
Traceback (most recent call last):
...
ConnectionRefusedError: [Errno 111] Connection refused


You can see that the server, if you have it running, does not even react. The operating system does not even
inform it that an incoming connection to its port was refused. (Note that if you have a firewall running on your
machine, the client might just hang when it tries connecting, rather than getting a friendly “Connection refused”
exception to tell it what is going on!)
But if you run the server with an empty string for the hostname, which tells the Python bind() routine that you
are willing to accept connections through any of your machine’s active network interfaces, then the client can connect
successfully from another host (the empty string is supplied by giving the shell these two double quotes at the end of
the command line).


$ python tcp_sixteen.py server ""
Listening at ('0.0.0.0', 1060)
Waiting to accept a new connection
We have accepted a connection from ('127.0.0.1', 60359)
Socket name: ('127.0.0.1', 1060)
Socket peer: ('127.0.0.1', 60359)
Incoming sixteen-octet message: b'Hi there, server'
Reply sent, socket closed
Waiting to accept a new connection


As noted before, my operating system uses the special IP address 0.0.0.0 to mean “accept connections on any
interface,” but this convention may be different on your operating system, and Python hides this difference by letting
you use the empty string instead.


Deadlock


The term deadlock is used for all sorts of situations in computer science where two programs, sharing limited
resources, can wind up waiting on each other forever because of poor planning. It turns out that it can happen fairly
easily when using TCP.
I mentioned previously that typical TCP stacks use buffers—both so that they have somewhere to place incoming
packet data until an application is ready to read it and so that they can collect outgoing data until the network
hardware is ready to transmit an outgoing packet. These buffers are typically quite limited in size, and the system is
not generally willing to let programs fill all of RAM with unsent network data. After all, if the remote end is not yet
ready to process the data, it makes little sense to expend system resources generating more of it.

Free download pdf