Topic : BSD Sockets
Author : Unknown
Page : << Previous 4  Next >>
Go to page :


sample programs below.





Putting a Host Program Address Together
Once a host address and port number are known then the complete process address must be put together in a form that may be used by the system calls already covered. The structures set up to allow this follow:

#include <netinet/in.h>

/*
* Internet address (a structure for historical reasons)
*/
struct in_addr {
    union {
         struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
         struct { u_short s_w1,s_w2; } S_un_w;
         u_long S_addr;
    } S_un;
#define s_addr  S_un.S_addr
        /* can be used for most tcp & ip code */
};


/*
* Socket address, internet style.
*/
struct sockaddr_in {
      short   sin_family;
      u_short sin_port;
      struct  in_addr sin_addr;
      char    sin_zero[8];
};


Filling in the fields for sockaddr_in will produce an Internet version of a socket address.





Finding a Machine Address
Finding an address that can be used to connect to a remote machine is done with either of the following commands:

#include <netdb.h>

struct hostent *gethostbyname(char *name)

struct hostent *gethostbyaddr(char *addr, int len, int type)


name contains the host name for which the IP address is needed. addr points to a structure of type in_addr and len is the size in bytes of this structure. In this discussion type is always AF_INET since the discussion is limited to use of IP addresses on the Internet.
Both calls return a pointer to a host entry structure. This structure has the following form:


   struct hostent {
      char   *h_name;  /* official name of host */
      char   **h_aliases;  /* alias list */
      int    h_addrtype;   /* address type */
      int    h_length;     /* length of address */
      char   **h_addr_list;
         /* list of addresses from name server */
   #define  h_addr h_addr_list[0]
         /* address for backward compatibility */
   };






Network Byte Order for Numbers
Not all machine architectures use the same internal representations for numbers. For instance, in host systems based on Intel microprocessors and the DEC VAX architecture bytes are stored in increasing memory locations in reverse or "little-endian" order. All other systems store bytes in increasing memory locations in "normal" or "big-endian" order.
Left as is, communications between, e.g., IBM-compatible PCs and Sun Microsystems workstations would be difficult at best. To overcome this all data sent over a network is converted to Network Byte Order which is, in the context of the above discussion, "big-endian" order.

Routines for converting data between a host's internal representation and Network Byte Order are:


#include <sys/types.h>
#include <netinet/in.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);


These functions are macros and result in the insertion of conversion source code into the calling program. On little-endian machines the code will change the values around to network byte order. On big-endian machines no code is inserted since none is needed; the functions are defined as null.





Network Address Conversion Routines
An Internet address is usually written and specified in the dotted-decimal notation described above. Internally it becomes part of a structure of type in_addr. To convert between these two representations two functions are available.

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>     /* in_addr structure */

unsigned long inet_addr(char *ptr)

char *inet_ntoa(struct in_addr inaddr)


inet_addr() converts a character string in dotted-decimal notation to a 32-bit Internet address. The return value is not consistent, unfortunately. The correct return should be a pointer to a structure of type in_addr but many systems, following an older convention, return only the internal representation of the dotted-decimal notation. The man pages will clarify the situation for the host system on which the function is used.
inet_ntoa() expects a structure of type in_addr as a parameter (note that the structure itself is passed, not a pointer) and returns a pointer to a character string containing the dotted-decimal representation of the Internet address.






Internet Connection-Oriented Client-Server Example
The next two sections contain sample programs for server and client when connection-oriented communication across the Internet (using TCP) is requested. The server and client programs are named vcserver and vcclient, respectively. As built, the programs have some restrictions:

vcserver should be started first as a background job.
The port number reported by vcserver should be copied for use by the client.
The process id of vcserver should also be copied, for use in terminating vcserver when the test is finished.
vcclient is then started.
If vcclient is started on the same host as vcserver is running, the command line to start vcclient is

   vcclient localhost server-port-number
   
If vcclient is started on a host different from the host on which vcserver is running, the command line to start vcclient is

   vcclient server-host-name server-port-number

vcserver will remain resident until the user terminates it. The cleanest way to do this is

   kill -15 pid
   
where pid is the process id of vcserver.





Server Source Listing - vcserver.c
/*  vcserver.c -- TCP network (virtual circuit) server  */

#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>    /* sockaddr_in structure */

/* This entry allows the program to look up the name
   of the host and any alias names associated with it. */

#include <netdb.h>          /* /etc/hosts table entries */

main (int argc, char *argv[])

{
   int rc,            /* system call return code */
       new_sd, sock,  /* server/listen socket descriptors */
       adrlen,        /* sockaddr length */
       cnt;           /* number of bytes I/O */

   struct sockaddr_in myname;  /* Internet socket name */
   struct sockaddr_in *nptr;   /* ptr to get port number */
   struct sockaddr    addr;    /* generic socket name */

   char buf[80];   /* I/O buffer, kind of small  */

   /* For lookup in /etc/hosts file.   */

   struct hostent *hp, *gethostbyaddr();

   /* Identify the server process. */

   printf("\nThis is the network server with pid %d\n",
        getpid() );

   /* As in UNIX domain sockets, create a "listen" socket */

   if (( sock = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
      printf("network server socket failure %d\n", errno);
      perror("network server");
      exit(1);
   /* Initialize the fields in the Internet socket name
      structure.                                          */

   myname.sin_family = AF_INET;  /* Internet address */
   myname.sin_port = 0;  /* System will assign port #  */
   myname.sin_addr.s_addr = INADDR_ANY;  /* "Wildcard" */

   /* Bind the Internet address to the Internet socket */

   if (bind(sock, &myname, sizeof(myname) ) < 0 ) {
      close(sock);  /* defensive programming  */
      printf("network server bind failure %d\n", errno);
      perror("network server");
      exit(2);
   }

   /*   Get the port number assigned to the Internet socket.
         getsockname() obtains the port number associated
         with the bound socket and returns it as part of the
         information in the sockaddr addr structure.  Note
         that, since the port number is not passed directly
         by this program to any client, the only way to
         "advertise" it is to print it, that is, send it to
         the user's stdout.  Other than this printout, this
         code is not intrinsic to the connectivity process.
   */

   adrlen = sizeof(addr); /* need int for return value */
   if ( ( rc = getsockname( sock, &addr, &adrlen ) ) < 0 )
   {
      printf("setwork server getsockname failure %d\n",
            errno);
      perror("network server");
      close (sock);
      exit(3);
   }

   /*   DEBUG CODE: the generic address "addr" is used to
         return the socket value obtained from the
         getsockname() call.  Print this information.  In the
         generic structure definition, all but the address
         family is defined as a char string.  After this
         call, the generic address structure addr is used to
         hold information about the client process. */

   printf("\nAfter getsockname():");
   printf(" server listen socket data\n");
   printf("\taddr.sa_family field value is: %d\n",
        addr.sa_family);
  


Page : << Previous 4  Next >>