Previous | Contents | Index |
You can use any of the following C Socket routines to get device socket information:
Example 2-14 shows a TCP server using the getsockopt(), getpeername() and, getsockname() routines to get device socket information.
Example 2-14 Obtaining Device Socket Information by Using C Socket Programming |
---|
/* This program accepts a connection on TCP port 1234, sends the string, "Hello, world!", and immediately closes the connection and terminates. */ #if defined(__VMS) || defined(VMS) #include <types.h> #include <in.h> #include <socket.h> #include <unixio.h> #include <string.h> #else #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> #include <unistd.h> #include <string.h> #endif #define PORTNUM 1234 main() { struct sockaddr_in lcladdr, name; int r, s, namelen = sizeof(name), one = 1; char *message = "Hello, world!\r\n"; memset( &lcladdr, 0, sizeof(lcladdr)); lcladdr.sin_family = AF_INET; lcladdr.sin_addr.s_addr = INADDR_ANY; lcladdr.sin_port = htons(PORTNUM); if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) perror("socket"); if (setsockopt(s,(1) SOL_SOCKET, (2) SO_REUSEADDR, (3) &one, (4) sizeof(one))) (5) perror("setsockopt"); if (bind(s, &lcladdr, sizeof(lcladdr))) perror("bind"); if (listen(s, 1)) perror("listen"); if ((r = accept(s, 0, 0)) < 0) perror("accept"); if (getsockname(r,(6) &name,(7)&namelen(8)))perror("getsockname"); else printf("Local address: %s\tport: %d\n", inet_ntoa(name.sin_addr.s_addr), ntohs(name.sin_port)); if (getpeername(r,(9) &name,(10) &namelen))(11) perror("getpeername"); else printf("Remote address: %s\tport: %d\n", inet_ntoa(name.sin_addr.s_addr), ntohs(name.sin_port)); if (send(r, message, strlen(message), 0) != strlen(message)) perror("send"); if (close(r)) perror("close"); if (close(s)) perror("close"); } |
TCP/IP allows the application to read data after it performs the following:
The $QIO IO$_READVBLK function transfers data received from the internet host (kept in system dynamic memory) into the address space of the user's process. After the read operation completes, the data in dynamic memory is discarded.
Example 2-15 shows a TCP/IP server using the IO$_READVBLK function to read data into a single I/O buffer.
Example 2-15 Reading Data Using OpenVMS System Services |
---|
/* ** ** Attempt to receive data from the server. ** Use the function code of IO$_READVBLK, passing the address of the ** buffer to P1 and the maximum size of the buffer to P2. ** */ printf("\n Attempt to receive data from the server.\n" ); memset( IOBuff, 'Z', MaxBuff ); sysSrvSts = sys$qiow( 0, /* efn.v | 0 */ IOChannel, /* chan.v */ IO$_READVBLK, /* func.v */ &iosb, /* iosb.r | 0 */ 0, 0, /* astadr, astprm: UNUSED */ IOBuff, /* p1.r IO buffer */ MaxBuff, /* p2.v IO buffer size */ 0, /* p3 UNUSED */ 0, /* p4.v IO options flag */ 0, 0 /* p5, p6 UNUSED */ ); if((( sysSrvSts & 1 ) != 1 ) || /* Validate system service status. */ (( iosb.cond_value & 1 ) != 1)) /* Validate the IO status. */ { cleanup( IOChannel ); errorExit( sysSrvSts, iosb.cond_value ); } else if( iosb.count == 0 ) printf( " FAILED receiving data, no connection.\n" ); else printf( " SUCCEEDED in to receiving: '%s'\n", IOBuff ); |
You can also specify a list of read buffers by omitting the p1
and p2 arguments and passing the list of buffers as the
p6 parameter. See Section 3.7 for more information.
2.9.2 Reading Data with a C Socket Interface
Example 2-16 shows an example of a TCP/IP server using the recv() routine to read data.
Example 2-16 Reading Data Using C Socket Programming |
---|
/* * * INCLUDE FILES * */ #if defined (_VMS || defined (VMS) #include <errno.h> #include <types.h> #include <stdio.h> #include <socket.h> #include <in.h> #include <netdb.h> /* change hostent to comply with BSD 4.3 */ #include <inet.h> #include <tcpip$inetdef.h> /* INET symbol definitions */ . . . main(argc,argv) int argc; char **argv; { int sock_2, sock_3; /* sockets */ static char message[BUFSIZ]; static struct sockaddr_in sock2_name; /* Address struct for socket2.*/ static struct sockaddr_in retsock2_name; /* Address struct for socket2.*/ struct hostent hostentstruct; /* Storage for hostent data. */ struct hostent *hostentptr; /* Pointer to hostent data. */ static char hostname[256]; /* Name of local host. */ int flag; int retval; /* helpful for debugging */ int namelength; . . . /* * Receive message from client socket. */ retval = recv(sock_2,(1) message,(2) sizeof(message),(3) flag);(4) if (retval == -1) { perror ("receive"); cleanup( 1, sock_3); } else printf (" %s\n", message); |
Before a host can receive (read) IP multicast datagrams destined for a particular multicast group other than the all hosts group, the application must direct the host it is running on to become a member of that multicast group.
To join a group or drop membership from a group, specify the following options. Make sure you include the <netinet/in.h> header file.
struct ip_mreq mreq; if (setsockopt( sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, & mreq sizeof(mreq)) == -1) perror("setsockopt"); |
struct ip_mreq { struct in_addr imr_multiaddr; /* IP multicast address of group */ struct in_addr imr_interface; /* local IP address of interface */ }; |
struct ip_mreq mreq; if (setsockopt( sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq sizeof(mreq))== -1) perror("setsockopt"); |
To receive multicast datagrams sent to a specific UDP port, the receiving socket must have bound to that port using the $QIO(IO$_SETMODE) system service routine or the bind() C Socket routine. More than one process can receive UDP datagrams destined for the same port if the routine is preceded by a setsockopt() system call that specifies the SO_REUSEPORT option.
For example:
int setreuse = 1; if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &setreuse, sizeof(setreuse)) == -1) perror("setsockopt"); |
When the SO_REUSEPORT option is set, every incoming multicast or broadcast UDP datagram destined for the shared port is delivered to all sockets bound to that port.
Delivery of IP multicast datagrams to SOCK_RAW sockets is determined by
the protocol type of the destination.
2.11 Reading Out-of-Band Data (TCP)
Only stream-type (TCP/IP) sockets can receive out-of-band (OOB) data. Upon receiving a TCP/IP OOB character, TCP/IP Services stores a pointer in the received stream to the character that precedes the OOB character.
A read operation with a user buffer size larger than the size of the received stream up to the OOB character completes by returning to the user the received stream up to, but not including, the OOB character.
Poll the socket to determine if additional read operations are needed
before getting all the characters from the stream preceding the OOB
character.
2.11.1 Reading OOB Data with OpenVMS System Services
To receive OOB data from a remote process, issue the IO$_READVBLK function with the IO$M_INTERRUPT modifier.
To poll the socket, issue a $QIO command with the IO$_SENSEMODE function and the TCPIP$C_IOCTL subfunction that specifies the SIOCATMARK 'ioctl' parameter.
If the SIOCATMARK returns a value of 0, issue additional read QIOs to read more data before reading the OOB character. If the SIOCATMARK returns a value of 1, the next read QIO returns the OOB character.
These functions are useful if a socket has the socket option OOBINLINE set. The OOB character is read with the characters in the stream (IO$_READVBLK), but not before the preceding characters. To determine whether or not the first character in the user buffer on the next read is an OOB, poll the socket.
To get a received OOB character for a socket with the socket option OOBINLINE clear, issue one of the following functions:
Example 2-17 shows how to use the IO$M_INTERRUPT modifier to read out-of-band data.
Example 2-17 Reading OOB Data Using OpenVMS System Services |
---|
/* ** Attempt to receive the OOB data from the client. ** Use the function code of IO$_READVBLK, passing the address of the ** input buffer to P1, and the OOB code, TCPIP$C_MSG_OOB, to P4. ** We support the sending and receiving of a one byte of OOB data. */ sysSrvSts = sys$qiow( 0, /* efn.v | 0 */ IOChanClient, /* chan.v */ IO$_READVBLK, /* func.v */ &iosb, /* iosb.r | 0 */ 0, 0, /* astadr, astprm: UNUSED */ &OOBBuff, /* p1.r IO buffer */ MaxBuff, /* p2.v IO buffer size */ 0, /* p3 UNUSED */ TCPIP$C_MSG_OOB, /* p4.v IO options flag */ 0, 0 /* p5, p6 UNUSED */ ); if((( sysSrvSts & 1 ) != 1 ) || /* Validate the system service. */ (( iosb.cond_value & 1 ) != 1)) /* Validate the IO status. */ { cleanup( IOChanClient ); cleanup( IOChannel ); errorExit( sysSrvSts, iosb.cond_value ); } else if( iosb.count == 0 ) printf( " FAILED to receive the message, no connection.\n" ); else printf( " SUCCEEDED in receiving '%d'\n", OOBBuff ); |
You can use the recv() socket routine with the MSG_OOB flag set to receive out-of-band data regardless of how many of the preceding characters in the stream you have received.
Example 2-18 shows an example of a TCP/IP server using the recv() routine to receive out-of-band data.
Example 2-18 Reading OOB Data Using C Socket Programming |
---|
#include <types.h> #include <in.h> #include <socket.h> #include <unixio.h> #include <string.h> #define PORTNUM 1234 . . . /* * Accept connection from socket 2: * accepted connection will be on socket 3 */ namelength = sizeof (sock2_name); sock_3 = accept (sock_2, &sock2_name, &namelength); if (sock_3 == -1) { perror ("accept"); cleanup( 2, sock_2, sock_3); } /* * Receive message from socket 2. */ flag = MSG_OOB; retval = recv(sock_3,(1) message,(2)sizeof(message),(3)flag);(4) if (retval == -1) { perror ("receive"); cleanup( 2, sock_2, sock_3); } else printf (" %s\n", message); |
You can issue a read operation to look at data in a socket receive
queue without removing the data from the buffer. This is called peeking.
2.12.1 Peeking at Data with OpenVMS System Services
To peek at data next in the socket receive queue, issue the
IO$_READVBLK function of the $QIO system service with the TCPIP$M_PEEK
flag. This allows you to issue multiple read operations on the same
data.
2.12.2 Peeking at Data with the C Socket Interface
Use the MSG_PEEK flag with the recv() routine to peek at data in the socket receive queue. Example 2-19 shows a TCP server using the recv() routine with the MSG_PEEK flag to peek at received data.
Example 2-19 Previewing Data Using C Socket Programming |
---|
/* This program accepts a connection on TCP port 1234, prompts for a character to be entered, and uses the "peek" feature to determine what character was chosen before actually reading it. */ #include <types.h> #include <in.h> #include <socket.h> #include <unixio.h> #define PORTNUM 1234 main() { struct sockaddr_in lcladdr; int r, s; char buffer[64]; memset() lcladdr.sin_family = AF_INET; lcladdr.sin_addr.s_addr = INADDR_ANY; lcladdr.sin_port = htons(PORTNUM); if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) perror("socket"); if (bind(s, &lcladdr, sizeof(lcladdr))) perror("bind"); if (listen(s, 1)) perror("listen"); if ((r = accept(s, 0, 0)) < 0) perror("accept"); sprintf(buffer, "Please pick a character:\r\n"); if (send(r, buffer, strlen(buffer), 0) != strlen(buffer)) perror("send"); if (recv(r,(1) buffer,(2) 1,(3) MSG_PEEK)(4) != 1) perror("recv"); sprintf(buffer, "Before receiving, I see you picked '%c'.\r\n", buffer[0]); if (send(r, buffer, strlen(buffer), 0) != strlen(buffer)) perror("send"); if (recv(r, buffer, 1, 0) != 1) perror("recv"); sprintf(buffer, "Sure enough, I received '%c'.\r\n", buffer[0]); if (send(r, buffer, strlen(buffer), 0) != strlen(buffer)) perror("send"); if (close(r)) perror("close"); if (close(s)) perror("close"); } |
The recv() routine receives data from a connected socket and places it in a buffer, as follows:
For programs that use TCP, data writing occurs after a client program
initiates a connection and the server program accepts the connection.
When using UDP, you also have the option of establishing a default peer
address with a specific socket, but this is not required for data
transfer.
2.13.1 Writing Data with OpenVMS System Services
The IO$_WRITEVBLK function of the $QIO system service copies data from the address space of the user's process to system dynamic memory and then transfers the data to an internet host or port.
Example 2-20 shows an example of a TCP client using the IO$_WRITEVBLK function to transmit a single data buffer. An IO$_ACCESS QIO was previously executed to establish the connection with the remote host.
Example 2-20 Writing Data Using OpenVMS System Services |
---|
/* ** ** Attempt to send data to a previously established network connection. ** Use the function code IO$_WRITEVBLK, passing the address of the ** output buffer to P1, and the size of the message to P2. ** */ sprintf( IOBuff, "The answer is %d", 42 ); sysSrvSts = sys$qiow( 0, /* efn.v | 0 */ IOChanClient, /* chan.v */ IO$_WRITEVBLK, /* func.v */ &iosb, /* iosb.r | 0 */ 0, 0, /* astadr, astprm: UNUSED */ IOBuff, /* p1.r IO buffer */ strlen( IOBuff )+ 1, /* p2.v IO buffer size */ 0, /* p3 UNUSED */ 0, /* p4.v IO options flag */ 0, 0 /* p5, p6 UNUSED */ ); if((( sysSrvSts & 1 ) != 1 ) || /* Validate system service. */ (( iosb.cond_value & 1 ) != 1)) /* Validate the IO status. */ { cleanup( IOChanClient /* chan.v */ ); cleanup( IOChannel ); errorExit( sysSrvSts, iosb.cond_value ); } else if( iosb.count == 0 ) printf( " FAILED to send message, no connection.\n\n" ); else printf( " SUCCEEDED in sending the message.\n\n" ); |
You can also specify a list of write buffers by omitting the p1 and p2 parameters, and instead passing the list of buffers as the p5 parameter. Note that when writing a list of buffers, the p5 parameter is used; when reading a list, the p6 parameter is used. For more information, see Section 3.6.
Previous | Next | Contents | Index |