Previous | Contents | Index |
You can use either the OpenVMS system services or the C Socket interface to write TCP/IP applications that run on your corporate internet. These applications consist of a series of system calls that perform tasks, such as creating a socket. These system calls are direct entry points that the client and server processes use to obtain services from the kernel software. System calls look and behave exactly like other procedural calls, taking arguments and returning one or more results including a status value. These arguments can contain values or pointers to objects in the application program.
This chapter describes the process followed by communicating client and server machines. This process reflects the sequence of system calls within the client and server programs (see Tables 2-1 and 2-4). The chapter also includes C Socket and OpenVMS system services example routines for each step in the communication process.
The OpenVMS and C Socket programming examples are located in the TCPIP$EXAMPLES library. |
The most commonly used paradigm in constructing distributed applications is the client/server model. The requester, known as the client, sends a request to a server and waits for a response. The server is an application-level program that offers a service that can be reached over the network. Servers accept requests that arrive over the network, perform their service, and return the result to the client.
In addition to having a client and a server, the connection also has a mode of communication. This variable can be either connection-oriented or connectionless. When writing internet applications, the developer uses the mode of communication required by the application-level service. Therefore, if the application-level service uses the connection-oriented mode of communication, the developer uses the virtual circuit or the Transmission Control Protocol (TCP) approach. If the application-level service uses the connectionless mode of communication, then the developer uses the datagram or the User Datagram Protocol (UDP) approach.
Figure 2-1 shows the communication process for a TCP client/server internet application.
Figure 2-1 TCP Socket Communication Process
In this figure:
Table 2-1 identifies the basic calling sequence, the C socket routine, and the equivalent system service routine for server applications that use TCP.
Task | C Socket Routine | OpenVMS System Service Routine |
---|---|---|
Create a device socket | socket() |
$ASSIGN
$QIO(IO$_SETMODE) 1 |
Bind socket name | bind() | $QIO(IO$_SETMODE) 1 |
Define listener device socket | listen() | $QIO(IO$_SETMODE) 1 |
Accept connection request | accept() | $QIO(IO$_ACCESS) |
Exchange data |
read()
recv() recvmsg() |
$QIO(IO$_READVBLK) |
write()
send() sendmsg() |
$QIO(IO$_WRITEVBLK) | |
Shut down the socket (optional) | shutdown() | $QIO(IO$_DEACCESS|IO$M_SHUTDOWN) |
Close and delete the socket | close() |
$QIO(IO$_DEACCESS)
$DASSGN |
Table 2-2 describes the basic calling sequence for client applications that use TCP.
Task | C Socket Routine | OpenVMS System Service Routine |
---|---|---|
Create a device socket | socket() |
$ASSIGN
$QIO(IO$_SETMODE) 1 |
Bind socket name | bind() | $QIO(IO$_SETMODE) 1 |
Connect to server | connect() | $QIO(IO$_ACCESS) |
Exchange data |
read()
recv() recvmsg() |
$QIO(IO$_READVBLK) |
write()
send() sendmsg() |
$QIO(IO$_WRITEVBLK) | |
Shut down the socket (optional) | shutdown() | $QIO(IO$_DEACCESS|IO$M_SHUTDOWN) |
Close and delete the socket | close() |
$QIO(IO$_DEACCESS)
$DASSGN |
Figure 2-2 shows the communication process for a UDP client/server internet application.
Figure 2-2 UDP Socket Communication Process
In this figure:
Table 2-3 identifies the basic calling sequence, the system service routine, and the equivalent C Socket routine for server applications that use UDP.
Task | C Socket Routine | OpenVMS System Service Routine |
---|---|---|
Create a device socket | socket() |
$ASSIGN
$QIO(IO$_SETMODE) 1 |
Bind socket name | bind() | $QIO(IO$_SETMODE) 1 |
Specify port for incoming datagrams | recvfrom() | $QIO(IO$_ACCESS) |
Exchange data |
read()
recv() recvfrom() recvmsg() |
$QIO(IO$_READVBLK) |
write()
send() sendto() sendmsg() |
$QIO(IO$_WRITEVBLK) | |
Shut down the socket (optional) | shutdown() | $QIO(IO$_DEACCESS|IO$M_SHUTDOWN) |
Close and delete the socket | close() |
$QIO(IO$_DEACCESS)
$DASSGN |
Table 2-4 describes the basic calling sequence for client applications that use the UDP protocol.
Task | C Socket Routine | OpenVMS System Service Routine |
---|---|---|
Create a device socket | socket() |
$ASSIGN
$QIO(IO$_SETMODE) 1 |
Bind socket name | bind() | $QIO(IO$_SETMODE) 1 |
Exchange data |
read()
recv() recvfrom() recvmsg() |
$QIO(IO$_READVBLK) |
write()
send() sendto() sendmsg() |
$QIO(IO$_WRITEVBLK) | |
Shut down the socket (optional) | shutdown() | $QIO(IO$_DEACCESS|IO$M_SHUTDOWN) |
Close and delete the socket | close() |
$QIO(IO$_DEACCESS)
$DASSGN |
For communication to take place between two processes, communication end points are required for each process. Therefore, an abstraction called a socket was created to serve as an end point that sends and receives messages. Sockets are created with an address family similar to the way that file folders are created within a file system, where each major topic includes folders of information relating to that topic. When an application program requests that a socket be created, a small integer (known as a descriptor) is returned. The application program uses the descriptor to reference the newly created socket.
To create a device socket, complete the following steps:
The functions of the internet protocols are performed as I/O functions of the internet pseudodevice. When using the DIGITAL TCP/IP Services for OpenVMS software, TCPIP$DEVICE: is the logical name for internet pseudodevices.
When a channel is assigned to the TCPIP$DEVICE template internet
pseudodevice, the internet software creates a new pseudodevice with a
unique unit number. The returned channel number is used in subsequent
operation requests with that device.
2.2.1 Creating Device Sockets with OpenVMS System Services
When you use OpenVMS system services, you make two calls to create the device socket:
When you make the $QIO or $QIOW call, use either the IO$_SETMODE or the IO$_SETCHAR I/O function. You generally create, bind, and set up sockets to listen with one $QIO call. The IO$_SETMODE and IO$_SETCHAR functions perform in an identical manner, where internet software is concerned. However, you must have logical I/O permissions (LOG_IO privilege) to successfully use the IO$_SETMODE I/O function.
Example 2-1 shows a TCP/IP server using the $ASSIGN and $QIOW system services to create a device socket.
Example 2-1 Creating a Device Socket Using OpenVMS System Services |
---|
/* ** ** Assign a channel to the network device, "TCPIP$DEVICE:". ** */ sysSrvSts = sys$assign( &devDSC, /* devnam.d */ &IOChannel, /* chan.r */ 0, /* acmode.v | 0 */ 0, /* mbxnam.d | 0 */ 0 /* flags.v | 0 */ ); if(( sysSrvSts & 1 ) != 1 ) /* Validate the system service status. */ { sys$dassgn( IOChannel /* chan.v */ ); errorExit( sysSrvSts, 1 ); } /* ** ** Attempt to create device socket. ** Use the function code of IO$_SETMODE, passing the socket ** creation parameter to P1. ** */ socketParam.protocol = TCPIP$C_TCP; socketParam.type = INET_PROTYP$C_STREAM; socketParam.family = AF_INET; sysSrvSts = sys$qiow( 0, /* efn.v | 0 */ IOChannel, /* chan.v */ IO$_SETMODE, /* func.v */ &iosb, /* iosb.r | 0 */ 0, 0, /* astadr, astprm: UNUSED */ &socketParam, /* p1.r Socket creation parameter */ 0, 0, 0, 0, 0 /* p2, p3, p4, p5, p6 UNUSED */ ); if((( sysSrvSts & 1 ) != 1 ) || /* Validate the system service status. */ (( iosb.cond_value & 1 ) != 1)) /* Validate the I/O status. */ { cleanup( IOChannel ); errorExit( sysSrvSts, iosb.cond_value ); } |
2.2.2 Creating Device Sockets with the C Socket Interface
When using the C Socket interface, create the device socket with one
call to the socket() routine. Example 2-2 shows a TCP/IP
server using the socket() routine to create a device socket.
Example 2-2 Binding a Socket Using C Socket Programming |
---|
#include <types.h> #include <in.h> . . . #include <string.h> #define PORTNUM 1234 main() { int r, s, i; struct sockaddr_in lcladdr; lcladdr.sin_family = AF_INET; lcladdr.sin_addr.s_addr = INADDR_ANY; lcladdr.sin_port = htons(PORTNUM); s = socket(AF_INET,SOCK_STREAM,0);(1) . . . |
The Berkeley Internet Name Domain (BIND) service is a host name and address lookup service for the Internet. If BIND is enabled on your system, you can make a call to the BIND resolver to obtain host names and addresses.
Typically, you make a call to the BIND resolver either before you bind
a socket or before you make a connection to a socket. You can also use
this service to translate either the local or remote host name to an
address before making a connection.
2.3.1 BIND Lookups with OpenVMS System Services
If BIND is enabled on your system, the IO$_ACPCONTROL function searches the BIND database for the host name if it does not find the name in the local host database. The p1 argument allows you to specify the GETHOSTBYADDR or GETHOSTBYNAME subfunctions to control how the routine searches the database.
Example 2-3 shows a BIND lookup with OpenVMS system services.
Example 2-3 BIND Lookup Using OpenVMS System Services |
---|
/* ** ** Bind the socket to a local address. ** */ addrLength = sizeof( localAddr ); memset( &localAddr, 0, sizeof( localAddr )); localAddr.sin_family = AF_INET; localAddr.sin_addr.s_addr = INADDR_ANY; localAddr.sin_port = htons( SERVER_PORT ); /* ** ** Declare and populate a string descriptor, (struct dsc$descriptor_s), ** as defined in <descrip.h>. ** */ localAddrDSC.dsc$a_pointer = (char*)&localAddr; localAddrDSC.dsc$w_length = (long)addrLength; /* ** ** Attempt to Bind the device socket to the local host address. ** Use the function code of IO$_SETMODE, passing the local ** address information as a descriptor to P3. ** ** NOTE: The functionality of this call, to bind the socket, and the ** functionality of the sys$qiow call, to create the socket, could be ** combined into one call. ** */ sysSrvSts = sys$qiow( 0, /* efn.v | 0 */ IOChannel, /* chan.v */ IO$_SETMODE, /* func.v */ &iosb, /* iosb.r | 0 */ 0, 0, /* astadr, astprm: UNUSED */ 0, 0, /* p1, p2 UNUSED */ &localAddrDSC, /* p3.d Socket bind parameter */ 0, 0, 0 /* p4, p5, p6 UNUSED */ ); if((( sysSrvSts & 1 ) != 1 ) || /* Validate the system service status. */ (( iosb.cond_value & 1 ) != 1)) /* Validate the IO status. */ { cleanup( IOChannel ); errorExit( sysSrvSts, iosb.cond_value ); } |
If the BIND resolver is enabled on your system, you can use either of the following routines to search the BIND database if the host name is not found in the local database:
The host record contains both name and address information.
Example 2-4 shows an example of using the gethostname(), gethostbyname(), and gethostbyaddr() routines to find a local host name and address.
Example 2-4 BIND Lookup Using C Socket Programming |
---|
/* This program finds the hostname of the system where the application is running, then looks itself up both by name and by address. It looks at only the first address returned. */ #include <netdb.h> #include <errno.h> #include <socket.h> #include <in.h> main() { char hostname[33]; struct in_addr our_address; struct hostent *hostent_ptr; if (gethostname(hostname, sizeof(hostname)))perror("gethostname");(1) printf("Local hostname: %s\n", hostname); if (!(hostent_ptr = gethostbyname(hostname))) perror("gethostbyname");(2) else our_address.s_addr = *(int *)hostent_ptr->h_addr; printf("Found host: %s address: %s\n", hostent_ptr->h_name, inet_ntoa(our_address.s_addr)); if (!(hostent_ptr = gethostbyaddr(&our_address.s_addr, sizeof(our_address.s_addr),(3) AF_INET))) perror("gethostbyaddr"); else printf("Back-translated host: %s\n", hostent_ptr->h_name); } |
In this example, the following routines and arguments were used to find a local host name and address:
Previous | Next | Contents | Index |