Sockets (Reference:, Gray Chapter 10) Network Programming Lecture Notes by 1 Introduction Turhan TUNALI Unix uses a common interface for the access of files and devices that reside on a single host. The common sequence is open read write close. Although a similar approach is taken for the system V IPC tools, the application for each tool introduced specific commands. The use of RPC is also complex and restrictive. What is needed is an extension of the read-write paradigm with the inclusion of sufficient networking semantics to permit unrelated processes, on different hosts, to communicate as if they were reading and writing to a local file. Two different Application Program Interfaces (API) are developed o Berkeley Socket Interface o Transport Level Interface (TLI) We will deal with Berkeley Sockets in this lecture.
A socket is an abstract data structure that is used to create a channel (connection point) to send and receive information between unrelated processes. A usual sequence of events can be as follows: o Server: Create socket Map the socket to a local address Wait for requests from clients o Client: Create socket Determine information (host name, port number) about server Send and receive information. 2 Communication Basics 2.1 Network Addresses Every host on a network has two unique addresses: o Ethernet address: Assigned by the manufacturer 48 bits Written in Hexadecimal notation Six eight bit numbers Example: Ethernet address of Abel is 8:0:20:85:69:5a
o Internet address Assigned by Internet authorities 32 bits Four eight bit numbers Written in decimal separated by dots Example: Internet address (IP) of Abel is 147.126.2.4 The system maps Internet address to Ethernet address. This is done by using Address Resolution Protocol (ARP). 2.2 Domains-Network and Communication
More convenient method is used to represent IP addresses. Ex: cs.luc.edu. Domain Name Server (DNS) provides the mapping between the latter and the IP addresses. In this lecture, we will use the term domain to indicate communication type for socket interface. There are two types of socket communication domains: o UNIX Domain: Sockets have actual file names Sockets can only be used with processes that reside in the same host o Internet Domain: Sockets allow unrelated processes on different hosts to communicate 2.3 Protocol Families We will mostly be dealing with UDP and TCP in this lecture. 2.4 Socket Types Data can be sent in two different ways: o Stream of bits o Datagrams containing address, error control and other information Accordingly, we specify two basic socket types: o Stream Sockets Reliable
Allow full-duplex communication Connection oriented o Datagram Sockets Unreliable Allow full-duplex communication Connectionless 3 IPC Using SOCKETPAIR The socketpair network call is used to create pair of sockets for UNIX domain: int socketpair ( int family, int type, int protocol, int sv[2] ); The first argument is set to PF_UNIX. o Later on we will use PF_INET for Internet. The second argument can be o SOCK_STREAM o SOCK_DGRAM The third argument is set to 0 to indicate default. o Default for Internet is UDP for connectionless sockets TCP for connection-oriented sockets The fourth argument is the base address of an integer array that will reference the two socket descriptors that will be created
Each descriptor is bi-directional and is available both for reading and writing. The following program creates a socket pair, forks a child, and uses sockets to communicate the parent and the child: Note that the socket library must be passed to the compiler via -lsocket. /* * Program 10.1 Creating a socket pair #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #define BUF_SZ 10 main(void) { int sock[2], /* The socket pair cpid, i; static char buf[buf_sz]; /* Temporary buffer for message if (socketpair(pf_unix, SOCK_STREAM, 0, sock) < 0) { perror("generation error"); exit(1); switch (cpid = (int) fork()) { case -1: perror("bad fork"); exit(2); case 0: /* The child process close(sock[1]); for (i = 0; i < 10; i += 2) { sleep(1); sprintf(buf, "c: %d\n", i); write(sock[0], buf, sizeof(buf)); read(sock[0], buf, BUF_SZ); printf("c-> %s", buf); /* Message from parent close(sock[0]); break; default: /* The parent process close(sock[0]); for (i = 1; i < 10; i += 2) { sleep(1); read(sock[1], buf, BUF_SZ); printf("p-> %s", buf); /* Message from child sprintf(buf, "p: %d\n", i); write(sock[1], buf, sizeof(buf));
close(sock[1]); return 0; Before the process forks, both sock[0] and sock[1] descriptors are available in parent for reading and writing. After the fork, the child process closes sock[1] and reads and writes with sock[0]. The parent process closes sock[0] and reads and writes with sock[1]. At the kernel level the sockets are still one and the same. Thus, what the child process writes to sock[0] can be read by the parent process from sock[1].
4 Sockets The Connection-Oriented Paradigm Used in a client-server communication model. Server connection-oriented communication sequence o Create a socket, socket( ) o Assign a name to a socket, bind( ) o Establish a queue for connections, listen( ) o Extract a connection from the queue, accept( ) o Reply to the request Client connection-oriented communication sequence o Create a socket, socket( ) o Initiate a connection, connect( ) o Send request to the server
The socket network call is as follows: ); int socket( int family, int type, int protocol The first argument can be o PF_UNIX o PF_INET The second argument can be
o SOCK_STREAM o SOCK_DGRAM The third argument is set to 0 for default. If the process creating the socket is to act as a server, then the socket must be bound. The bind network call is used for this purpose: int bind( int socket, const struct sockaddr *name, int namelen); The first argument is the integer returned from the socket call. The second argument is a reference to struct sockaddr { u_short sa_family; char sa_data[14]; ; If the socket is for UNIX domain, we have the following: o For UNIX Domain sockets, a reference to a file must be bound to the socket. A UNIX socket domain address is defined as struct sockaddr_un { short sun_family; char sun_path[108]; ;
o In above The first member is AF_UNIX The second member is the path to the file name bind will create the file entry for the socket If the socket is for Internet domain, we have the following: o An Internet domain address field is defined as struct sockaddr_in { short sin_family; u_short struct sin_addr; char sin_zero[8]; sin_port; in_addr The first member is AF_INET The second member is 16 bit port number In the third member, sin_addr is reference to in_addr that holds the 32 bit internet address. The fourth member is currently unused We can now complete the definition of the second argument of the bind call:
The first member of sockaddr indicates the address family The second member is a reference to the actual address where either sockaddr_in or sockaddr_un is passed Finally, the third argument of bind is the size of the address structure Next network call issued is listen: int listen( int backlog ); int socket, The first argument is the socket descriptor The second argument denotes the maximum size of the queue Next is the accept call. This call will block if there are no pending connection requests int accept( *addr, int socket, struct sockaddr int *addrlen );
The first argument is a socket descriptor that has previously been bound to an address with bind network call and is currently listening for connection The second argument is a pointer to sockaddr. The third argument is the length of sockaddr. If successful, accept returns a new socket descripter and the old one continues accepting other client calls In a connection oriented setting, the client process initiates the connection with the server process with the connect network call. int connect( int socket, struct sockaddr *name, int namelength ); The first argument is the socket descriptor The second argument: o If connection-oriented, *name references the address of the socket with which it wants to communicate o If connectionless, *name will reference where (address) the datagrams are to be sent. o If protocol is UNIX, name references a path/file name AF_INET, name references an Internet address/port number pair
Once the connection between the client and server has been established, they can communicate using standard I/O calls such as read and write or one of special calls such as send and receive. When they are done, they issue a close. 4.1 A UNIX Domain Stream Socket Example The server creates a socket, binds it to an address, generates a wait queue, accepts a connection, reads from socket displays it on screen. Client creates a socket, connect to the server, generates ten messages and sends them to the server. The Unix addresses of client and server are known in advance. /* Server - UNIX domain, connection-oriented #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> /* as we are using UNIX protocol #define NAME "my_sock" main( void ) { int orig_sock, /* Original socket descriptor in server new_sock, /* New socket descriptor from connect clnt_len, /* Length of client address i; /* Loop counter static struct sockaddr_un clnt_adr, /* UNIX addresses of client and server serv_adr; static char buf[10]; /* Buffer for messages void clean_up( int, char *); /* Close socket and remove it routine
if ((orig_sock = socket(af_unix, SOCK_STREAM, 0)) < 0) {/* SOCKET perror("generate error"); exit(1); serv_adr.sun_family = AF_UNIX; /* Set tag appropriately strcpy(serv_adr.sun_path,name);/* Assign name (108 chars max) unlink(name); /* Remove old copy if present if (bind( orig_sock, (struct sockaddr *) &serv_adr, /* BIND sizeof(serv_adr.sun_family)+strlen(serv_adr.sun_path)) < 0) { perror("bind error"); clean_up(orig_sock, NAME); exit(2); listen(orig_sock, 1); /* LISTEN clnt_len = sizeof(clnt_adr); if ((new_sock = accept( orig_sock, (struct sockaddr *) &clnt_adr, &clnt_len)) < 0) { /* ACCEPT perror("accept error"); clean_up(orig_sock, NAME); exit(3); for (i = 1; i <= 10; i++) { /* Process sleep(1); read(new_sock, buf, sizeof(buf)); printf("s-> %s", buf); close(new_sock); clean_up(orig_sock, NAME); exit(0); void clean_up( int sd, char *the_file ){ close( sd ); unlink( the_file ); /* close it /* rm it /* Client - UNIX domain, connection-oriented #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h>
#include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #define NAME "my_sock" main( void ) { int orig_sock, /* Original socket descriptor in client i; /* Loop counter static struct sockaddr_un serv_adr; /* UNIX address of the server process static char buf[10]; /* Buffer for messages if ((orig_sock = socket(af_unix, SOCK_STREAM, 0)) < 0) { /* SOCKET perror("generate error"); exit(1); serv_adr.sun_family = AF_UNIX; /* Set tag appropriately strcpy(serv_adr.sun_path, NAME);/* Assign name if (connect( orig_sock, (struct sockaddr *) &serv_adr, /* CONNECT sizeof(serv_adr.sun_family)+strlen(serv_adr.sun_path)) < 0) { perror("connect error"); exit(1); for (i = 1; i <= 10; i++) { /* Send msgs sprintf(buf, "c: %d\n", i); write(orig_sock, buf, sizeof(buf)); close(orig_sock); exit(0);
4.2 An Internet Domain Stream Socket Example We need host information to set up communications in this case. The gethostbyname network call returns information about a host if we know its name. ); struct hostent *gethostbyname( const char *name The only parameter takes a single character string reference that contains the name of the host. The call will return a reference to a hostent structure: struct hostent { char *h_name; char **h_aliases;
int h_addrtype; int h_length; char **h_addr_list; #define h_addr h_addr_list[0] ; The following program uses gethostbyname to obtain information about a host. Note that lnsl must be added to the compilation line. /* Checking host entries #include <stdio.h> #include <sys/types.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> main( void ) { struct hostent *host; static char who[10]; printf("enter host name to look up: "); scanf("%10s", who); host = gethostbyname( who ); if ( host!= (struct hostent *) NULL ) { printf("here is what I found about %s :\n", who); printf("official name : %s\n", host->h_name); printf("aliases : "); while ( *host->h_aliases ) { printf("%s ", *host->h_aliases ); ++host->h_aliases; printf("\naddress type : %i\n", host->h_addrtype); printf("address length: %i\n", host->h_length); printf("address list : "); while ( *host->h_addr_list ) { struct in_addr in; memcpy( &in.s_addr, *host->h_addr_list, sizeof (in.s_addr)); printf("[%s] = %s ", *host->h_addr_list, inet_ntoa(in)); ++host->h_addr_list; printf("\n");
Note that the inet_ntoa network call translates the character encoded network address into standard dotted notation. In addition to the Internet address, the client must also know the port number of the particular service on a server. An application can issue getservbyname network call to obtain such information. struct servent *getservbyname( const char *name, char *proto ); The getservbyname is passed the name of the service and protocol. It returns a reference to a servent structure. struct servent { char *s_name; char **s_aliases; int s_port; char *s_proto; ; The following program uses getservbyname network call to return information about a selected service type for a given protocol. /* Checking service -- port entries for a host #include <stdio.h> #include <netdb.h> #include <netinet/in.h> main( void ) { struct servent *serv; static char protocol[10], service[10];
printf("enter service to look up : "); scanf("%9s", service); printf("enter protocol to look up: "); scanf("%9s", protocol); serv = getservbyname( service, protocol ); if ( serv!= (struct servent *)NULL ) { printf("here is what I found \n"); printf("official name : %s\n", serv->s_name); printf("aliases : "); while ( *serv->s_aliases ) { printf("%s ", *serv->s_aliases ); ++serv->s_aliases; printf("\nport number : %i\n", htons(serv->s_port)); printf("protocol Family: %s\n\n", serv->s_proto); else printf("service %s for protocol %s not found\n",service,protocol); Note that the port number is passed through a network function ntohs that maintains byte ordering during the conversion of 16 and 32 bit integer values: u_short ntohs(u_short netshort); The inverse of ntohs is htons. The letter s indicates that argument is short 16 bits. For long integers, similar calls are ntohl and htonl.
The following program uses Internet protocol with connection oriented sockets. The server receives messages from clients, change the case of the message and return it to the client. Communication terminates when client sends a. in column one. For each connection, server forks a child that will carry on the communication. #include <stdio.h> #include <string.h> #include <ctype.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/ioctl.h> #include <sys/sockio.h> #define PORT 6969 static char buf[bufsiz]; /* Buffer for messages Note that the port number 6969 is chosen arbitrarily, grater than 1024 and currently not in use.
The server below passes the defined constant INADDR_ANY, found in the header file <netinet/in.h> to htonl. This constant, which is mapped to the value 0, indicates to the server that any address of socket type (SOCK_STREAM) will be acceptable. /* * Internet domain, connection-oriented SERVER #include "local.h" main( void ) { int orig_sock, /* Original socket descriptor in server new_sock, /* New socket descriptor from connect clnt_len; /* Length of client address static struct sockaddr_in clnt_adr, /* Internet address of client & server serv_adr; static char buf[bufsiz]; /* Buffer for messages int len, i; /* Misc counters, etc. if ((orig_sock = socket(af_inet, SOCK_STREAM, 0)) < 0) {/* SOCKET perror("generate error"); exit(1); memset( &serv_adr, 0, sizeof(serv_adr) ); /* Clear it out serv_adr.sin_family = AF_INET; /* Set address type serv_adr.sin_addr.s_addr = htonl(inaddr_any); /* Any interface serv_adr.sin_port = htons(port); /* Use our fake port /* BIND if (bind( orig_sock, (struct sockaddr *) &serv_adr, sizeof(serv_adr)) < 0){ perror("bind error"); close(orig_sock); exit(2); if (listen(orig_sock, 5) < 0 ) { /* LISTEN perror("listen error"); exit(3); do { clnt_len = sizeof(clnt_adr); if ((new_sock = accept( orig_sock, (struct sockaddr *) &clnt_adr, &clnt_len)) < 0) { /* ACCEPT perror("accept error"); close(orig_sock); exit(4); if ( fork( ) == 0 ) { /* In CHILD process while ( (len=read(new_sock, buf, BUFSIZ)) > 0 ){
for (i=0; i < len; ++i) /* Change the case buf[i] = toupper(buf[i]); write(new_sock, buf, len); /* write it back if ( buf[0] == '.' ) break; /* are we done yet? close(new_sock); /* In CHILD process exit( 0 ); else close(new_sock); /* In PARENT process while( 1 ); /* FOREVER /* * Internet domain, connection-oriented CLIENT #include "local.h" main( int argc, char *argv[] ) { int orig_sock, len; static struct sockaddr_in serv_adr; struct hostent *host; if ( argc!= 2 ) { fprintf(stderr, "usage: %s server\n", argv[0]); exit(1); host = gethostbyname(argv[1]); /* GET INFO if (host == (struct hostent *) NULL ) { perror("gethostbyname "); exit(2); memset(&serv_adr, 0, sizeof( serv_adr)); /* Clear it out serv_adr.sin_family = AF_INET; memcpy(&serv_adr.sin_addr, host->h_addr, host->h_length); serv_adr.sin_port = htons( PORT ); if ((orig_sock = socket(af_inet, SOCK_STREAM, 0)) < 0) { /* SOCKET perror("generate error"); exit(3); /* CONNECT if (connect(orig_sock, (struct sockaddr *)&serv_adr, sizeof(serv_adr)) < 0) { perror("connect error"); exit(4); do { write(fileno(stdout),"> ", 3); /* Prompt the user if ((len=read(fileno(stdin), buf, BUFSIZ)) > 0) { /* Get user input
write(orig_sock, buf, len); /* Write to socket if ((len=read(orig_sock, buf, len)) > 0 ) /* If returned write(fileno(stdout), buf, len); /* display it. while( buf[0]!= '.' ); close(orig_sock); exit(0); The client program expects the name of the server to be passed in the command line. It then expects a message to be entered on the command line, sends this message to the server. The server changes the case and sends it back to the client. The client displays the received message.
5 Sockets The Connectionless Paradigm The server executes the following sequence of calls: socket( ) bind( ) recvfrom( ) sendto( ) The client executes the following sequence of calls: socket( ) bind( ) sendto( ) recvfrom( )
Note that the client also needs to bind socket in this case. Moreover, listen and accept are not used by the server and connect is not used by the client. The sendto network call has several alternatives: int send( char *msg, ); int socket, const int len, int flags int sendto( int socket, constchar *msg, int len, int flags,
sockaddr *to, const struct int tolen ); int sendmsg( int socket, const struct msghdr *msg, int flags ); The send network call can only be used with connected sockets. The other two can be used with both kind of sockets. The first two send sequence of bytes. The last one can do scatter-gather i/o with the struct and struct msghdr { caddr_t msg_name; int msg_namelen; struct iovec *msg_iov; int msg_iovlen; caddr_t msg_accrights; int msg_accrightslen; ; typedef struct iovec { caddr_t iov_base; int iov_len; iovec_t;
If sendto is used with connected sockets, the last two arguments are ignored. Note that there are linker specifications as lnsl and - lsocket. All of the above calls return the number of bytes sent. The following calls are alternatives for receiving. All of them return the number of bytes received and block if nothing to read. int recv( *buffer, ); int recvfrom( *buffer, flags, sockaddr *from, int socket, char int len, int flags int socket, char int len, int const struct int *fromlen ); int recvmsg( int socket, const struct msghdr *msg, int flags ); The usage of the above calls are the same as that of send calls respectively.
5.1 A Unix Domain Datagram Socket Example The client generates 10 messages and sends them to the server. The server displays the messages. They use sendto and recvfrom network calls for communication. /* SERVER - UNIX domain - connectionless #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> /* as we are using UNIX protocol #define SERVER_FILE "server_socket" main( void ) { int orig_sock, /* Original socket descriptor in server clnt_len, /* Length of client address i; /* Loop counter static struct sockaddr_un clnt_adr, /* UNIX addresses of client and server serv_adr; static char buf[10]; /* Buffer for messages void clean_up( int, char *); /* Close socket and remove it routine if ((orig_sock = socket(af_unix, SOCK_DGRAM, 0)) < 0) {/* SOCKET perror("generate error"); exit(1); serv_adr.sun_family = AF_UNIX; /* Set tag appropriately strcpy(serv_adr.sun_path,server_file);/* Assign name unlink( SERVER_FILE); /* Remove leftovers if (bind( orig_sock, (struct sockaddr *) &serv_adr, /* BIND sizeof(serv_adr.sun_family)+strlen(serv_adr.sun_path)) < 0) { perror("bind error"); clean_up(orig_sock, SERVER_FILE); exit(2); for (i = 1; i <= 10; i++) { recvfrom(orig_sock, buf, sizeof(buf), 0, /* RECEIVE it (struct sockaddr *) &clnt_adr, &clnt_len); printf("s-> %s", buf); clean_up(orig_sock, SERVER_FILE); exit(0);
void clean_up( int sd, char *the_file ){ close( sd ); unlink( the_file ); /* CLIENT - UNIX domain - connectionless #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #include <unistd.h> #define SERVER_FILE "server_socket" main( void ) { int orig_sock, i; static struct sockaddr_un clnt_adr, serv_adr; static char buf[10], client_file[15]; void clean_up( int, char * ); serv_adr.sun_family = AF_UNIX; strcpy(serv_adr.sun_path, SERVER_FILE); if ((orig_sock = socket(af_unix, SOCK_DGRAM, 0)) < 0) { perror("generate error"); exit(1); sprintf(client_file,"%07d_socket",getpid()); clnt_adr.sun_family = AF_UNIX; strcpy(clnt_adr.sun_path, client_file); if (bind( orig_sock, (struct sockaddr *) &clnt_adr, /* BIND sizeof(clnt_adr.sun_family)+strlen(clnt_adr.sun_path)) < 0) { perror("bind error"); exit(2); for (i=1; i <= 10; i++) { sleep(1); /* slow down the client sprintf(buf, "c: %d\n", i); /* create message sendto(orig_sock, buf, sizeof(buf), 0, /* SEND it (struct sockaddr *) &serv_adr, sizeof(struct sockaddr)); clean_up( orig_sock, client_file); exit(0);
void clean_up( int sd, char *the_file ){ close( sd ); unlink( the_file );
5.2 An Internet Domain Datagram Socket Example Both the client and server run on separate windows. Server is run first and it displays the port number. In the command line, the client is passed the name of the host. The user enters a message to client. The client sends this message to the server which displays this message. Then a response to this message is entered to the server which in turn sends this to the client and the client displays the message. The client terminates with a ^D, server is removed with a kill command. #include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> #include <netinet/in.h> #include <arpa/inet.h> static char buf[bufsiz]; /* Buffer for messages /* * Program 10.10 - SERVER - Internet Domain - connectionless #include "local.h" main( void ) { int sock, n, server_len, client_len; struct sockaddr_in server, /* Address structures client; /* create the SOCKET if ((sock = socket(af_inet, SOCK_DGRAM, 0)) < 0) { perror("server socket "); exit(1); /* set svr adr info server.sin_family = AF_INET; /* Address family
server.sin_addr.s_addr = htonl(inaddr_any); /* use any address server.sin_port = htons(0); /* pick a free port /* BIND the socket if (bind(sock, (struct sockaddr *) &server, sizeof(server) ) < 0) { perror("server bind "); exit(2); /* obtain chosen adr if (getsockname(sock, (struct sockaddr *) &server, &server_len) < 0) { perror("server getsocketname "); exit(3); /* display port # printf("server using port %d\n", ntohs(server.sin_port)); while ( 1 ) { client_len = sizeof(client); /* estimate length memset(buf, 0, BUFSIZ); /* clear the buffer if ((n=recvfrom(sock, buf, BUFSIZ, 0, /* the clnt message (struct sockaddr *) &client, &client_len)) < 0){ perror("server recvfrom "); close(sock); exit(4); write(fileno(stdout), buf, n); /* show msg to server memset(buf, 0, BUFSIZ); /* clear the buffer if (fgets(buf, BUFSIZ, stdin)!= NULL ){ /* get server's msg if ((sendto(sock, buf, strlen(buf),0, /* send it to client (struct sockaddr *) &client, client_len)) <0){ perror("server sendto "); close(sock); exit(5); /* Program 10.11 - CLIENT - Internet Domain - connectionless #include "local.h" main(int argc, char *argv[]){ int sock, n, server_len; static struct sockaddr_in /* Address structures server, client; struct hostent *host; /* For host info
if ( argc < 3 ) { /* need server & port fprintf(stderr, "usage: %s server port_#\n", argv[0]); exit(1); if (!(host=gethostbyname(argv[1]))){ /* get server info perror("client gethostname "); exit(2); /* set svr adr info server.sin_family = AF_INET; /* address family memcpy(&server.sin_addr, host->h_addr, host->h_length); /* act adr server.sin_port = htons(atoi(argv[2])); /* @ passed in port # /* create a SOCKET if ((sock=socket(af_inet, SOCK_DGRAM, 0)) < 0 ) { perror("client socket "); exit(3); /* set clnt adr info client.sin_family = AF_INET; /* address family client.sin_addr.s_addr = htonl(inaddr_any); /* use any address client.sin_port = htons( 0 ); /* pick a free port /* BIND the socket if (bind(sock, (struct sockaddr *) &client, sizeof(client)) < 0) { perror("client bind "); exit(4); while( fgets(buf, BUFSIZ, stdin)!= NULL ){ /* get clnt's msg server_len=sizeof(server); /* guess at length if (sendto( sock, buf, strlen(buf), 0, /* send msg to server (struct sockaddr *) &server, server_len) < 0 ){ perror("client sendto "); close(sock); exit(5); memset(buf,0,bufsiz); /* clear the buffer if ((n=recvfrom(sock, buf, BUFSIZ, 0, /* server's message (struct sockaddr *) &server, &server_len)) < 0){ perror("client recvfrom "); close(sock); exit(6); write(fileno(stdout),buf,n); /* show msg to clnt memset(buf,0,bufsiz); /* clear the buffer close(sock); exit(0);
The define constant INADDR_ANY is a wild card address that indicates to the server that it can use any valid address. The getsockname system call is used to determine which port the system has selected since the port number is passed value 0 to let the system pick an port that is not in use. fgets system call is used to obtain user input.