Socket programming

From 118wiki

Jump to: navigation, search

Contents

Socket Programming

"Socket" programming refers to using the Berkeley sockets API for accessing TCP ports, sending and receiving data. The API differs between client and server. Numerous Python libraries support socket programming.

Single Client, Single Server Example

Here is a very simple Python example of a TCP client program:

import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(("127.0.0.1",8888))
sock.send("this is a test of connection to the server")
response = sock.recv(1024)
print response + '\n'
sock.close()

This client program has numerous "bugs", in that it doesn't handle communication errors, doesn't handle the case when a response is not entirely returned in one message, and so on (however, a more polished example would be longer).

And a corresponding TCP server program:

import socket
S = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
S.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
myport = 8888
S.bind(('',myport))
S.listen(5)
try:
  while 1:
    newS, address = S.accept()
    print "A client has connected from", address
    while 1:
      receivedData = newS.recv(1024)
      if not receivedData: break
      if receivedData.startswith("quit"): break
      # just some funny response returned here ....
      receivedData = receivedData.split()
      receivedData.reverse()
      receivedData = ' '.join(receivedData)
      newS.send(receivedData)
    newS.close()
    print "Disconnected from", address
finally:
  S.close()

This server example also has many flaws, and of course many things aren't explained. But the main criticism of this server is that it is engineered for only one client at a time (notice it has only one thread to handle clients, and a while loop devoted to that client, which blocks other clients from connecting until the previous client is finished).

The Echo Example

This is the usual type of example used to teach TCP, where a client sends a message and the server echoes the message by sending it back to the client.

Client: media:TCPEchoClient.txt -- click to view, or right-click and save as to download and run this (rename it to the ".py" extension to execute it).

Server: media:TCPEchoServer.txt

This is example has a slight improvement over the previous one: both client and server use the sendall() socket method. The difference between send and sendall is:

  1. a sock.send(string) may not transmit the entire string. The documentation on sock.send() states that it returns an integer, the number of bytes actually sent. The advantage of sock.send() is that it usually returns very quickly.
  2. a sock.sendall(string) sends all the bytes, but internally can get blocked due to lack of buffers, and therefore might not return to the caller for a long time (many seconds in some cases)

The example still doesn't fully account for exceptions. And the server is restricted to handling one client at a time.

Multithreaded Echo Example

This version of TCP Echo uses Python's threading module.

Client: same as before, the client is single-threaded.

Server: media:TCPThreadingServer.txt

The server uses the Thread class of the threading module. The pattern of the Thread class is similar to Java threads: define your own class to be a subclass of threading.Thread, make sure it has a constructor method (so that it can save a socket given to the new thread), and a run method. The main thread of the server creates a new instance of your class whenever a new client connects, so there can be many clients, each with its own thread, running in parallel. Each client thread has its own socket with which it receives and sends data. When the run method's body ends, the thread for that client stops (therefore, most applications have a loop in the run method that continues until the client should be disconnected). Again, this example could be better by handling more exceptions.

'Select' Echo Example

Select is a Unix technique to avoid having a program wait for file I/O, network sockets to have data, or timers to expire. The problem addressed by select is this: when a program invokes F.read() for some file F, the program has to wait for file F to supply data, which can take time if F is a slow device. What if there is another file available for reading, say G, in the meantime? How can a program "know" in advance, before deciding on executing F.read() or G.read(), which of these would wait or not wait? The select function answers the question. In the C version of select, a program supplies three lists of file descriptors and a timeout value. (Three lists, for input, output, and exception readiness testing.) If nothing is ready, select waits for the specified timeout period. Otherwise, select returns immediately with information about which file descriptors are "ready".

Client: same as before

Server: media:TCPSelectServer.txt

The server here is single-threaded. Yet, in some sense, the select pattern could be used to handle many clients in parallel, if only this server were changed to construct and keep track of a socket for each client. The reason it doesn't do so in this example is that the job of "echoing" a message is so simple.

Personal tools