The Socket API
        struct sockaddr { /* struct to hold an address */
            u_short sa_family;  /* AF_xxx family */
            char sa_data[14];  /* upto 14 bytes of protocol specific address */
        };
          struct in_addr {
            u_long s_addr; /* 32 bit address */
        };

       struct sockaddr_in {
            short sin_family; /* AF_INET family */
            u_short sin_port; /* 16 bit port number */
            struct in_addr sin_addr;  /* 32 bit host address */
            char sin_zero[8]; /* unused */
        };
 

Major System Calls used with sockets

1)    socket()

This function call creates a new socket to be used for network communication. The call returns a socket descriptor (sockfd).

#include <sys/types.h>
#include <sys/socket.h>

int socket( int family, int type, int protocol);

2) bind()

An application calls bind() to specify the local endpoint address for a socket.

#include <sys/types.h>
#include <sys/socket.h>

int bind( int sockfd, struct sockaddr *myaddr, int addrlen);

The endpoint address specifies both an IP address and a port number. Primarily, servers use bind() to specify a well-known port at which they will await connections.

3) connect()
 
A connection-oriented client process calls connect() to establish a connection to a server.

#include <sys/types.h>
#include <sys/socket.h>

int connect( int sockfd, struct sockaddr *servaddr, int addrlen);

The sockaddr structure specifies the remote endpoint address and the addrlen argument specifies the size of the address structure.

4) listen()

Used by connection-oriented servers to indicate willingness to receive connections. This call places the socket of the server in a passive mode and makes it ready to accept incoming connections.

#include <sys/types.h>
#include <sys/socket.h>

int listen( int sockfd, int backlog);

This call is executed after socket() and bind(), but before the accept() call. The backlog argument specifies the maximum number of connection requests that can be queued by the system while it waits for the server to execute the accept() call.

5) accept()

After a connection-oriented server calls socket(), bind(), and listen(), it calls accept() to extract the next incoming request.

#include <sys/types.h>
#include <sys/socket.h>

int accept(int sockfd, struct sockaddr *peer, int *addrlen);

accept() creates a new socket with the same properties as sockfd for each new connection request and returns the socket descriptor. The peer argument returns the address of the connected peer (i.e. client). The addrlen argument (on return of the call) contains size of the client address.

6) close()

#include <sys/types.h>
#include <sys/socket.h>

int close(int sockfd);

This call deallocates a socket.

7) read() and write()

The server uses read() to receive a request (after a connection is established) that the client sebds by calling write(). After sending its request, the client uses read() to receive a reply.

n = read( int sockfd, char *buff, int nbyes);

The buff argument specifies the address of the buffer to write the data which was read in. The nbytes argument specifies the size of user buffer.

n = write( int sockfd, char *buff, int nbytes);

The buff argument specifies the address of the buffer from where data is to be sent. The nbytes argument specifies the size of the data to be sent.

8) htonl(), htons(), ntohl(), and ntohs()

These four routines are utility routines that convert binary integers between the hosts' native byte order and the network standard byte order.

#include <sys/types.h>
#include <sys/socket.h>

u_long htonl(u_long hostlong);
u_short htons(u_short hostshort);
u_long ntohl(u_long netlong);
u_short ntohs(u_short netshort);
 

Connection-oriented Server Algorithm

int sockfd, newsockfd();

if ((sockfd = socket(...)) < 0)
        printf("socket error \n");
if (bind(sockfd, ...) < 0)
        printf("bind error \n");
if (listen(sockfd, 5) < 0)
        printf("listen error \n");

Concurrent Server

for( ; ; ) {
             newsockfd = accept(sockfd, ....); /* blocks */
            if (newsockfd < 0)
                    printf("accept error \n");
 
            if ((childpid = fork()) < 0)
                    printf("server: fork error \n");
            else if (childpid == 0) {   /* child  */
                            close(sockfd);
                            doit(newsockfd);
                            exit(0);
            }
            close(newsockfd);  /* parent */
  }

Iterative Server

for( ; ; ) {
             newsockfd = accept(sockfd, ....); /* blocks */
            if (newsockfd < 0)
                    printf("accept error \n");

            doit(newsockfd);
            close(newsockfd);
}