FTP Port 20 Telnet Port 23 SMTP (Mail) Port 25 HTTP (WWW) Port 80
Creating a socket
A socket is created through the socket (family, type, [ proto ]) call; family is one of the above mentioned address families: AF UNIX and AF INET, type is represented through the following
constants: SOCK STREAM, SOCK DGRAM and SOCK RAW. proto argument is optional and defaults to 0. We see that socket() function returns a socket
in the specified domain with the specifieed type. Because the constants mentioned above are contained in the socket module, it will be better if they are used with the socket.CONSTANT notation.
Without doing so, the interpreter may generate an error.
To create a stream socket in the Internet domain we are using the following line:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
SOCK_STREAM Stream socket (TCP) SOCK_DGRAM Datagram socket (UDP) SOCK_RAW Raw socket
The following call will create a stream socket in the UNIX domain:
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
Connecting a socket and data transfer
A server from our point of view is a process which listen on a specified port. We may call the association port, process as a service. When another process wants to meet the server or
use a specific service it must connect itself to the address and portnumber specified by the server. This is done calling the socket method connect(address ), where address is a pair
(host, port) in the Internet domain and a pathname in the UNIX domain.
When using the Internet domain a connection is realized with the following code:
sock.connect(('localhost', 8000))
If the service is unavailable or the server don't want to talk with the client process a socket.error- (111, 'Connection refused') is issued. Elsewhere, after the connection is established with the
desired server, data is sent and received with send(buffer, [ flags ]) and recv(buffer, [flags ]) methods. These methods accepts as mandatory parameter the size of the buffer in bytes and some optional flags
which are UNIX specific.
Binding a name to socket
The socket, after creation, is nameless, though it have an associated descriptor. Before it can be used it must be bind to a proper address since this is the only way a foreign process may
reference it. The bind(address ) method is used to name a socket. The meaning of the address is explained above. Next call will bind a socket in the Internet domain with address
composed from hostname localhost and port number 8000 :
sock.bind(('localhost', 8000))
Please take care when typing: indeed there are two pairs of parenthesis. Doing elsewhere the interpreter will issue a TypeError. The purpose of the two pairs of parenthesis is simple:
address is a tuple containing a string and an integer. The hostname must be properly picked, the best method is to use gethostname() routine in order to assure host independence and portability.
Listening and accepting connections
Once we have a socket with a proper name bound to it, next step is calling the listen(queue ) method. It instructs the socket to passively listen on port port . listen() take as parameter
an integer representing the maximum queued connection. This argument should be at least 1 and maximum, system-dependent, 5. Until now we have a socket with a proper bounded
address. When a connection request arrives, the server decide whether it will be accepted or not. Accepting a connection is made through the accept() method. It takes no parameter
but it returns a tuple (clientsocket, address) where clientsocket is a new socket server uses to communicate with the client and address is the client's address. accept() normally
blocks until a connection is realized. This behavior can be overridden running the method in a separate thread, collecting the new created socket descriptors in a list and process them in
order. Meantime, the server can do something else. The above mentioned methods are used as follows:
sock.listen(5)
clisock, address = sock.accept()
The code instructs the socket on listening with a queue of five connections and accept all incoming calls. As you can see, accept() returns a new socket that will be used in further
data exchanging. Using the chain bind-listen-accept we create TCP servers. Remember, a TCP socket is connection-oriented; when a client wants to speak to a particular server it must
connect itself, wait until the server accepts the connection, exchange data then close. This is modeling a phone call: the client dial the number, wait till the other side establish the
connection, speak then quit.
s.accept() # Accept a new connection s.bind(address) # Bind to an address and port s.close() # Close the socket s.connect(address) # Connect to remote socket at the specified address s.getpeername() # Get name of remote machine s.getsockname() # Get socket address as (ipaddr,port) s.listen(backlog) # Start listening for connections, backlog specifies max number of pending connections s.recv(bufsize) # Receive data, maximum of bufsize s.recvfrom(bufsize) # Receive data (UDP) s.send(string) # Send data in the variable string s.sendto(string, address) # Send packet (UDP)
s.gethostbyname(hostname) # Get IP address for a host s.gethostname() # Name of local machine s.ntohl(x) # Convert 32-bit integer to host order s.ntohs(x) # Convert 16-bit integer to host order s.htonl(x) # Convert 32-bit integer to network order s.htons(x) # Convert 16-bit integer to network order
Implement both Client/Server parts of a communication such that Client will send two integers, each of which is a two-digit decimal number. And Server will reply with the sum of those integers.
Client may take the two integers as an argument input to the program or in run-time from the user. After receiving the reply of the Server, Client will show the user final result.
Tip 1: Use str() function to convert an integer to a string, and use int() function to convert a string to an integer.
Tip 2: You have to specify how long a message you are expecting to receive at recv(n) function. Since you can get full mark for adding up two-digit decimal numbers, you might want to use recv(2) for two times so you can get two strings, each of which has length of 2 and contains the number the client sends.
Tip 3: Learn from the examples in last lab and start from modifying them.
After you finish the programs, you have to raise your hand and let the TA check you out.
Take-home thinking
1. Instead of only summing two-digit numbers, take the any number of digits from the user and execute it on the Server side.
2. Make the Server Running and accepting connections forever.