0% found this document useful (0 votes)
194 views88 pages

DMC 1946

This document provides an introduction and overview of socket programming concepts. It discusses how sockets allow for protocol-independent connections between processes. It describes key socket characteristics like connection-oriented vs connectionless and reliable vs unreliable. It also explains the roles of clients and servers in communication and some common socket system calls used by servers and clients, like socket(), bind(), listen(), accept(), connect(), and send/recv functions. The goal is to provide hands-on practice and learning of network programming concepts through experimentation with sockets.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
194 views88 pages

DMC 1946

This document provides an introduction and overview of socket programming concepts. It discusses how sockets allow for protocol-independent connections between processes. It describes key socket characteristics like connection-oriented vs connectionless and reliable vs unreliable. It also explains the roles of clients and servers in communication and some common socket system calls used by servers and clients, like socket(), bind(), listen(), accept(), connect(), and send/recv functions. The goal is to provide hands-on practice and learning of network programming concepts through experimentation with sockets.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 88

1.

Introduction
This laboratory manual is written to accompany Network Programming Laboratory course for the MCA Distance Education Programme of Anna University. The prerequisite for this course is basic networking concepts and transport layer protocol basics. The first module of this manual contains introduction to Socket address structures and System calls. The second module deals about various applications that can be performed with the help of Protocol dependent functions using connection oriented and connection less socket types.

The emphasis in this manual is learning through practice and experimentation. Learning a network programming requires a lot of practice in writing programs and these labs are designed to provide that practice. These labs are also designed to reinforce experimentation and debugging skills, both of which are important for a successful Network programmer.

At the end of the session, you will be able to write your own programs, modify, debug, test and verify them.

2. Socket Programming in C
Sockets are a protocol independent method of creating a connection between processes. Sockets can be analyzed in terms of three dimensions: Connection, Boundary, and Reliability. (i) Connection Oriented or Connectionless: Is a connection established before communication or does each packet describe the destination? (ii) Packet based or Streams based: Are there message boundaries or is it one stream? (iii) Reliable or Unreliable: Can messages be lost, duplicated, reordered, or corrupted?

The characteristics of sockets are determined based on their domain, type and transport protocol.The common domains are AF UNIX and AF INET that gives the address format as UNIX pathname and as host and port number respectively. The common types of protocol are virtual circuit that receives the message in the transmitted order which makes it reliable and datagram which follows an arbitary order and hence its unreliable.The sockets have more than one type of transport protocol like TCP (uses virtual circuit) and UDP ( uses datagram).

2.1.

Clients and Servers

When two computers communicate on the Internet or any other network, one of the two is called the client and the other is called the server. The client is the one that initiates the request; thus, the client is analogous to the person who initiates a phone call or mails a letter. The other computer is called the server, analogous to the person who receives a phone call or receives a letter. The server must be started first. Once a server is started, it goes to sleep waiting for clients to connect. Whenever a client makes a request, it wakes up, handles the request, and waits for the next clients request. If handling the

request is complex, a server might fork off a new thread or even a new process for each request. The terms request and connections can be used synonymously to understand socket programming. A server on UNIX systems is typically run as a daemon. A daemon is a process which is not connected to a controlling terminal; it is running in background. Note that the client needs to know about the existence of the server, but, until the connection is established, the server does not necessarily know about the existence of the client. A single host can run multiple different servers. One of the jobs of the TCP software is to multiplex incoming segments; that is, it has to determine the destination process. This is done with a port. A computer has 64K ports for TCP and an additional 64K ports for UDP. In order for a client to establish a connection to a server, it needs to know the IP address of the server and the port number on which the application process is listening. Most computers on the Internet have a name as well as an IP address. When you want to connect to www.amazon.com, you do not need to know its IP address is 207.171.183.16. There is a fairly elaborate name service system on the Internet (which uses the same client server system) called DNS (the domain name server), hence when an application has only a name, it can connect to a name server which will return the IP address of the server in which the application runs. Likewise, most people who use services on the Internet do not know anything about port numbers. The standard Internet services listen on standard port numbers. For example, a production web server always listens on TCP port 80. A web server in a testing environment might listen on some other port. If you append a colon followed by a number at the end of a URL, (for example, www.amazon.com:8080), this tells your browser (the client) to connect to a different port (8080 in the example), but of course you would only do this if you know that there is a web server listening on that particular port.

Table 2.1 shows some well known services and their port numbers. SERVICES ssh (the secure shell that you use to connect to Solaris) smtp (simple mail transfer protocol; i.e. email) finger (a way to query users on a system) ftp (file transfer protocol, a service to copy files from one system to another) telnet (an insecure version of ssh) PORT NUMBER 22 25 79 21 23

The lower 2000 ports are reserved by the kernel and require administrative privileges to use; the ports above this can be used by user processes. Table 2.1 2.2 Socket System calls

The mechanism that application programs use to communicate on a network is the socket. Sockets were first introduced in Unix BSD 4.1 (1982), and the popularity of this operating system among academics made the TCP/IP protocol suite a standard for socket programming (although the socket interface can handle other protocols as well). There is a series of UNIX system calls that deal with sockets. The Win32 APIs for sockets are very similar. Table 2.2 explains few socket system calls. API socket bind listen accept connect send,sendto recv,recvfrom shutdown FUNCTIONS creates a socket of a given domain, type, protocol (buy a phone) creates a socket of a given domain, type, protocol (buy a phone) Specifies the number of pending connections that can be queued for a server socket. (call waiting allowance) server accepts a connection request from a client (answer phone) client requests a connection request to a server (call) write to connection (speak) read from connection (listen) end the call Table 2.2

A socket is one end of a connection. Here is the function prototype. #include <sys/types.h> #include <sys/socket.h> int socket(int domain, int type, int protocol); For the socket system call the first argument, the domain, should be PF_INET, although the older form, AF_INET should also work. These two strings are defined in the header file sys/socket.h. There are other domains as well. The second argument, the type, should be SOCK_STREAM to create a TCP socket, or SOCK_DGRAM to create a UDP socket. Recall that the TCP protocol sends a continuous stream of bytes to its application, which is why this is called a stream type. The third argument should generally be zero, which means choose the default protocol (TCP for a stream socket). The socket call returns a file descriptor if successful and a negative number on failure. Failure is unlikely if your arguments are correct. Both client processes and server processes use sockets and the socket system call, but the sequence of system calls after creating the socket is different for clients and for servers.

2.3 Socket system calls for Server A server process first creates a socket using the socket system call. After a socket has been created, it must be bound to an address. The system call for this is bind. int bind(int sock, struct sockaddr *addr, socklen_t addrlen) The first argument is an open socket, the value returned from a socket system call. The second is a pointer to a socket address, and the third is the size of this address.

In the header file sys/socket.h the following structure is defined. struct sockaddr { u_short sa_family; /* address family: AF_xxx value */ char sa_data[14]; /* up to 14 bytes of protocol specific address */

}; The type of the second field depends on the type of socket, so this is a union. A union in C language is a struct which can take on different forms. For internet addresses, we will use struct sock_addr_in. This has to contain the IP address and the port number. For internet addresses, the following structures are defined in the header file netinet/in.h. struct in_addr { u_long s_addr; /* 32-bit netid/hostid */ /* network byte ordered */ };

struct sock_addr_in { short sin_family; /* AF_INET */ u_short sin_port; /* 16 bit port number */ /* network byte ordered */ struct in_addr sin_addr; char sin_zero[8]; /* unused */ }; By now your eyes have certainly glazed over, but this is not as complicated as it seems. Here is some sample code which you can use to bind a server to port 8080. (The function error(char *) is a short function that you have to write which calls perror and then exits.)

The following lines of code create a socket and bind it to a port number. 1. int sock, len, retval; 2. unsigned short port; 3. struct sockaddr_in server; 4. port = (unsigned short) 8080; 5. sock=socket(AF_INET, SOCK_STREAM, 0);

6. if (sock < 0) error("Opening socket"); 7. server.sin_family=AF_INET; 8. server.sin_addr.s_addr=INADDR_ANY; 9. server.sin_port=htons(port); 10. len=sizeof(server); 11. retval = bind(sock, (struct sockaddr *)&server, len); 12. if (retval < 0) error("binding"); This code creates a socket called sock and sets the fields of server. The symbolic constant INADDR_ANY in line 8 is used to refer to the internet address of the machine on which the process is running. The function htons() at line 9 stands for host to network short. This function takes a short int (16 bit) as an argument, (which of course is in in host byte order) and returns the value in network byte order. The network is big-endian, so on a big-endian computer, this function simply returns its argument, but on a little endian computer (which includes Intel processors), it converts its argument to big endian and returns that value. This is one of a family of four functions. htons(short) Host to network short htonl(long) Host to network long ntohs(short) Network to host short ntohl(long) Network to host long Once a socket is created and bound to an address, a server socket has to listen for connections. The system call for this is listen which takes two arguments. The first is a socket which is bound to an address, the second is the length of the backlog queue; note that this is not the number of connections that can be accepted, this is the number of connections that can be waiting to be accepted. In the old days, this had to be set to 5; on most modern systems, it usually doesn't matter what you set it to. If connections from clients are arriving faster than your server can accept them, the client receives a connection refused error. Once a server is listening, it should enter an infinite loop to wait for clients to connect. The first (or at least one of the first) statements in this loop is a call to accept. Here is the function prototype.

#include <sys/types.h> #include <sys/socket.h> int accept(int s, struct sockaddr *addr, socklen_t *addrlen);

The accept system call takes three arguments. The first is the socket, the second is a pointer to a struct sockaddr, and the third is the size of a struct sockaddr. A call to accept will block until a client connects to the server. This will wake up the server. Accept returns an int, which is another socket. This is confusing, because the server listens on one socket, but when a connection from a client is established, all of the communication is on a different socket, the value of which is returned by the accept system call. The second argument to accept will be set to the address of the client so that the server can know whom it is talking to. Once a connection has been accepted, both sides can communicate on the new socket (the engineering term for this is full duplex). You can use read() and write() if you wish, but the preferred system calls are recv() for reading and send() for writing. These are similar to read and write except that they take a fourth argument, which allows you to set some flags. If you set the fourth argument to zero, they work identically to read and write. Here are the function prototypes for send and recv: #include <sys/types.h> #include <sys/socket.h> ssize_t recv(int s, void *buf, size_t len, int flags); ssize_t send(int s, const void *msg, size_t len, int flags); A ssize_t is a signed 32 bit integer and a size_t is an unsigned 32 bit integer on most machines. The return value is is the number of bytes read or written if the call was a success, 0 if the client has closed the socket or a negative value if some other exception has occurred. The last argument, flags, should be set to zero. As with read, a call to recv may not necessarily read the number of bytes requested, it will read the number of bytes available to read, up to the size of the buffer (which should be in len). However, a call to send should always send the number of bytes requested (the value in len) unless an exception occurs.

Here is a complete program for a very simple server. /* server.c - creates a connection oriented (stream) Internet server for the Unix Operating system. Port is passed in as an argument To compile on solaris gcc ... -lnsl -lsocket */

#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <arpa/inet.h> #define BUFSIZE 1024 extern int errno; void error(char *msg) { perror(msg); exit(0); } int main(int argc, char *argv[]) { int sock, newsock, len, fromlen, n; unsigned short port; struct sockaddr_in server, from; char buffer[BUFSIZE]; char *msg = "I Got your message"; if (argc < 2) { fprintf(stderr,"usage %s portnumber\n",argv[0]); exit(0); }

port = (unsigned short) atoi(argv[1]); sock=socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) error("Opening socket"); server.sin_family=AF_INET; server.sin_addr.s_addr=INADDR_ANY; server.sin_port=htons(port); len=sizeof(server); if (bind(sock, (struct sockaddr *)&server, len) < 0) error("binding socket"); fromlen=sizeof(from); if (listen(sock,5) < 0) error("listening"); while (1) { newsock=accept(sock, (struct sockaddr *)&from, &fromlen); if (newsock < 0) error("Accepting"); printf("A connection has been accepted from %s\n", inet_ntoa((struct in_addr)from.sin_addr)); n = recv(newsock,buffer,BUFSIZE-1,0); if (n < 1) { error("Reading"); } else { buffer[n]='\0'; printf("Message from client is: %s\n",buffer); len = strlen(msg); n = send(newsock,msg,len,0); if (n < len) error("Error writing"); if (close(newsock) < 0) error("closing");

10

} } return 0; // we never get here } This program creates a TCP socket in the Internet domain. It takes one argument, the port number that the server should be bound to. It binds the socket to that port on the local host (i.e. the machine that it is running on), listens for connections, and then enters an infinite loop. Whenever it accepts a new connection from a client, it reads a message from the client and displays it on the screen, sends a message back to the client, and closes the socket, The only new function call in this program is inet_ntoa which takes one argument, an in_addr, (which is just a 32 bit unsigned int) and returns a string which is the IP address of its argument in dotted decimal form.

2.4 Socket system calls for Client The client creates a socket just like the server. However, instead of binding to an address, it calls the connect system call, which establishes a connection to a server. Here is the function prototype #include <sys/types.h> #include <sys/socket.h> int connect(int s, const struct sockaddr *name, int namelen); You've probably already forgotten what a struct sockaddr is and we have reproduced for your convenience.

struct sockaddr { u_short sa_family; /* address family: AF_xxx value */ char sa_data[14]; /* up to 14 bytes of protocol specific address */ }; The contents of sa_data are interpreted according to the type of address. For Internet addresses, use struct in_addr

11

{ u_long s_addr; /* 32-bit netid/hostid */ /* network byte ordered */ }; struct sock_addr_in { short sin_family; /* AF_INET */ u_short sin_port; /* 16 bit port number */ /* network byte ordered */ struct in_addr sin_addr; char sin_zero[8]; /* unused */ }; You need to fill in the port number and the IP address of the server. Usually, you do not know the IP address, but you have the name of the computer. In this case, use the system call gethostbyname(). This takes one argument, a character string which is the name of the machine on which the server is running, and it returns a pointer to a struct hostent. This has a field, char *h_addr, which is the IP address. The size of this is in the field h_length. If you have been paying attention, you might have noticed that an IP address, which is a 32 bit unsigned int, is considered a struct in_addr or a char *. Here is a complete client. It takes two arguments, the name of the computer on which the server is running and the port number on which it is listening. /* client.c Creates Internet stream client for a UNIX platform.

The name and port number of the server are passed in as arguments. To compile on solaris gcc ... -lnsl lsocket */ #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <stdio.h> #include <unistd.h>

12

#include <stdlib.h> /* for atoi */

char *msg = "Hello from the client"; void error(char *msg) { perror(msg); exit(0); } int main(int argc, char *argv[]) { int sock, n; unsigned short port; struct sockaddr_in server; struct hostent *hp; char buffer[1024]; if (argc != 3) { printf("Usage: %s server port\n", argv[0]); exit(1); } sock= socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) error("Opening socket"); server.sin_family = AF_INET; hp = gethostbyname(argv[1]); if (hp==NULL) error("Unknown host"); memcpy((char *)&server.sin_addr,(char *)hp->h_addr, hp->h_length); port = (unsigned short)atoi(argv[2]); server.sin_port = htons(port); if (connect(sock, (struct sockaddr *)&server, sizeof server) < 0) error("Connecting"); n = send(sock, msg, strlen(msg),0);

13

if (n < strlen(msg)) error("Writing to socket"); n = recv(sock, buffer, 1023,0); if (n < 1) error("reading from socket"); buffer[n]='\0'; printf("The message from the server is %s\n",buffer); if (close(sock) < 0) error("closing"); printf("Client terminating\n"); return 0; }

If you are new to sockets, you should test these two programs before continuing, ideally on separate computers. Note that when you start up the server, nothing happens until it receives a connection. Note: Open two windows using Telnet login and type the code for client and server. Run the server program before running the client program. (Use loopback address for connectivity). The following command is used for compiling the program. gcc <programName.c> -o <objectFileName> where gcc is the compiler name, ProgramName.c is the C program file to be compiled objectFileName is the executable file name which is optional default object file is a.out. To execute the objectFileName, type the name as follows ./objectFileName where ./ denotes the location of the objectFileName.

2.5 Elementary TCP sockets

Figure 2.1 shows a timeline of the typical scenario that takes place between a TCP client and server.

14

TCP Server socket()

well-known port

bind()

listen() TCP Client accept() socket() connection establishment (TCP three-way handshake write() data (request) read() process request data (reply) read() blocks until connection from client

connect()

write()

close() end-of-file notification

read()

close() Figure 2.1 Typical communications between a client and a server. To make the discussion easier the terms system call and function can be used synonymously. In the next section you are going to learn more details about the important system calls. To perform network I/O, the first thing a process must do is call the socket function, specifying the type of communication protocol desired. 15

2.5.1 Socket function

#include<sys/socket.h> int socket(int family, int type, int protocol); Returns: non-negative descriptor if OK, -1 on error

The following are the possible values for each argument.

Protocol family constants:

Family AF_INET AF_INET6 AF_LOCAL AF_ROUTE AF_KEY

Description IPv4 protocols IPv6 protocols Unix domain protocols Routing sockets Key socket

Type of socket for socket function

Type SOCK_STREAM SOCK_DGRAM SOCK_SEQPACKET SOCK_RAW

Description Stream socket Datagram socket Sequenced packet socket Raw socket

Protocol of sockets for AF_INET or AF_INET6

Protocol IPPROTO_TCP IPPROTO_UDP IPPROTO_SCTP

Description TCP transport protocol UDP transport protocol SCTP transport protocol

16

Combinations of family and type for the socket function

AF_INET SOCK_STREAM SOCK_DGRAM

AF_INET6 AF_LOCAL AF_ROUTE AF_KEY Yes Yes Yes Yes Yes

TCP/SCTP TCP/SCTP UDP UDP SCTP IPv6

SOCK_SEQPACKET SCTP SOCK_RAW IPv4

2.5.2 Connect Function

The connect function is used by a TCP client to establish a connection with a TCP server.

#include<sys/socket.h> int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen); Return: 0 if OK, -1 on error

sockfd is a socket descriptor returned by the socket function. The second and third arguments are pointer to a socket address structure and its size (of the server).

2.5.3 Bind Function

The bind function assigns a local protocol address to a socket. The protocol address is a combination of either a 32-bit IPv4 address or a 128-bit IPv6 address, along with a 16-bit TCP or UDP port number.

#include<sys/socket.h> int bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen); Return: 0 if OK, -1 on error

17

2.5.4 Listen Function The listen function is called only by a TCP server and it performs two actions: 1. When a socket is created by the socket function, it is assumed to be an active socket, that is, a client socket that will issue a connect. The listen function converts an unconnected socket into a passive socket, indicating that the kernel should accept incoming connection requests directed to this socket. 2. The second argument to this function specifies the maximum number of connections the kernel should queue for this socket. #include<sys/socket.h> int listen(int sockfd, int backlog); Returns: 0 if OK, -1 on error

2.5.5 Accept Function accept is called by a TCP server to return the next completed connection from the front of the completed connection queue. If the completed connection queue is empty, the process is put to sleep.

#include<sys/socket.h> int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen); Return: non-negative descriptor if OK, -1 on error

2.5.6 Fork Function

The fork function is the only way in Unix to create a new process.

#include<unistd.h> pid_t fork(void); Returns: 0 in child, process ID of child in parent, -1 on error

18

2.5.7 Close Function

The normal UNIX close function is also used to close a socket and terminate a TCP connection.

#include<unistd.h> int close(int sockfd); Returns: 0 if OK, -1 on error

2.5.8 getsockname and getpeername Functions These two functions return either the local protocol address associated with a socket (getsockname) or the foreign protocol address associated with a socket (getpeername). #include<sys/socket.h> int getsockname(int sockfd, struct sockaddr *localaddr, socklen_t *addrlen); int getpeername(int sockfd, struct sockaddr *peeraddr, socklen_t *addrlen); Both Return: 0 if OK, -1 on error 2.5.9 Value-Result arguments When a socket address structure is passed to any socket function, it is always passed by reference. That is, a pointer to the structure is passed. The length of the structure is also passed as an argument. But the way in which the length is passed depends on which direction the structure is being passed: from the process to the kernel, or vice versa. Three functions, bind, connect, and sendto, pass a socket address structure from the process to the kernel. One argument to these three functions is the pointer to the socket address structure and another argument is the integer size of the structure, as in struct sockaddr_in serv;

/* fill in serv{} */ connect (sockfd, (SA *) &serv, sizeof(serv));

19

Since the kernel is passed both the pointer and the size of what the pointer points to, it knows exactly how much data to copy from the process into the kernel. The datatype for the size of a socket address structure is actually socklen_t and not int, but the POSIX specification recommends that socklen_t be defined as uint32_t. Four functions, accept, recvfrom, getsockname, and getpeername, pass a socket address structure from the kernel to the process, the reverse direction from the previous scenario. Two of the arguments to these four functions are the pointer to the socket address structure along with a pointer to an integer containing the size of the structure. The reason that the size changes from an integer to be a pointer to an integer is because the size is both a value when the function is called (it tells the kernel the size of the structure so that the kernel does not write past the end of the structure when filling it in) and a result when the function returns (it tells the process how much information the kernel actually stored in the structure). This type of argument is called a value-result argument. Two other functions pass socket address structures: recvmsg and sendmsg . But, we will see that the length field is not a function argument but a structure member. When using value-result arguments for the length of socket address structures, if the socket address structure is fixed-length, the value returned by the kernel will always be that fixed size: 16 for an IPv4 sockaddr_in and 28 for an IPv6 sockaddr_in6, for example. But with a variable-length socket address structure (e.g., a Unix domain sockaddr_un), the value returned can be less than the maximum size of the structure. 2.6 Setting up a destination addresses and port number An application program creates a variable of type struct sockaddr_in, then assigns the destination address and port number to this variable. In sending or receiving data on the socket connection, this variable is passed as a parameter. struct sockaddr_in server /*set up server name and port number*/

20

server.sin_family = AF_INET /* use TCP/IP */ server.sin_port = 800 /* specify port 800 */ server.sin_addr.s_addr = inet_addr("156.59.20.50"); 2.6.1 Binding the destination address Rather than specify the destination address in each call, the destination address can be bound to the socket. /* set up the server connection side */ server.sin_family = AF_INET; /* use TCP/IP */ server.sin_port = 0; /* use first available port */ server.sin_addr.s_addr = INADDR_ANY; if( bind( s, &server, sizeof(server) ) < 0 ) { perror("Error, socket not bound."); exit(3); } 2.6.2 Sending data to the socket connection There are five possible system calls that an application program can use to send data to a socket. They are send(), sendto(), sendmsg(), write() and writev(). The following code fragment sends data to the port. char buf[32]; strcpy(buf, HELLO); sendto( s, buf, sizeof(buf)+1, 0, &server, sizeof(server));

21

2.6.3 Receiving data from the socket connection The following code fragment receives data from the port. char buf[32]; int s, client_address_size; struct sockaddr_in client, server;

if( recvfrom( s, buf, sizeof(buf), 0, (struct sockaddr *) &client, &client_address_size) < 0 ) { perror("Error getting data from socket connection."); exit( 4 ); }

2.7 Writing Programs

The C programs are composed of functions. The general structure of any C program is as follows. Preprocessor Commands Type definitions Function prototypes Variable Declarations Function Definitions

Example

main() { printf ( Hello, I am with C ); }

22

This program, in fact, consists of a single piece of executable code known as a function. All C programs must include a function with the name main, execution of C programs always starts with the execution of the function main, if it is missing the program cannot run and most compilers will not be able to finish the translation process properly without the function called main. A C function normally consists of a sequence of statements that are executed in the order in which they are written. The curly brackets or braces on lines 2 and 4 serve to enclose the body of the function main. They must be present in matched pairs. Line 3 is the heart of this simple program. The word printf is a library function, which has something to do with printing. This means that the actual instructions for displaying on the screen are copied into your program from a library of already compiled useful functions. This process of putting together a program from a collection of already compiled bits and pieces are known as linking and is often done by a linker or loader program as distinct from a compiler.

2.8 Example UDP Client Program and steps for executing it. This client program establishes a socket connection and sends the message "Hello" to the server application. 2.8.1 Server Program

This server program establishes a socket connection and receives data from a client application. /* server program, run this first */ #include <string.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h>

23

main() { int sockint, s, namelen, client_address_size; struct sockaddr_in client, server; char buf[32];

/* create datagram socket using UDP */ printf("Creating datagram socket.\n"); s = socket(AF_INET, SOCK_DGRAM, 0); if( s == -1 ) printf("Socket was not created.\n"); else printf("Socket created successfully.\n");

/* set up the server name */ server.sin_family = AF_INET; server.sin_port = 0; /* use first available port number */ server.sin_addr.s_addr = INADDR_ANY;

if( bind(s, &server, sizeof( server )) < 0 ) { printf("Error binding server.\n"); exit(3); }

/* find out what port was assigned */ namelen = sizeof( server ); if( getsockname( s, (struct sockaddr *) &server, &namelen) < 0 ) { perror("getsockname()\n"); exit(3); }

24

printf("The assigned port is %d\n", ntohs( server.sin_port));

/* receive message on socket s in buf */ client_address_size = sizeof( client ); printf("Waiting for a message to arrive.\n"); if( recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr *) &client,

&client_address_size) < 0 ) { printf("recvfrom()\n"); exit(4); } /* print the message */ printf("Data has been sent to the socket\n"); printf("The message was\n"); printf("%s\n", buf );

printf("Closing the socket connection.\n"); close(s); printf("Socket closed.\n"); }

2.8.2 Client Program

#include <string.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h>

main( argc, argv)

25

int argc; char **argv; { int s; unsigned short port; struct sockaddr_in server; char buf[32];

/* argv[1] is internet address of server argv[2] is port number Convert the port from ascii to integer and then from host byte order to network byte order using htons() */ port = htons( atoi( argv[2] ));

/* create datagram socket using UDP */ printf("Creating datagram socket.\n"); s = socket(AF_INET, SOCK_DGRAM, 0); if( s == -1 ) printf("Socket was not created.\n"); else printf("Socket created successfully.\n");

/* set up the server name */ server.sin_family = AF_INET; server.sin_port = port; server.sin_addr.s_addr = inet_addr( argv[1] );

strcpy( buf, "Hello" ); printf("Sending data to the socket.\n");

26

sendto( s, buf, (strlen(buf)+1), 0, &server, sizeof(server ) ); printf("Data has been sent to the socket\n"); printf("Closing the socket connection.\n"); close(s); printf("Socket closed.\n"); }

2.8.3 Compiling and running the example programs Type the following commands. $ cd $HOME $ mkdir sockets $ cd sockets $ mkdir udp $ cd udp $ cp /etc/demo/socket/client1.c client1.c $ cp /etc/demo/socket/server1.c server1.c $ cc client1.c $ cp a.out client1.out $ cc server1.c $ cp a.out server1.out

The command sequence first establishes a subdirectory where the examples and programs will be stored. The sample programs are then copied into this new directory. After compiling the client program, the executable file is copied to a.out because this will be lost when the server program is compiled. After typing all the commands about, the client application is stored in client1.out and the server application in server1.out. The server application is started first. You will be required to have two telnet sessions running at the same time, one in which you can run the server application, the other in which you will run the client application. Then run the server program by typing the following command. $ server1.out

27

Write down the port number and TCP/IP address that the server application is using. Leave the current telnet session running. Start another telnet session and login to the computer. Type the following commands (but replace IP_ADDRESS and PORT with the values displayed by the server application). $ cd sockets/udp $ client1.out IP_ADDRESS PORT

2.9 The echo program This example program reads from stdin and writes to stdout using getchar() and putchar(). #include <stdio.h> main() /* type1.c a simple program to echo stdin to stdout */ { int c; printf("Please begin typing. To finish, type 'F'\n"); c = getchar(); while( c != 'F' ) { putchar(c); c = getchar(); } } What we shall develop now is to modify the existing client1.c and server1.c programs so that client2 sends the typed data to server2, which displays it on stdout and then type the following commands. $ cd $HOME $ cd sockets/udp $ cp client1.c client2.c $ cp server1.c server2.c

28

Modify the file client2.c so that it reads data from stdin and sends the data to the socket connection. This should continue whilst an 'F' is not typed. When an F is typed, the F should be sent to the socket and the program should then close the socket and terminate (see listing ?? for psuedo code example). Modify the file server2.c so that it reads data from the socket connection and displays this on stdout. If an F is read, the F is displayed, then the socket is closed and the server application terminates (see listing ?? for psuedo code example). After compiling the client program, copy the file a.out to client2.out. After compiling the server program, copy the file a.out to server2.out.

29

EXERCISE:
1. List the types of socket. 2. Write the various functions performed by the system calls. 3. Write a program to create a socket and bind it to a port number. 4. List the various system calls for client. 5. What is the purpose of Connect, getsockname and Accept functions? 6. How to set up a destination address and port number for an application program? 7. Write a simple echo program. 8. How to compile and run a socket program? 9. Explain the communication between a client and a server. 10. List the services provided by the ports 22,25,79,21 and 23.

30

3. TCP CHAT PROGRAM

3.1.

Algorithm

TCP chat server

1. Create a socket and bind an address to it. 2. Make the socket to listen for clients 3. When a client sends a request, accept it. 4. Receive message from the client and display it in the terminal. 5. Get a message from the user and send it back to the client. 6. Repeat step 4 & 5 till user enters Exit. 7. Close the socket.

TCP chat client

1. Create a socket and connect with the server. 2. Get message from the user and send it to the server. 3. Read the message from the server and display it in the terminal. 4. Repeat step 2 & 3 until server sends Exit. 5. Close the socket.

3.2.

TCP Chat Server program.

#include<stdio.h> #include<netinet/in.h> #include<sys/types.h> #include<sys/socket.h> #include<netdb.h> #include<string.h>

31

#define MAX 80 #define PORT 43454 #define SA struct sockaddr

void func(int sockfd) { char buff[MAX]; int n; for(;;) { bzero(buff,MAX); read(sockfd,buff,sizeof(buff)); printf("From client: %s\t To client : ",buff); bzero(buff,MAX); n=0; while((buff[n++]=getchar())!='\n'); write(sockfd,buff,sizeof(buff)); if(strncmp("exit",buff,4)==0) { printf("Server Exit...\n"); break; } } }

int main() { int sockfd,connfd,len; struct sockaddr_in servaddr,cli;

sockfd=socket(AF_INET,SOCK_STREAM,0);

32

if(sockfd==-1) { printf("socket creation failed...\n"); exit(0); } else printf("Socket successfully created..\n");

bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family=AF_INET; servaddr.sin_addr.s_addr=htonl(INADDR_ANY); servaddr.sin_port=htons(PORT);

if((bind(sockfd,(SA *)&servaddr,sizeof(servaddr)))!=0) { printf("socket bind failed...\n"); exit(0); } else printf("Socket successfully binded..\n");

if((listen(sockfd,5))!=0) { printf("Listen failed...\n"); exit(0); } else printf("Server listening..\n");

len=sizeof(cli); connfd=accept(sockfd,(SA *)&cli,&len);

33

if(connfd<0) { printf("server acccept failed...\n"); exit(0); } else printf("server acccept the client...\n");

func(connfd); close(sockfd); }

3.3.

TCP Chat Client program.

#include<stdio.h> #include<netinet/in.h> #include<sys/types.h> #include<sys/socket.h> #include<netdb.h> #include<string.h>

#define MAX 80 #define PORT 43454 #define SA struct sockaddr

void func(int sockfd) { char buff[MAX]; int n; for(;;)

34

{ bzero(buff,sizeof(buff)); printf("Enter the string : "); n=0; while((buff[n++]=getchar())!='\n'); write(sockfd,buff,sizeof(buff));

bzero(buff,sizeof(buff)); read(sockfd,buff,sizeof(buff)); printf("From Server : %s",buff);

if((strncmp(buff,"exit",4))==0) { printf("Client Exit...\n"); break; } } } int main() { int sockfd,connfd; struct sockaddr_in servaddr,cli; sockfd=socket(AF_INET,SOCK_STREAM,0); if(sockfd==-1) { printf("socket creation failed...\n"); exit(0); } else printf("Socket successfully created..\n");

35

bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family=AF_INET; servaddr.sin_addr.s_addr=inet_addr("127.0.0.1"); servaddr.sin_port=htons(PORT); if(connect(sockfd,(SA *)&servaddr,sizeof(servaddr))!=0) { printf("connection with the server failed...\n"); exit(0); } else printf("connected to the server..\n"); func(sockfd); close(sockfd); }

3.4.

Compilation Steps

gcc tcpchats.c . /a.out gcc tcpchatc.c . /a.out 3.5. Server From client: Hello To client: Hai From client: exit Server exit... Client: To server: Hello From server: Hai To server: Exit Output

36

4.

TCP ECHO PROGRAM

4.1.

Algorithm

TCP echo server

1. Create a socket and bind an address to it. 2. Make the socket to listen for clients 3. When a client sends a request, accept it. 4. Receive message from the client and display it in the terminal. 5. Send the message back to the client. 6. Repeat step 4 & 5 till user enters exit. 7. Close the socket.

TCP echo client

1. Create a socket and connect with the server. 2. Get message from the user and send it to the server. 3. Read the message from the server and display it in the terminal. 4. Repeat step 2 & 3 until server sends Exit. 5. Close the socket.

4.2.

TCP Echo Server program

#include<stdio.h> #include<netinet/in.h> #include<sys/types.h> #include<sys/socket.h> #include<netdb.h> #include<string.h>

37

#define MAX 80 #define PORT 43454 #define SA struct sockaddr

void func(int sockfd) { char buff[MAX]; for(;;) { bzero(buff,MAX); read(sockfd,buff,sizeof(buff)); printf("From client: %s\n",buff); write(sockfd,buff,sizeof(buff)); if(strncmp("exit",buff,4)==0) { printf("Server Exit...\n"); break; } } }

int main() { int sockfd,connfd,len; struct sockaddr_in servaddr,cli;

sockfd=socket(AF_INET,SOCK_STREAM,0); if(sockfd==-1) { printf("socket creation failed...\n"); exit(0);

38

} else printf("Socket successfully created..\n");

bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family=AF_INET; servaddr.sin_addr.s_addr=htonl(INADDR_ANY); servaddr.sin_port=htons(PORT);

if((bind(sockfd,(SA *)&servaddr,sizeof(servaddr)))!=0) { printf("socket bind failed...\n"); exit(0); } else printf("Socket successfully binded..\n"); if((listen(sockfd,5))!=0) { printf("Listen failed...\n"); exit(0); } else printf("Server listening..\n");

len=sizeof(cli); connfd=accept(sockfd,(SA *)&cli,&len);

if(connfd<0) { printf("server acccept failed...\n"); exit(0);

39

} else printf("server acccept the client...\n");

func(connfd); close(sockfd); }

4.3.

TCP Echo Client program

#include<stdio.h> #include<netinet/in.h> #include<sys/types.h> #include<sys/socket.h> #include<netdb.h> #include<string.h>

#define MAX 80 #define PORT 43454 #define SA struct sockaddr

void func(int sockfd) { char buff[MAX]; int n; for(;;) { bzero(buff,sizeof(buff)); printf("Enter the string : "); n=0; while((buff[n++]=getchar())!='\n');

40

write(sockfd,buff,sizeof(buff));

bzero(buff,sizeof(buff)); read(sockfd,buff,sizeof(buff)); printf("From Server : %s",buff);

if((strncmp(buff,"exit",4))==0) { printf("Client Exit...\n"); break; } } }

int main() { int sockfd,connfd; struct sockaddr_in servaddr,cli;

sockfd=socket(AF_INET,SOCK_STREAM,0); if(sockfd==-1) { printf("socket creation failed...\n"); exit(0); } else printf("Socket successfully created..\n");

bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family=AF_INET; servaddr.sin_addr.s_addr=inet_addr("127.0.0.1");

41

servaddr.sin_port=htons(PORT);

if(connect(sockfd,(SA *)&servaddr,sizeof(servaddr))!=0) { printf("connection with the server failed...\n"); exit(0); } else printf("connected to the server..\n");

func(sockfd);

close(sockfd); } 4.3. Compilation Steps

gcc tcpechos.c ./a.out gcc tcpechoc.c ./a.out

4.4.

Output

Client: Enter string: Hello From server: Hello Enter string: exit Server: From client: Hello From client: exit

42

5. TCP FILE TRANSFER PROGRAM

5.1 Algorithm

TCP file transfer server

1. Create a socket and bind an address to it. 2. Make the socket to listen for clients 3. When a client sends a request, accept it. 4. Receive data from the client and display it in the terminal. 5. Open a new file and save the contents. 6. Close the socket.

TCP file transfer client

1. Create a socket and connect with the server. 2. Open a file and send the contents to the server. 3. Close the socket.

5.2.

TCP File Transfer Server program.

#include<stdio.h> #include<netinet/in.h> #include<sys/types.h> #include<sys/socket.h> #include<netdb.h> #include<string.h>

#define MAX 80 #define PORT 43454

43

#define SA struct sockaddr

void func(int sockfd) { char buff[MAX]; FILE *fp;

bzero(buff,MAX); read(sockfd,buff,sizeof(buff)); printf("From client: %s\n",buff);

fp=fopen("sfile","a"); fputs(buff,fp); close(fp); }

int main() { int sockfd,connfd,len; struct sockaddr_in servaddr,cli;

sockfd=socket(AF_INET,SOCK_STREAM,0); if(sockfd==-1) { printf("socket creation failed...\n"); exit(0); } else printf("Socket successfully created..\n");

bzero(&servaddr,sizeof(servaddr));

44

servaddr.sin_family=AF_INET; servaddr.sin_addr.s_addr=htonl(INADDR_ANY); servaddr.sin_port=htons(PORT);

if((bind(sockfd,(SA *)&servaddr,sizeof(servaddr)))!=0) { printf("socket bind failed...\n"); exit(0); } else printf("Socket successfully binded..\n");

if((listen(sockfd,5))!=0) { printf("Listen failed...\n"); exit(0); } else printf("Server listening..\n");

len=sizeof(cli); connfd=accept(sockfd,(SA *)&cli,&len);

if(connfd<0) { printf("server acccept failed...\n"); exit(0); } else printf("server acccept the client...\n");

45

func(connfd); close(sockfd); } 5.3. TCP File Transfer Client program.

#include<stdio.h> #include<netinet/in.h> #include<sys/types.h> #include<sys/socket.h> #include<netdb.h> #include<string.h>

#define MAX 200 #define PORT 43454 #define SA struct sockaddr

void func(int sockfd) { char buff[MAX]; FILE *fp; int n;

bzero(buff,sizeof(buff)); fp=fopen("clifile","r"); bzero(buff,MAX); n=0; while((buff[n++]=getc(fp))!=EOF); write(sockfd,buff,sizeof(buff));

close(fp);

46

int main() { int sockfd,connfd; struct sockaddr_in servaddr,cli;

sockfd=socket(AF_INET,SOCK_STREAM,0); if(sockfd==-1) { printf("socket creation failed...\n"); exit(0); } else printf("Socket successfully created..\n");

bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family=AF_INET; servaddr.sin_addr.s_addr=inet_addr("127.0.0.1"); servaddr.sin_port=htons(PORT);

if(connect(sockfd,(SA *)&servaddr,sizeof(servaddr))!=0) { printf("connection with the server failed...\n"); exit(0); } else printf("connected to the server..\n");

func(sockfd); close(sockfd);

47

} 5.4. Compilation Steps

gcc tcpfiles.c ./a.out

gcc tcpfilec.c ./a.out

5.5.

Output

Client:

Server: From client: Hello How are you

48

6. UDP CHAT PROGRAM

6.1.

Algorithm

UDP chat server

1. Create a socket. 2. Receive message from the client and display it in the terminal. 3. Get a message from the user and send it back to the client. 4. Repeat step 2 & 3 till user enters Exit. 5. Close the socket.

UDP chat client

1. Create a socket. 2. Get message from the user and send it to the server. 3. Read the message from the server and display it in the terminal. 4. Repeat step 2 & 3 until server sends Exit.

6.2.

UDP Chat Server program

#include<stdio.h> #include<netinet/in.h> #include<sys/types.h> #include<sys/socket.h> #include<netdb.h> #include<string.h>

#define MAX 80 #define PORT 43454 #define SA struct sockaddr

49

void func(int sockfd) { char buff[MAX]; int n,clen; struct sockaddr_in cli;

clen=sizeof(cli); for(;;) { bzero(buff,MAX); recvfrom(sockfd,buff,sizeof(buff),0,(SA *)&cli,&clen); printf("From client: %s\t To client : ",buff); bzero(buff,MAX); n=0; while((buff[n++]=getchar())!='\n'); sendto(sockfd,buff,sizeof(buff),0,(SA *)&cli,clen); if(strncmp("exit",buff,4)==0) { printf("Server Exit...\n"); break; } } }

int main() { int sockfd; struct sockaddr_in servaddr; sockfd=socket(AF_INET,SOCK_DGRAM,0); if(sockfd==-1)

50

{ printf("socket creation failed...\n"); exit(0); } else printf("Socket successfully created..\n"); bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family=AF_INET; servaddr.sin_addr.s_addr=htonl(INADDR_ANY); servaddr.sin_port=htons(PORT); if((bind(sockfd,(SA *)&servaddr,sizeof(servaddr)))!=0) { printf("socket bind failed...\n"); exit(0); } else printf("Socket successfully binded..\n"); func(sockfd); close(sockfd); }

6.3.

UDP Chat Client program

#include<stdio.h> #include<netinet/in.h> #include<sys/types.h> #include<sys/socket.h> #include<netdb.h> #include<string.h>

#define MAX 80

51

#define PORT 43454 #define SA struct sockaddr

int main() { char buff[MAX]; int sockfd,len,n; struct sockaddr_in servaddr; sockfd=socket(AF_INET,SOCK_DGRAM,0); if(sockfd==-1) { printf("socket creation failed...\n"); exit(0); } else printf("Socket successfully created..\n"); bzero(&servaddr,sizeof(len)); servaddr.sin_family=AF_INET; servaddr.sin_addr.s_addr=inet_addr("127.0.0.1"); servaddr.sin_port=htons(PORT);

len=sizeof(servaddr); for(;;) { printf("\nEnter string : "); n=0; while((buff[n++]=getchar())!='\n'); sendto(sockfd,buff,sizeof(buff),0,(SA *)&servaddr,len); bzero(buff,sizeof(buff)); recvfrom(sockfd,buff,sizeof(buff),0,(SA *)&servaddr,&len); printf("From Server : %s\n",buff);

52

if(strncmp("exit",buff,4)==0) { printf("Client Exit...\n"); break; } } close(sockfd); }

6.4.

Compilation Steps

gcc udpchats.c ./a.out gcc udpchatc.c ./a.out

6.5. Server

Output

From client: Hello To client: Hai From client: exit Server exit..

Client To server: Hello From server: Hai To server: exit

53

7. UDP ECHO PROGRAM

7.1.

Algorithm

UDP echo server

1. Create a socket. 2. Receive message from the client and display it in the terminal. 3. Send it back to the client. 4. Repeat step 2 & 3 till user enters Exit. 5. Close the socket.

UDP echo client

1. Create a socket. 2. Get message from the user and send it to the server. 3. Read the message from the server and display it in the terminal. 4. Repeat step 2 & 3 until server sends Exit.

7.2.

UDP Echo Server program

#include<stdio.h> #include<netinet/in.h> #include<sys/types.h> #include<sys/socket.h> #include<netdb.h> #include<string.h>

#define MAX 80 #define PORT 43454 #define SA struct sockaddr

54

int main() { char buff[MAX]; int sockfd,len,n; struct sockaddr_in servaddr;

sockfd=socket(AF_INET,SOCK_DGRAM,0); if(sockfd==-1) { printf("socket creation failed...\n"); exit(0); } else printf("Socket successfully created..\n");

bzero(&servaddr,sizeof(len)); servaddr.sin_family=AF_INET; servaddr.sin_addr.s_addr=inet_addr("127.0.0.1"); servaddr.sin_port=htons(PORT);

len=sizeof(servaddr); for(;;) { printf("\nEnter string : "); n=0; while((buff[n++]=getchar())!='\n');

sendto(sockfd,buff,sizeof(buff),0,(SA *)&servaddr,len); bzero(buff,sizeof(buff)); recvfrom(sockfd,buff,sizeof(buff),0,(SA *)&servaddr,&len);

55

printf("From Server : %s\n",buff);

if(strncmp("exit",buff,4)==0) { printf("Client Exit...\n"); break; } }

close(sockfd); }

7.3.

UDP Echo Client program.

#include<stdio.h> #include<netinet/in.h> #include<sys/types.h> #include<sys/socket.h> #include<netdb.h> #include<string.h>

#define MAX 80 #define PORT 43454 #define SA struct sockaddr

int main() { char buff[MAX]; int sockfd,len,n; struct sockaddr_in servaddr;

56

sockfd=socket(AF_INET,SOCK_DGRAM,0); if(sockfd==-1) { printf("socket creation failed...\n"); exit(0); } else printf("Socket successfully created..\n");

bzero(&servaddr,sizeof(len)); servaddr.sin_family=AF_INET; servaddr.sin_addr.s_addr=inet_addr("127.0.0.1"); servaddr.sin_port=htons(PORT);

len=sizeof(servaddr); for(;;) { printf("\nEnter string : "); n=0; while((buff[n++]=getchar())!='\n');

sendto(sockfd,buff,sizeof(buff),0,(SA *)&servaddr,len); bzero(buff,sizeof(buff)); recvfrom(sockfd,buff,sizeof(buff),0,(SA *)&servaddr,&len); printf("From Server : %s\n",buff);

if(strncmp("exit",buff,4)==0) { printf("Client Exit...\n"); break; }

57

close(sockfd); }

7.4.

Compilation Steps

gcc udpechos.c ./a.out

gcc udpechoc.c ./a.out

7.5.

Output

Client: Enter string: Hello From server: Hello Enter string: Exit From server: Exit

Server: From client: Hello From client: Exit

58

8. UDP FILE TRANSFER PROGRAM

8.1.

Algorithm

UDP file transfer server

1. Create a socket. 2. Receive file content from the client and display it in the terminal. 3. Open a new file and save it.

UDP file transfer client

1. Create a socket. 2. Open a file and send the contents to the server.

8.2.

UDP File Server program

#include<stdio.h> #include<netinet/in.h> #include<sys/types.h> #include<sys/socket.h> #include<netdb.h> #include<string.h>

#define MAX 80 #define PORT 43454 #define SA struct sockaddr

void func(int sockfd) { char buff[MAX];

59

int len; FILE *fp; struct sockaddr_in client;

len=sizeof(client); bzero(buff,MAX); recvfrom(sockfd,buff,sizeof(buff),0,(SA*)&client,&len); printf("From client: %s\n",buff);

fp=fopen("sfile","a"); fputs(buff,fp); close(fp); }

int main() { int sockfd; struct sockaddr_in servaddr; sockfd=socket(AF_INET,SOCK_DGRAM,0); if(sockfd==-1) { printf("socket creation failed...\n"); exit(0); } else printf("Socket successfully created..\n");

bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family=AF_INET; servaddr.sin_addr.s_addr=htonl(INADDR_ANY); servaddr.sin_port=htons(PORT);

60

if((bind(sockfd,(SA *)&servaddr,sizeof(servaddr)))!=0) { printf("socket bind failed...\n"); exit(0); } else printf("Socket successfully binded..\n");

func(sockfd);

close(sockfd); }

8.3.

UDP File Client program.

#include<stdio.h> #include<netinet/in.h> #include<sys/types.h> #include<sys/socket.h> #include<netdb.h> #include<string.h> #define MAX 80 #define PORT 43454 #define SA struct sockaddr

int main() { char buff[MAX]; int sockfd,len,n; FILE *fp;

61

struct sockaddr_in servaddr;

sockfd=socket(AF_INET,SOCK_DGRAM,0); if(sockfd==-1) { printf("socket creation failed...\n"); exit(0); } else printf("Socket successfully created..\n");

bzero(&servaddr,sizeof(len)); servaddr.sin_family=AF_INET; servaddr.sin_addr.s_addr=inet_addr("127.0.0.1"); servaddr.sin_port=htons(PORT);

len=sizeof(servaddr);

bzero(buff,sizeof(buff)); fp=fopen("clifile","r"); bzero(buff,MAX); n=0; while((buff[n++]=getc(fp))!=EOF); sendto(sockfd,buff,sizeof(buff),0,(SA*)&servaddr,sizeof(servaddr));

close(fp); close(sockfd); }

62

8.4.

Compilation Steps

gcc udpfiles.c ./a.out

gcc udpfilec.c ./a.out

8.5.

Output

Client Socket created

Server Socket created From client : Hello

63

9.

SLIDING WINDOW PROGRAM

Sliding window protocol is used by the transmission control protocol which sends data into a network. The protocol varies the number of segments that are sent out at each transmission depending on the current network conditions: if the network is heavily loaded then a small number is sent; if the network is lightly loaded then many more are sent. The collection of segments sent is known as a window. This protocol is occasionally referred to as the slow start protocol. Its a feature of packet-based data transmission protocols. Sliding window protocols are used where reliable in-order delivery of segments is required, such as in the data link layer as well as in the transport layer of ISO/OSI model. Conceptually, each portion of the transmission is assigned a unique consecutive sequence number, and the receiver uses the numbers to place received segments in the correct order, discarding duplicate segments and identifying missing ones. The problem with this is that there is no limit of the size of the sequence numbers that can be required. By placing limits on the number of segments that can be transmitted or received at any given time, a sliding window protocol allows an unlimited number of segments to be communicated using fixed-size sequence numbers. For the highest possible throughput, it is important that the sender is not forced to stop sending by the sliding window protocol earlier than one round-trip delay time (RTT). The limit on the amount of data that it can send before stopping to wait for an acknowledgment should be larger than the bandwidth-delay product of the communications link. If it is not, the protocol does not allow the effective utilization of the available bandwidth. The simplest sliding window is stop-and-wait ARQ protocol. After sending each segment, the sender doesn't send any further segments until it receives an acknowledgement (ACK) signal from the receiver. After receiving a good frame, the receiver sends an ACK to the sender. If the ACK does not reach the sender before a certain time, known as the timeout, the sender sends the same frame again. Stop and wait

64

flow protocol is a special variant of the sliding window protocol where the size of the sender window and the receiver window is 1. Thus, N=1+1=2 possible sequence numbers (conveniently represented by a single bit) are required. A general sliding window protocol allows the size of the window to be greater than 1. One type of generic sliding window protocol is Go-Back-N ARQ where the receiver refuses to accept any segment but the next one in sequence. If a packet is lost in transit, following segments are ignored until the missing packet is retransmitted, a minimum loss of one round trip time. For this reason, it is inefficient on links that suffer frequent packet loss. The receiver process keeps track of the sequence number of the next frame it expects to receive, and sends that number with every ACK it sends. The receiver will ignore any frame that does not have the exact sequence number it expects whether that frame is a "past" duplicate of a frame it has already ACK'ed or whether that frame is a "future" frame past the last packet it is waiting for. Once the sender has sent all of the segments in its window, it will detect that all of the segments since the first lost frame are outstanding, and will go back to sequence number of the last ACK it received from the receiver process and fill its window starting with that frame and continue the process over again. The most general case of the sliding window protocol is Selective Repeat ARQ. This requires a much more capable receiver, which can accept segments with sequence numbers highe r than the current nr and store them until the gap is filled in. It may be used as a protocol for the delivery and acknowledgement of message units, or it may be used as a protocol for the delivery of subdivided message sub-units. It may be used as a protocol for the delivery and acknowledgement of message units, or it may be used as a protocol for the delivery of subdivided message sub-units. When used as the protocol for the delivery of messages, the sending process continues to send a number of segments specified by a window size even after a frame loss. Unlike Go-Back-N ARQ, the receiving process will continue to accept and acknowledge segments sent after an initial error; this is the general case of the sliding window protocol with both transmit and receive window sizes greater than 1.

65

When used as the protocol for the delivery of subdivided messages it works somewhat differently. In non-continuous channels where messages may be variable in length, standard ARQ or Hybrid ARQ protocols may treat the message as a single unit. The advantage, however, is that it is not necessary to discard following correct data for one round-trip time before the transmitter can be informed that a retransmission is required. This is therefore preferred for links with low reliability and/or a high bandwidth-delay product. The window size wr need only be larger than the number of consecutive lost segments that can be tolerated. Thus, small values are popular; wr=2 is common. 9.1. Algorithm

Reciever

1. Create a socket and bind an address to it. 2. Make the socket to listen for clients 3. When a client sends a request, accept it. 4. Receive data from the client and print it. 5. Send acknowledgement to the client. 6. Close the socket.

Sender

1. Create a socket and connect with the server. 2. Create a send and receive buffer and calculate sequence no. & segments to be sent as given in Sliding Window Protocol 3. Read acknowledgement from the server and display it and repeat the process. 4. Close the socket.

66

9.2.

Sliding window sender program

#include<stdio.h> #include<stdlib.h> #include<sys/socket.h> #include<sys/types.h> #include<string.h> #include<netinet/in.h> #include<arpa/inet.h> #define portno 3337 #define ipaddr "127.0.0.1" #define max 100 #define MAX_SEQ 20

int main(int argc, char *argv[]) { int clientfd,sqn_no=0,SWS=4; int last_ack,ackno,intrans=0,flg; struct sockaddr_in server; char buffer[max];

clientfd=socket(AF_INET,SOCK_STREAM,0); if(clientfd<0) { perror("Unable to create socket"); exit(1); } bzero(&server,sizeof(server)); server.sin_family=AF_INET; server.sin_port=htons(portno); if(inet_pton(AF_INET,"127.0.0.1",&(server.sin_addr))<0)

67

{ perror("Error in client"); exit(1); } if(connect(clientfd,(struct sockaddr*)&server,sizeof(server))<0) { perror("connect error"); close(clientfd); exit(1); } printf("Connected \n");

flg=0; SWS=4; sqn_no=1; intrans=0; last_ack=1; while(1) {

while( (flg==0 && SWS>(sqn_no-last_ack)) || (flg==1 && SWS>(sqn_no+20last_ack))) { printf("\nCurrent sender window

=(%d,%d,%d,%d)",last_ack,(last_ack+1)%20,(last_ack+2)%20,(last_ack+3)%20); bzero(buffer,sizeof(buffer)); sprintf(buffer,"%d ",sqn_no); if(write(clientfd,buffer,sizeof(buffer))<0) { printf("Send error"); close(clientfd);

68

exit(1); } intrans=intrans+1; printf("\nsequence no %d sent ",sqn_no); printf("\nNo of packet in transit = %d",intrans);

sqn_no++; if(sqn_no>=20) { flg=1; sqn_no=(sqn_no)%MAX_SEQ; } } sleep(2); bzero(buffer,sizeof(buffer)); read(clientfd,buffer,sizeof(buffer)); intrans--; sscanf(buffer,"%d",&ackno); printf("\nReceived ACK%d == %d\n",ackno,last_ack); if(ackno==last_ack) { last_ack++; if(last_ack>=20) { flg=0; last_ack=(last_ack)%MAX_SEQ; } } } }

69

9.3.

Sliding window receiver Program

#include<netinet/in.h> #include<sys/types.h> #include<stdlib.h> #include<sys/socket.h> #include<arpa/inet.h> #include<stdio.h> #include<string.h> #define MAXLINE 100 #define ipaddr "127.0.0.1" #define SERV_PORT 3337

void str_chat(int sockfd) { ssize_t n; int sqn_no; char line[MAXLINE]; for(;;) { if(read(sockfd,line,MAXLINE)<=0) { printf("\ncanot read from socket"); return; } write(sockfd,line,MAXLINE); } close(sockfd); }

int main(int argc,char **argv)

70

{ int listenfd,connfd; pid_t childpid; char buff[100]; socklen_t clilen; struct sockaddr_in cliaddr,servaddr; listenfd=socket(AF_INET,SOCK_STREAM,0); printf("Socket created\n"); bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family=AF_INET; inet_pton(AF_INET,ipaddr,&(servaddr.sin_addr)); servaddr.sin_port=htons(SERV_PORT); if(bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr))<0); printf("\nno bind error"); listen(listenfd,5); clilen=sizeof(cliaddr); connfd=accept(listenfd,(struct sockaddr*)&cliaddr,&clilen);

printf("\nServer connected "); // str_chat(connfd);

while(1) { bzero(buff, sizeof(buff)); read(connfd,buff,sizeof(buff)); printf("\nPacket%s acknowledged", buff); write(connfd,buff,sizeof(buff)); } close(connfd);

71

9.4.

Compilation steps

gcc slideser.c ./a.out gcc slidecli.c ./a.out

9.5.

Output

Server: Packet hello acknowledged Packet exit acknowledged

Client Current sender Window (1,2,3,4) Sequence no 1 sent No. of packet in transit : 1

72

10. ARP PROGRAM Address Resolution Protocol is a network layer protocol used to convert an IP address into a physical address (called a MAC address), such as an Ethernet address. A host wishing to obtain a physical address broadcasts an ARP request onto the TCP/IP network. The host on the network that has the IP address in the request then replies with its physical hardware address. There is also Reverse ARP (RARP) which can be used by a host to discover its IP address. In this case, the host broadcasts its physical address and a RARP server replies with the host's IP address. 10.1. Algorithm

ARP server

1. Create a socket and bind an address to it. 2. Make the socket to listen for clients 3. When a client sends a request, accept it. 4. Receive address from the client and search for its corresponding MAC address. 5. Send MAC address to the client. 6. Close the socket.

ARP client

1. Create a socket and connect with the server. 2. Get IP address from the user and send it to the server. 3. Read the MAC address from the server and display it in the terminal. 4. Close the socket.

73

10.2. ARP Server Program

#include<stdio.h> #include<string.h> #include<stdlib.h> #include<sys/socket.h> #include<sys/types.h> #include<arpa/inet.h> #include<netinet/in.h> #include<netdb.h> #include<error.h>

#define max 100 struct arpdata { uint16_t htype,ptype,opr; uint8_t hlen,plen; char shaddr[48],thaddr[48]; char sipaddr[32],tipaddr[32]; };

struct node { char ipaddr[32]; char haddr[48]; };

int tcp_listen(const char *host,const char *serv,socklen_t *addrlenp) { int listenfd; struct addrinfo hints,*res,*ressave;

74

bzero(&hints,sizeof(struct addrinfo)); hints.ai_flags=AI_PASSIVE; hints.ai_family=AF_UNSPEC; hints.ai_socktype=SOCK_STREAM; getaddrinfo(host,serv,&hints,&res); ressave=res; do { listenfd=socket(res->ai_family,res->ai_socktype,res->ai_protocol); if(listenfd<0) continue; if(bind(listenfd,res->ai_addr,res->ai_addrlen)==0) break; close(listenfd); }while((res=res->ai_next)!=NULL);

listen(listenfd,2); if(addrlenp) *addrlenp=res->ai_addrlen; freeaddrinfo(ressave); return listenfd; }

int main(int argc,char **argv) { int listenfd,connfd,i,n; struct sockaddr *cliaddr; char buff[max]; struct node d[]={ {"10.0.0.1","ff.gg.hh.0x4322h.o4xd"}, {"20.0.0.1","xx.ff.gl.0923.3.42254"}

75

}; struct arpdata r; socklen_t addrlen; listenfd=tcp_listen(NULL,argv[1],&addrlen); cliaddr=malloc(addrlen); connfd=accept(listenfd,cliaddr,&addrlen); bzero(&r,sizeof(struct arpdata)); read(connfd,&r,sizeof(struct arpdata)); printf("\nIPaddr = %s",r.tipaddr); for(i=0;i<2;i++) { if(!strcmp(r.tipaddr,d[i].ipaddr)) { strcpy(r.thaddr,d[i].haddr); write(connfd,&r,sizeof(struct arpdata)); break; } } if(i==2) { strcpy(r.thaddr,"ip address not found"); write(connfd,&r,sizeof(struct arpdata)); } close(connfd); close(listenfd); }

76

10.3. ARP Client Program

#include<stdio.h> #include<string.h> #include<stdlib.h> #include<sys/socket.h> #include<sys/types.h> #include<arpa/inet.h> #include<netinet/in.h> #include<netdb.h> #include<error.h>

#define max 100 struct arpdata { uint16_t htype,ptype,orp; uint8_t hlen,plen; char shaddr[48],thaddr[48]; char sipaddr[32],tipaddr[32]; };

int tcp_connect(const char *host,const char *serv) { int sockfd; struct addrinfo hints,*res,*ressave; bzero(&hints,sizeof(struct addrinfo)); hints.ai_family=AF_UNSPEC; hints.ai_socktype=SOCK_STREAM; getaddrinfo(host,serv,&hints,&res); ressave=res; do

77

{ sockfd=socket(res->ai_family,res->ai_socktype,res->ai_protocol); if(sockfd<0) continue; if(connect(sockfd,res->ai_addr,res->ai_addrlen)==0) break; close(sockfd); }while((res=res->ai_next)!=NULL);

freeaddrinfo(ressave); return sockfd; }

int main(int argc,char **argv) { int sockfd; struct sockaddr *cliaddr;

char buff[max]; struct arpdata r; sockfd=tcp_connect(argv[1],argv[2]); bzero(&r,sizeof(struct arpdata)); printf("\nEnter ipaddress = "); scanf("%s",r.tipaddr); write(sockfd,&r,sizeof(struct arpdata)); bzero(&r,sizeof(struct arpdata)); read(sockfd,&r,sizeof(struct arpdata)); printf("\nH/w address = %s",r.thaddr); close(sockfd); }

78

10.4.

Compilation Steps

gcc arpserver.c ./a.out gcc arpclient.c ./a.out

10.5.

Output

Client Enter IP address: 10.0.0.1 H/w addr: ff.gg.hh.0x4322h.o4xd

Server: IP address: 10.0.0.1

79

11. SHORTEST PATH PROGRAM

Shortest path algorithm is a graph search algorithm that solves the single-source shortest path problem for a graph with nonnegative edge path costs, producing a shortest path tree. This algorithm is often used in routing. For a given source vertex (node) in the graph, the algorithm finds the path with lowest cost (i.e. the shortest path) between that vertex and every other vertex. It can also be used for finding costs of shortest paths from a single vertex to a single destination vertex by stopping the algorithm once the shortest path to the destination vertex has been determined. The shortest path algorithm can be described in the following way. Let the node at which we are starting be called the initial node. The distance of node Y is the distance between the initial node and node Y. Dijkstra's algorithm will assign some initial distance values and will try to improve them step by step. 1. Assign to every node a distance value. Set it to zero for our initial node and to infinity for all other nodes. 2. Mark all nodes as unvisited. Set initial node as current. 3. For current node, consider all its unvisited neighbors and calculate their tentative distance (from the initial node). For example, if current node (A) has distance of 6, and an edge connecting it with another node (B) is 2, the distance to B through A will be 6+2=8. If this distance is less than the previously recorded distance (infinity in the beginning, zero for the initial node), overwrite the distance. 4. When we are done considering all neighbors of the current node, mark it as visited. A visited node will not be checked ever again; its distance recorded now is final and minimal. 5. If all nodes have been visited, finish. Otherwise, set the unvisited node with the smallest distance (from the initial node) as the next "current node" and continue from step 3.

80

11.1. Algorithm

Server

1. Create a socket. 2. Receive distance matrix from the client and find shortest path using Dijkstras shortest path algorithm. 3. Send it to the client.

Client

1. Create a socket. 2. Get distance matrix from the user 3. Send it to server and receive the new distance matrix 4. Display it in terminal

11.2. Server program

#include<stdio.h> #include<netinet/in.h> #include<sys/types.h> #include<sys/socket.h> #include<netdb.h> #include<string.h>

#define MAX 80 #define PORT 43454 #define SA struct sockaddr

void func(int sockfd) {

81

char buff[MAX]; int len; int I,j,a[5][5],n,k; struct sockaddr_in client;

len=sizeof(client); bzero(buff,MAX); recvfrom(sockfd,&a ,sizeof(a),0,(SA*)&client,&len); recvfrom(sockfd,&n,sizeof(n), 0,(SA*)&client,&len); for(I=0;I<n;I++) { for(j=0;j<n;j++) { for(k=0;k<n;k++) { if(a[I][j]>a[I][k]+a[k][j]) a[I][j]=a[I][k]+a[k][j]; } } } sendto(sockfd,&a,sizeof(a),0,(SA *)&client,len); } int main() { int sockfd; struct sockaddr_in servaddr; sockfd=socket(AF_INET,SOCK_DGRAM,0); if(sockfd==-1) { printf("socket creation failed...\n"); exit(0);

82

} else printf("Socket successfully created..\n");

bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family=AF_INET; servaddr.sin_addr.s_addr=htonl(INADDR_ANY); servaddr.sin_port=htons(PORT);

if((bind(sockfd,(SA *)&servaddr,sizeof(servaddr)))!=0) { printf("socket bind failed...\n"); exit(0); } else printf("Socket successfully binded..\n");

func(sockfd);

close(sockfd); }

11.3. Client program.

#include<stdio.h> #include<netinet/in.h> #include<sys/types.h> #include<sys/socket.h> #include<netdb.h> #include<string.h>

83

#define MAX 80 #define PORT 43454 #define SA struct sockaddr

int main() { char buff[MAX]; int sockfd,len,n; int a[5][5],I,j; int size; struct sockaddr_in servaddr;

sockfd=socket(AF_INET,SOCK_DGRAM,0); if(sockfd==-1) { printf("socket creation failed...\n"); exit(0); } else printf("Socket successfully created..\n");

bzero(&servaddr,sizeof(len)); servaddr.sin_family=AF_INET; servaddr.sin_addr.s_addr=inet_addr("127.0.0.1"); servaddr.sin_port=htons(PORT);

len=sizeof(servaddr);

printf(\nEnter no.of vertices: ); scanf(%d,&n); for(I=0;I<n;I++)

84

{ for(j=0;j<n;j++) { printf(\nEnter the distance from vertex %d to %d : (10000 for infinity) : ,I,j); scanf(%d,&a[I][j]); } } sendto(sockfd,&a,sizeof(a),0,(SA*)&servaddr,sizeof(servaddr)); sendto(sockfd,&n,sizeof(n), 0,(SA*)&servaddr,sizeof(servaddr)); recvfrom(sockfd,&a,sizeof(a),0, (SA*)&servaddr,&len); printf(\nShortest path : ); for(I=0;I<n;I++) printf(\n for(I=0;I<n;I++) { printf(\n %d | ,I); for(j=0;j<n;j++) { printf( %d ,a[I][j]); } printf(\n); } close(sockfd); } %d ,I);

85

11.4.

Compilation Steps

gcc spaths.c ./a.out gcc spathc.c ./a.out

11.5.

Output

Client Enter no. of vertices: 2 Enter the distance from vertex 1 to 1: 0 Enter the distance from vertex 1 to 2: 2 Enter the distance from vertex 2 to 1: 2 Enter the distance from vertex 2 to 2: 0 Shortest path: 1 1 0 2 2 2 2 0

86

Exercises: Implement the above applications using protocol independent functions. Implement the above applications using Threads instead of fork system call. Develop an application where the client is handling multiple descriptors. (Use I/O Multiplexing). Implement the operation of PING command by generating ICMP Echo request and reply segments over IPV4 and IPV6. Implement a client/server communication for performing DNS operation. Simulate the SNMP behavior using client/server communication. Implement the various refinements of TCP protocol ensuring reliability in Client/Server communication.

(Refer: Unix Network Programming by Richard Stevens).

87

88

You might also like