The following example illustrates using socket functions in a network application program. The steps are written using many of the basic socket functions, C socket syntax, and conventions described in this information.
#include <sys/socket.h>
⋮
int s;
⋮
s = socket(AF_INET, SOCK_STREAM, 0);
The code fragment in Figure 1 allocates a socket descriptor s in the Internet address family. The domain parameter is a constant that specifies the domain where the communication is taking place. A domain is the collection of application programs using the same addressing convention. z/OS® UNIX supports three domains: AF_INET, AF_INET6, and AF_UNIX. The type parameter is a constant that specifies the type of socket, which can be SOCK_STREAM, or SOCK_DGRAM.
The protocol parameter is a constant that specifies the protocol to use. For AF_INET, it can be set to IPPROTO_UDP for SOCK_DGRAM and IPPROTO_TCP for SOCK_STREAM. Passing 0 chooses the default protocol. If successful, the socket() call returns a positive integer socket descriptor. For AF_UNIX, the protocol parameter must be 0. These values are defined in the netinet/in.h include file.
int bind(int s, struct sockaddr *name, int namelen);
⋮
int rc;
int s;
struct sockaddr_in myname;
/* clear the structure to be sure that the sin_zero field is clear */
memset(&myname, 0, sizeof(myname));
myname.sin_family = AF_INET;
myname.sin_addr = inet_addr("129.5.24.1");
/* specific interface */
myname.sin_port = htons(1024);
⋮
rc = bind(s, (struct sockaddr *) &myname,
sizeof(myname));
Figure 3 shows another example of the bind() call. It uses the utility routine gethostbyname() to find the Internet address of the host, rather than using inet_addr() with a specific address.
int bind(int s, struct sockaddr_in name, int namelen);
⋮
int rc;
int s;
char *hostname = "myhost";
struct sockaddr_in myname;
struct hostent *hp;
hp = gethostbyname(hostname);
/*clear the structure to be sure that
the sin_zero field is clear*/
memset(&myname,0,sizeof(myname));
myname.sin_family = AF_INET;
myname.sin_addr.s_addr = *((ip_addr_t
*)hp->h_addr);
myname.sin_port = htons(1024);
⋮
rc = bind(s,(struct
sockaddr *) &myname, sizeof(myname));
int listen(int s, int backlog);
⋮
int s;
int rc;
⋮
rc = listen(s, 5);
The listen() call tells the TCP/IP address space that the server is ready to begin accepting connections, and that a maximum of five connection requests can be queued for the server. Additional requests are ignored. For a complete description, see z/OS XL C/C++ Runtime Library Reference.
int connect(int s, struct sockaddr *name, int namelen);
⋮
int s;
struct sockaddr_in servername;
int rc;
⋮
memset(&servername, 0,sizeof(servername));
servername.sin_family = AF_INET;
servername.sin_addr = inet_addr("129.5.24.1");
servername.sin_port = htons(1024);
⋮
rc = connect(s, (struct sockaddr *) &servername,
sizeof(servername));
The connect() call attempts to connect socket descriptor s to the server with an address servername. This could be the server that was used in the previous bind() example. The connect request is completed immediately and returns control to the caller, regardless of the server accepting the connection. After a successful return, the socket descriptor s is associated with the connection to the server. For a complete description, see z/OS XL C/C++ Runtime Library Reference.
int accept(int s, struct sockaddr *addr, int *addrlen);
⋮
int clientsocket;
int s;
struct sockaddr clientaddress;
int addrlen;
⋮
addrlen = sizeof(clientaddress);
⋮
clientsocket = accept(s, &clientaddress, &addrlen);
When a connection request is accepted on socket descriptor s, the name of the client and length of the client name are returned, along with a new socket descriptor. The new socket descriptor is associated with the client that began the connection, and s is again available to accept new connections. For a complete description, see z/OS XL C/C++ Runtime Library Reference.
int send(int socket, char *buf, int buflen, int flags);
int recv(int socket, char *buf, int buflen, int flags);
⋮
int bytes_sent;
int bytes_received;
char data_sent[256];
char data_received[256];
int s;
⋮
bytes_sent = send(s, data_sent,
sizeof(data_sent), 0);
⋮
bytes_received = recv(s,
data_received, sizeof(data_received), 0);
The example in Figure 7 shows an application program sending data on a connected socket and receiving data in response. The flags field can be used to specify additional options to send() or recv(), such as sending out-of-band data. For more information see z/OS XL C/C++ Runtime Library Reference.
int sendto(int socket, char *buf, int buflen, int flags,
struct sockaddr *addr, int addrlen);
int recvfrom(int socket, char *buf, int buflen, int flags,
struct sockaddr *addr, int *addrlen);
⋮
int bytes_sent;
int bytes_received;
char data_sent[256];
char data_received[256];
struct sockaddr_in to;
struct sockaddr from;
int addrlen;
int s;
⋮
memset(&to, 0, sizeof(to));
to.sin_family = AF_INET;
to.sin_addr = inet_addr("129.5.24.1");
to.sin_port = htons(1024);
⋮
bytes_sent = sendto(s, data_sent,
sizeof(data_sent), 0, &to, sizeof(to));
⋮
addrlen = sizeof(from); /* must be initialized */
bytes_received = recvfrom(s, data_received,
sizeof(data_received), 0, &from, &addrlen);
The sendto() and recvfrom() calls take additional parameters that allow the caller to specify the recipient of the data or to be notified of the sender of the data. For more information see z/OS XL C/C++ Runtime Library Reference. Usually, sendto() and recvfrom() are used for datagram sockets, and send() and recv() are used for stream sockets.
fd_set readsocks;
fd_set writesocks;
fd_set exceptsocks;
struct timeval timeout;
int number_of_sockets;
int number_found;
⋮
/* number_of_sockets previously set to the socket number of largest
* integer value.
* Clear masks out.
*/
FD_ZERO(&readsocks);; FD_ZERO(&writesocks); FD_ZERO(&exceptsocks);
/* Set masks for socket s only */
FD_SET(s, &readsocks)
FD_SET(s, &writesocks)
FD_SET(s, &exceptsocks)
⋮
/* go into select wait for 5 minutes waiting for socket s to become
ready or the timer has popped*/
rc = select(number_of_sockets+1,
&readsocks, &writesocks, &exceptsocks, &timeout);
⋮
/* Check rc for condition set upon exiting select */
number_found = select(number_of_sockets,
&readsocks, &writesocks, &exceptsocks, &timeout);
In this example, the application program uses bit sets to indicate that the sockets are being tested for certain conditions and also indicates a timeout. If the timeout parameter is NULL, the select() call blocks until a socket becomes ready. If the timeout parameter is nonzero, select() waits up to this amount of time for at least one socket to become ready on the indicated conditions. This is useful for application programs servicing multiple connections that cannot afford to block, waiting for data on one connection. For a complete description, see z/OS XL C/C++ Runtime Library Reference.
int ioctl(int s, unsigned long command, char *command_data);
⋮
int s;
int dontblock;
char buf[256];
int rc;
⋮
dontblock = 1;
⋮
rc = ioctl(s, FIONBIO, (char *) &dontblock);
⋮
if (((rc=recv(s, buf, sizeof(buf),
0)) < 0)&&(errno == EWOULDBLOCK))
/* no data available */
else
/* either got data or some other error occurred */
This example causes the socket descriptor s to be placed into nonblocking mode. When this socket is passed as a parameter to calls that would block, such as recv() when data is not present, it causes the call to return with an error code, and the global errno value is set to EWOULDBLOCK. Setting the mode of the socket to be nonblocking allows an application program to continue processing without becoming blocked. For a complete description, see z/OS XL C/C++ Runtime Library Reference.
int close(int s);
⋮
int rc;
int s;
rc = close(s);