Developing applications over TCP/IP using Internet sockets

Code samples (Internet domain)

Examples of client and server socket programs make up the rest of this section. These programs illustrate how to use the sockets interface to establish a connection and transmit data between hosts using TCP.

Server (Internet domain)

The following code creates a server that waits for client connection requests. The manual page for each routine defines the necessary #include files when calling that routine.

Sample server (part 1 of 3)

  1 #include <sys/types.h>
  2 #include <sys/socket.h>
  3 #include <netinet/in.h>
  4 #include <stdio.h>
  5 #include <netdb.h>

line 1
System pseudo-types.

line 2
Definitions related to sockets: types, address families, options; and structures used by the kernel to store most addresses.

line 3
Constants and structures defined by the Internet system, and definitions of bits in Internet address integers.

line 4
Standard I/O definitions.

line 5
Structures returned by network database library. These include, for example, hostent and netent, which are returned by gethostbyname and getnetbyname respectively. See the SCO TCP/IP Programmer's Reference for a full listing of the sockets library functions.

Sample server (part 2 of 3)

  6 #define PORTNUM 601

7 main(argc, argv) 8 int argc; 9 char *argv[];

10 { 11 int s, ns, pid; 12 struct sockaddr_in sin; 13 char buf[80]; 14 if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) { 15 perror("tomd: socket"); 16 exit(1); 17 }

18 bzero(&sin, sizeof(sin));

19 sin.sin_family = AF_INET; 20 sin.sin_port = htons(PORTNUM); 21 sin.sin_addr.s_addr = htonl(INADDR_ANY);

22 if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) == -1) { 23 perror("tomd: bind"); 24 exit(1); 25 } 26 if (listen(s, 5) == -1) { 27 perror("tomd: listen"); 28 exit(1); 29 } 30 while(1) 31 { 32 if ((ns = accept(s, 0, 0)) == -1) { 33 perror("tomd: accept"); 34 exit(1); 35 }

36 if ((pid = fork()) == -1) { 37 perror("tomd: fork"); 38 exit(1); 39 }

line 6
This is the port number the server will use. See /etc/services for a listing of port numbers of common network services.

line 11
Declare integers: s is the socket descriptor. ns is the socket descriptor for the connection to the client. pid is the process ID for the fork.

line 12
The sockaddr structure for sin is declared. This allocates space for the Internet address and port number.

line 13
This is a buffer for data received from the client.

lines 14-16
Line 14 creates a socket, and establishes an endpoint for communication. It is a stream socket in the Internet address family using TCP. A socket created with the socket system call is identified only by its address family. As yet it has no name. Other processes cannot reference it and no communication can take place.

line 18
This line clears the address space, that is, initializes sin to all zeros. See bstring(S).

line 19
This line assigns the Internet address family, AF_INET.

line 20
This line moves the port number, defined in line 6, into the sin structure. If this server were advertising a well-known service like telnet, the port number could be obtained with a call to getservent(SLIB) (see lines 6 and 26 in the later client example for a similar functionality).

line 21
This line assigns the Internet host address. In this case, the server will receive data addressed to any of its configured network interfaces.

lines 22-24
Communication processes are bound by an association. An association consists of a local address and port number, and a foreign address and port number. bind allows a process to specify the local half of an association. Here the port number is associated with the socket channel number.

lines 26-28
The server waits for a client to attempt to connect. The listen call identifies a socket as a server and marks it as accepting connections. The maximum queue length listen can specify is five. This means it allows a backlog of five clients attempting to connect before turning them back.

lines 32-34
accept automatically creates a new socket descriptor with the same properties as s. The second and third arguments to accept can be used to return the address and address length of the connected client process. Setting them to zero causes the server to not retain the address information of the client, (see accept(SSC)).

line 36-39
The call to fork(S) creates a child process that is an exact copy of the calling process.

Sample server (part 3 of 3)

 41 	if (pid == 0) {
 42 	    while(1) {

43 if ((pid = read(ns, buf, sizeof(buf))) == -1) { 44 perror("tomd: read"); 45 exit(1); 46 } 47 if (pid < sizeof(buf)) break; 48 printf("Data from client: %s", buf); 49 } 50 printf("\nThe daemon child is dead\n"); 51 close(ns); 52 exit(0); 53 } 54 close(ns); 55 } 56 }

lines 40-41
The socket is passed on to the child so that the parent can continue to listen for connection requests from other clients.

line 42-47
The server reads the data sent by client. If the data received is less than the buffer size (see line 13 above), the loop breaks and the child dies.

line 50-51
The child closes and exits the connection to the client. If one end of a socket is closed and the other tries to write to it, the write will return an error. shutdown(SSC) causes all or part of a full-duplex connection to be terminated. See the discussion on close and shutdown in ``Data transfer (Internet domain)''.

line 53
This line closes the parent's file descriptor returned from accept.

Client (Internet domain)

The following code creates a client that requests a connection from a listening server. The manual page for each routine defines the necessary #include files when calling that routine.

Sample client (part 1 of 2)

  1 #include <sys/types.h>
  2 #include <sys/socket.h>
  3 #include <netinet/in.h>
  4 #include <stdio.h>
  5 #include <netdb.h>

6 #define PORTNUM 601

7 main(argc, argv) 8 int argc; 9 char *argv[];

10 { 11 int s; 12 struct sockaddr_in sin; 13 struct hostent *hp; 14 char buf[80];

15 if (argc != 2) { 16 printf("Illegal number of arguments"); 17 exit(1); 18 }

19 if ((hp = gethostbyname(argv[1])) == 0) { 20 perror("tom: gethostbyname"); 21 exit(1); 22 }

23 bzero(&sin, sizeof(sin)); 24 bcopy(hp->h_addr, &sin.sin_addr, hp->h_length); 25 sin.sin_family = hp->h_addrtype;

lines 10-14
Declarations are made here just as they are for the server, except that line 13 declares hp to be a pointer to a hostent structure.

lines 19-22
A hostent structure containing the IP number of the requested host is returned. See ``Mapping host names (Internet domain)'' for details on how the host IP number is obtained.

lines 23-25
The sin structure is cleared, the address of the server is copied into it, and the family type (pointed to in line 12), is copied from the hostent structure.

Sample client (part 2 of 2)

 26     sin.sin_port = htons(PORTNUM);
 28     if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
 29 	perror("tom: socket");
 30 	exit(1);
 31     }

32 if (connect(s, (struct sockaddr *) &sin, sizeof(sin), 0) == -1) { 33 perror("tom: connect"); 34 exit(1); 35 }

36 sprintf(buf, "Hello world");

37 if (write(s, buf, sizeof(buf)) == -1) { 38 perror("tom: write"); 39 exit(1); 40 }

41 close(s); 42 }

line 26
The port number of the server is copied into sin.

lines 28-31
A socket is created exactly as it was done for the server.

lines 32-35
A connection request is accepted by the server and a fully connected socket pair is established. s refers to the client socket. &sin and sizeof(sin) are pointers to the address family and size of the other socket, that is, the server.

lines 36-40
The client sends a message to the server, then terminates its connection with the server. s refers to the client socket, while buf refers to the message length specified in line 14.

line 41
The client closes the socket descriptor obtained with the socket call in line 28.

Next topic: Datagrams in the Internet Domain
Previous topic: Byte order

© 2003 Caldera International, Inc. All rights reserved.
SCO OpenServer Release 5.0.7 -- 11 February 2003