3.2. Introduction to Sockets Programming

3.2.1. Sockets

  • API for applications to read and write data from TCP/IP or UDP/IP
  • File abstraction (open, read, write, close)
  • Abstract operating system resource
  • First introduced with BSD UNIX
  • De-facto standard API for TCP/IP

3.2.2. Ports

  • The so called well known ports are those ports in the range of 0 to 1023 only the operating system or an Administrator of the system can access these. They are used for common services such as web servers (port 80) or e-mail servers (port 25).
  • Registered Ports are in the range of 1024 to 49151.
  • Dynamic and/or Private Ports are those from 49152 through 65535 and are open for use without restriction

3.2.3. The Socket API Commands

3.2.3.1. Creating a Socket

socket.socket(socket.AF_INET, socket.SOCK_STREAM)

Create and return a new socket object to use IP v4 and TCP.

Return type:socket object

Example usage:

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  • Will always use above options.
  • First option says it is IP version 4 (another value for IP version 6), in Unix it can also be set to a named pipe.
  • Second option says that it will connect to a TCP port, rather than UDP.
  • These names are the original ones used in the C libraries.
socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

Set options on the socket.

Example usage:

sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

There are many different socket options that can be set. The one set here, socket.SO_REUSEADDR, causes the port to be released immediately after the socket is closed. Without this option, if you restart the program right away after a previous exit, then a socket.bind() system call could fail reporting that the port is already in use.

3.2.3.2. The Socket API From the Server Side

socket.bind((hostname, port))

Bind to a particular port in preparation to receive connections on this port. bind() takes one parameter, which is a two value tuple consisting of a hostname (string) and port number (integer). Notice the double parentheses – the tuple is often generated as bind() is being called.

Parm hostname:The hostnames to accept connections from, usually ‘’, which will accept from any host. It may also be ‘localhost’ for security reasons.
Parm port:The port number to bind to. Must not already be in use.

Example usage:

sock.bind((hostname, port))
  • hostname can be one of: ‘’, socket.gethostname(), ‘localhost’ or the machine host name as a string.
  • The port should is usually between 1024 to 49151, but may be in the dynamic port range.
  • Can not bind to a port with another socket bound to it.
  • Note the double parenthesis, bind() takes a single tuple argument. The extra set of parenthesis makes the two values a tuple.
socket.listen(n)

Begin listening on the previously bound port for new connections.

Parameters:n (integer) – The number of simultaneous connections to queue waiting for service.
Limit n:5

Example usage:

sock.listen(n)
  • Tells the socket to listen for incoming connections
  • n here is an integer for number of new connections to hold in queue. Queued connections are ones received, but not yet accepted. For now, we can set n to 1. For an actual server, n may be larger (like 3 or 4)
socket.accept()

Accept a new connection.

Return type:socket

Example usage:

(newsock, address) = sock.accept()
  • Wait for a connection – blocking
  • Returns a tuple of a new allocated socket and the address of the client. The address is itself a tuple consisting of an IP address and port number.
  • A new socket is allocated because a server will usually want to continue listening to the old socket, for new connections.
  • Usually, the new socket is passed to a thread to handle communication with the client.

3.2.3.3. The Socket API From the Client Side

socket.connect((hostname, portNumber))

Establish a connection to a server.

Example usage:

sock.connect((hostname, portNumber))
  • Connect to a server that is listening for connections
  • The hostname may be either it’s canonical name, or it’s IP address.
  • For most exercises in this class, just set hostname to ‘localhost’.
  • portNumber should match the port number that the sever was bound to.
  • This is a blocking statement, until the connection is established.

3.2.3.4. The Socket API For Established Connections

socket.recv(N)

Receive up to N bytes from the socket. Block until a message is received on the socket, or the connection was closed.

Return type:string

Example usage:

message = sock.recv(1024)

Note

The only time that recv() will return with no data., i.e., if len(message) == 0: or if not message: (these two statements are equivalent) is when the connection was closed, usually by the far end closing the socket. Thus, testing for a zero length message is the usual way of detecting a disconnect. See close() and shutdown().

socket.send(msg)

Send a string message using an established socket connection.

Parameters:msg (string) – The message to send

Example usage:

sock.send(msg)
socket.close()

Close an established socket connection.

Example usage:

sock.close()
socket.shutdown(n)

Leave the socket open, but discontinue using it in one of three ways.

Parameters:n – Which function of the socket is discontinued. 0 = done receiving, 1 = done sending, 2 = both

Example usage:

sock.shutdown(1)

In most cases shutdown() is not used. If the far end is looping on recv(), when the near end does sock.shutdown(1), then the connection is still active, but the far end will receive a zero length message. The far end could still send some final data back to the near end. Some application layer protocols call for the use of shutdown(). If you are not expecting the far end to perform a shutdown(); however, then it is usually safe to assume that a zero length message is due to a close().

Here is an example of when you might want to use shutdown(). This is the determined sender and the patient receiver. The sender is trying to send a large amount of data, so it sends multiple 1024 byte blocks. After sending all of the data, the sender does a shutdown() to signal to the receiver that all of the data has been sent. At this point, the sender can not send any more data, but it can receive data. When the receiver gets the zero length message, it sends back the size of the data received. If the receiver does not report the same value as was sent, the determined sender re-connects and tries to send the data again.

# This is the 'determined sender'
import socket
import string

try_send = True
while try_send:
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((server, 4000))
    buffer = orig_data
    sent = 0
    while len(buffer) > 1024:
        sent += sock.send(buffer[:1024])
        buffer = buffer[1024:]
    sock.send(buffer)
    sock.shutdown(1)
    received = sock.recv(30)
    sock.close()
    if string.atoi(received) == sent:
        try_send = False
    else:
        print "Not all data sent"

The receiver sends back the size of the data received after the shutdown() and then waits for another connection.

# This is the patient receiver
import socket

ss = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ss.bind(('', 4000))
ss.listen(1)
while True:
    new,addr = ss.accept()
    buffer = ""
    block = 'x'
    while block:
        block = new.recv(1024)
        buffer += block
    # -- end of data
    new.send(len(buffer))
    new.close()
    handle_new_stuff(buffer)

3.2.3.5. Miscellaneous Socket Functions

socket.getaddrinfo(host, port)

Resolves the host/port argument, into a sequence of 5-tuples that contain all the necessary arguments for creating the corresponding socket. port is a string service name such as ‘http’, a numeric port number or None. Additional arguments (not shown here) are optional.

The getaddrinfo() function returns a list of 5-tuples with the following structure:

(family, socktype, proto, canonname, sockaddr)

family, socktype, proto are all integers and are meant to be passed to the socket() function. canonname is a string representing the canonical name of the host.

socket.gethostbyaddr(hostname)

Translate a host name to IPv4 address format.

socket.gethostbyname(ip_address)

Return a triple (hostname, aliaslist, ipaddrlist) where hostname is the primary host name responding to the given ip_address, aliaslist is a (possibly empty) list of alternative host names for the same address, and ipaddrlist is a list of IPv4/v6 addresses for the same interface on the same host (most likely containing only a single address).