BASIC SOCKET FUNCTIONS





BASIC SOCKET FUNCTIONS

Whether you are used to using the built-in Perl socket functions or the IO::Socket module, you shouldn't have any problems making the move to using Python's object based model. With Perl the first stage is to create a new generic socket using the socket function, we then use that as a base from which to bind to a service port in order to provide a network service, or to connect to a remote service. For example, the Perl fragment below creates a socket and then connects to a remote host:

use Socket;

sub open_tcp_socket
{
    my ($SOCKETHANDLE, $remotehost, $service_name) = @_;
    socket($SOCKETHANDLE,PF_INET,SOCK_STREAM,'tcp');
    my $port_num = (getservbyname($service_name,'tcp'))[2];
    my $remote_socket = sockaddr_in($port_num,
                                    scalar gethostbyname
                                    ($remotehost));
    connect($SOCKETHANDLE, $remote_socket);
}

We can open a connection and read some data using:

open_tcp_socket(*SOCKETHANDLE,'mail.mchome.com','smtp');
recv(SOCKETHANDLE, $message, 1024, 0);
print $message;
close(SOCKETHANDLE);

Python shortens some of these operations – for example we don't need to use the sockaddr_in() function to pack the port number and remote host address before calling connect() – the Python connect() accepts a tuple containing the port number and remote address and opens the connection. For example, we can rewrite the open_tcp_socket() function above in Python like this:

def open_tcp_socket(remotehost,servicename):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    portnumber = socket.getservbyname(servicename,'tcp')
    s.connect((remotehost,portnumber))
    return s

The code for using the function is remarkably similar:

mysock = open_tcp_socket('mail.mchome.com','smtp')
message = mysock.recv(1024)
print message
mysock.close()

As expected, the biggest difference is that Python creates a new socket object on which we use methods to connect(), listen(), and accept() connections, just as we use functions in Perl. The list of Perl functions, the arguments they accept and their Python equivalents are listed in Figure.

Figure Perl and Pythan socket functions
Perl built-in function Python socket method
socket(S,family,type) S = socket(family, type)
accept(S) S.accept()
bind(S,address) S.bind(address)
close(S) S.close()
connect(S, sockaddr_in(serviceport, scalar gethostbyname(address))) S.connect((address,serviceport))
getpeername(S) S.getpeername()
getsockname(S) S.getsockname()
getsockopt(S, level, option) S.getsockopt(level, option)
listen(S, waitqueue) S.listen(waitqueue)
recv(S, message, buflen [, flags]) message = S.recv(buflen [, flags])
send(S, message [, flags]) S.send(message [, flags])
send(S, message, flags, address) S.sendto(message [, flags], (address, port))
setsockopt(S, level, option, value) S.setsockopt(level, option, value)
shutdown(S, how) S.shutdown(how)

Note that the connect() method accepts a single argument, a tuple with two elements the IP address and the serviceport number that we would normally supply to the sockaddr_in() Perl function to create a packed address for the Perl connect() function.

The most important thing to remember when working with sockets under Python is that the socket is not a filehandle and so we can't use the readline() or other methods to read information from the socket. Instead, we need to use the recv() and send() methods to exchange data with a remote host. In most cases this shouldn't cause too many problems as most protocols work on a challenge/response system such as that used by SMTP or HTTP.

If you want to be able to read and write to a network socket then use the fdopen() function within the os module to create a new file object based on the file descriptor number. File descriptors are shared between files and sockets on most operating systems and you can obtain the file descriptor number of any file or socket object using the fileno() method. For example, we could rewrite the code we used earlier for reading from an SMTP server:

mysock = open_tcp_socket('mail.mchome.com','smtp')
message = mysock.recv(1024)
print message
mysock.close()

to:

mysock = open_tcp_socket('mail.mchome.com','smtp')
file = os.fdopen(mysock.fileno())
line = file.readline()
print line,
file.close()
mysock.close()

This opens the socket, creates a file object based on the sockets file number and then uses readline() to read the information. With the socket module we can do this automatically (without the need for os) using the makefile() method:

mysock = open_tcp_socket('mail.mchome.com','smtp')
file = mysock.makefile()
line = file.readline()
print line,
mysock.close()
file.close()

If you are communicating with one of the standard Internet services such as SMTP, HTTP or FTP then use one of the modules that comes with Python – we'll be looking at some alternatives later in this chapter.


     Python   SQL   Java   php   Perl 
     game development   web development   internet   *nix   graphics   hardware 
     telecommunications   C++ 
     Flash   Active Directory   Windows