ibm-information-center/dist/eclipse/plugins/i5OS.ic.rzab6_5.4.0.1/xnonblock.htm

416 lines
20 KiB
HTML

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang="en-us" xml:lang="en-us">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="security" content="public" />
<meta name="Robots" content="index,follow" />
<meta http-equiv="PICS-Label" content='(PICS-1.1 "http://www.icra.org/ratingsv02.html" l gen true r (cz 1 lz 1 nz 1 oz 1 vz 1) "http://www.rsac.org/ratingsv01.html" l gen true r (n 0 s 0 v 0 l 0) "http://www.classify.org/safesurf/" l gen true r (SS~~000 1))' />
<meta name="DC.Type" content="reference" />
<meta name="DC.Title" content="Example: Nonblocking I/O and select()" />
<meta name="abstract" content="This sample program uses nonblocking and the select() API." />
<meta name="description" content="This sample program uses nonblocking and the select() API." />
<meta name="DC.Relation" scheme="URI" content="example.htm" />
<meta name="DC.Relation" scheme="URI" content="cnonblock.htm" />
<meta name="DC.Relation" scheme="URI" content="cmultiplex.htm" />
<meta name="DC.Relation" scheme="URI" content="designrec.htm" />
<meta name="DC.Relation" scheme="URI" content="designrec.htm" />
<meta name="DC.Relation" scheme="URI" content="generic.htm" />
<meta name="DC.Relation" scheme="URI" content="../apis/accept.htm" />
<meta name="DC.Relation" scheme="URI" content="../apis/recv.htm" />
<meta name="DC.Relation" scheme="URI" content="../apis/ioctl.htm" />
<meta name="DC.Relation" scheme="URI" content="../apis/send.htm" />
<meta name="DC.Relation" scheme="URI" content="../apis/listen.htm" />
<meta name="DC.Relation" scheme="URI" content="../apis/close.htm" />
<meta name="DC.Relation" scheme="URI" content="../apis/socket.htm" />
<meta name="DC.Relation" scheme="URI" content="../apis/bind.htm" />
<meta name="DC.Relation" scheme="URI" content="../apis/sselect.htm" />
<meta name="copyright" content="(C) Copyright IBM Corporation 2001, 2006" />
<meta name="DC.Rights.Owner" content="(C) Copyright IBM Corporation 2001, 2006" />
<meta name="DC.Format" content="XHTML" />
<meta name="DC.Identifier" content="xnonblock" />
<meta name="DC.Language" content="en-us" />
<!-- All rights reserved. Licensed Materials Property of IBM -->
<!-- US Government Users Restricted Rights -->
<!-- Use, duplication or disclosure restricted by -->
<!-- GSA ADP Schedule Contract with IBM Corp. -->
<link rel="stylesheet" type="text/css" href="./ibmdita.css" />
<link rel="stylesheet" type="text/css" href="./ic.css" />
<title>Example: Nonblocking I/O and select()</title>
</head>
<body id="xnonblock"><a name="xnonblock"><!-- --></a>
<!-- Java sync-link --><script language="Javascript" src="../rzahg/synch.js" type="text/javascript"></script>
<h1 class="topictitle1">Example: Nonblocking I/O and <span class="apiname">select()</span></h1>
<div><p>This sample program uses nonblocking and the <span class="apiname">select() </span>API.</p>
<div class="section"><p><br /><img src="rzab6508.gif" alt="Graphic shows the socket calls that are used in the nonblocking I/O and select() example program." /><br /></p>
</div>
<div class="section"><h4 class="sectiontitle">Socket flow of events: Server that uses nonblocking I/O and
select()</h4><p>The following calls are used in the example:</p>
<ol><li>The <span class="apiname">socket()</span> function returns a socket descriptor representing
an endpoint. The statement also identifies that the INET (Internet Protocol)
address family with the TCP transport (SOCK_STREAM) is used for this socket.</li>
<li>The <span class="apiname">ioctl()</span> function allows the local address to be
reused when the server is restarted before the required wait time expires.
In this example, it sets the socket to be nonblocking. All of the sockets
for the incoming connections are also nonblocking because they inherit that
state from the listening socket.</li>
<li>After the socket descriptor is created, the <span class="apiname">bind()</span> function
gets a unique name for the socket. </li>
<li>The <span class="apiname">listen()</span> allows the server to accept incoming client
connections. </li>
<li>The server uses the <span class="apiname">accept()</span> function to accept an
incoming connection request. The <span class="apiname">accept()</span> call blocks indefinitely
waiting for the incoming connection to arrive. </li>
<li>The <span class="apiname">select()</span> function allows the process to wait for
an event to occur and to wake up the process when the event occurs. In this
example, the <span class="apiname">select()</span> function returns a number that represents
the socket descriptors that are ready to be processed. <dl><dt class="dlterm">0</dt>
<dd>Indicates that the process times out. In this example, the
timeout is set for 30 seconds.</dd>
<dt class="dlterm">-1</dt>
<dd>Indicates that the process has failed.</dd>
<dt class="dlterm">1</dt>
<dd>Indicates only one descriptor is ready to be processed. In this example,
when a 1 is returned the FD_ISSET and the subsequent socket calls complete
only once.</dd>
<dt class="dlterm">n</dt>
<dd>Indicates multiple descriptors waiting to be processed. In this example,
when an n is returned the FD_ISSET and subsequent code loops and completes
the requests in the order they are received by the server.</dd>
</dl>
</li>
<li>The <span class="apiname">accept()</span> and <span class="apiname">recv()</span> functions
are completed when the EWOULDBLOCK is returned. </li>
<li>The <span class="apiname">send()</span> function echoes the data back to the client. </li>
<li>The <span class="apiname">close()</span> function closes any open socket descriptors.</li>
</ol>
</div>
<div class="section"><div class="note"><span class="notetitle">Note:</span> By using the code examples, you agree to the terms of the <a href="codedisclaimer.htm">Code license and disclaimer information</a>.</div>
<pre>#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;sys/ioctl.h&gt;
#include &lt;sys/socket.h&gt;
#include &lt;sys/time.h&gt;
#include &lt;netinet/in.h&gt;
#include &lt;errno.h&gt;
#define SERVER_PORT 12345
#define TRUE 1
#define FALSE 0
main (int argc, char *argv[])
{
int i, len, rc, on = 1;
int listen_sd, max_sd, new_sd;
int desc_ready, end_server = FALSE;
int close_conn;
char buffer[80];
struct sockaddr_in addr;
struct timeval timeout;
struct fd_set master_set, working_set;
/*************************************************************/
/* Create an AF_INET stream socket to receive incoming */
/* connections on */
/*************************************************************/
listen_sd = socket(AF_INET, SOCK_STREAM, 0);
if (listen_sd &lt; 0)
{
perror("socket() failed");
exit(-1);
}
/*************************************************************/
/* Allow socket descriptor to be reuseable */
/*************************************************************/
rc = setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR,
(char *)&amp;on, sizeof(on));
if (rc &lt; 0)
{
perror("setsockopt() failed");
close(listen_sd);
exit(-1);
}
/*************************************************************/
/* Set socket to be nonblocking. All of the sockets for */
/* the incoming connections will also be nonblocking since */
/* they will inherit that state from the listening socket. */
/*************************************************************/
rc = ioctl(listen_sd, FIONBIO, (char *)&amp;on);
if (rc &lt; 0)
{
perror("ioctl() failed");
close(listen_sd);
exit(-1);
}
/*************************************************************/
/* Bind the socket */
/*************************************************************/
memset(&amp;addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(SERVER_PORT);
rc = bind(listen_sd,
(struct sockaddr *)&amp;addr, sizeof(addr));
if (rc &lt; 0)
{
perror("bind() failed");
close(listen_sd);
exit(-1);
}
/*************************************************************/
/* Set the listen back log */
/*************************************************************/
rc = listen(listen_sd, 32);
if (rc &lt; 0)
{
perror("listen() failed");
close(listen_sd);
exit(-1);
}
/*************************************************************/
/* Initialize the master fd_set */
/*************************************************************/
FD_ZERO(&amp;master_set);
max_sd = listen_sd;
FD_SET(listen_sd, &amp;master_set);
/*************************************************************/
/* Initialize the timeval struct to 3 minutes. If no */
/* activity after 3 minutes this program will end. */
/*************************************************************/
timeout.tv_sec = 3 * 60;
timeout.tv_usec = 0;
/*************************************************************/
/* Loop waiting for incoming connects or for incoming data */
/* on any of the connected sockets. */
/*************************************************************/
do
{
/**********************************************************/
/* Copy the master fd_set over to the working fd_set. */
/**********************************************************/
memcpy(&amp;working_set, &amp;master_set, sizeof(master_set));
/**********************************************************/
/* Call select() and wait 5 minutes for it to complete. */
/**********************************************************/
printf("Waiting on select()...\n");
rc = select(max_sd + 1, &amp;working_set, NULL, NULL, &amp;timeout);
/**********************************************************/
/* Check to see if the select call failed. */
/**********************************************************/
if (rc &lt; 0)
{
perror(" select() failed");
break;
}
/**********************************************************/
/* Check to see if the 5 minute time out expired. */
/**********************************************************/
if (rc == 0)
{
printf(" select() timed out. End program.\n");
break;
}
/**********************************************************/
/* One or more descriptors are readable. Need to */
/* determine which ones they are. */
/**********************************************************/
desc_ready = rc;
for (i=0; i &lt;= max_sd &amp;&amp; desc_ready &gt; 0; ++i)
{
/*******************************************************/
/* Check to see if this descriptor is ready */
/*******************************************************/
if (FD_ISSET(i, &amp;working_set))
{
/****************************************************/
/* A descriptor was found that was readable - one */
/* less has to be looked for. This is being done */
/* so that we can stop looking at the working set */
/* once we have found all of the descriptors that */
/* were ready. */
/****************************************************/
desc_ready -= 1;
/****************************************************/
/* Check to see if this is the listening socket */
/****************************************************/
if (i == listen_sd)
{
printf(" Listening socket is readable\n");
/*************************************************/
/* Accept all incoming connections that are */
/* queued up on the listening socket before we */
/* loop back and call select again. */
/*************************************************/
do
{
/**********************************************/
/* Accept each incoming connection. If */
/* accept fails with EWOULDBLOCK, then we */
/* have accepted all of them. Any other */
/* failure on accept will cause us to end the */
/* server. */
/**********************************************/
new_sd = accept(listen_sd, NULL, NULL);
if (new_sd &lt; 0)
{
if (errno != EWOULDBLOCK)
{
perror(" accept() failed");
end_server = TRUE;
}
break;
}
/**********************************************/
/* Add the new incoming connection to the */
/* master read set */
/**********************************************/
printf(" New incoming connection - %d\n", new_sd);
FD_SET(new_sd, &amp;master_set);
if (new_sd &gt; max_sd)
max_sd = new_sd;
/**********************************************/
/* Loop back up and accept another incoming */
/* connection */
/**********************************************/
} while (new_sd != -1);
}
/****************************************************/
/* This is not the listening socket, therefore an */
/* existing connection must be readable */
/****************************************************/
else
{
printf(" Descriptor %d is readable\n", i);
close_conn = FALSE;
/*************************************************/
/* Receive all incoming data on this socket */
/* before we loop back and call select again. */
/*************************************************/
do
{
/**********************************************/
/* Receive data on this connection until the */
/* recv fails with EWOULDBLOCK. If any other */
/* failure occurs, we will close the */
/* connection. */
/**********************************************/
rc = recv(i, buffer, sizeof(buffer), 0);
if (rc &lt; 0)
{
if (errno != EWOULDBLOCK)
{
perror(" recv() failed");
close_conn = TRUE;
}
break;
}
/**********************************************/
/* Check to see if the connection has been */
/* closed by the client */
/**********************************************/
if (rc == 0)
{
printf(" Connection closed\n");
close_conn = TRUE;
break;
}
/**********************************************/
/* Data was received */
/**********************************************/
len = rc;
printf(" %d bytes received\n", len);
/**********************************************/
/* Echo the data back to the client */
/**********************************************/
rc = send(i, buffer, len, 0);
if (rc &lt; 0)
{
perror(" send() failed");
close_conn = TRUE;
break;
}
} while (TRUE);
/*************************************************/
/* If the close_conn flag was turned on, we need */
/* to clean up this active connection. This */
/* clean up process includes removing the */
/* descriptor from the master set and */
/* determining the new maximum descriptor value */
/* based on the bits that are still turned on in */
/* the master set. */
/*************************************************/
if (close_conn)
{
close(i);
FD_CLR(i, &amp;master_set);
if (i == max_sd)
{
while (FD_ISSET(max_sd, &amp;master_set) == FALSE)
max_sd -= 1;
}
}
} /* End of existing connection is readable */
} /* End of if (FD_ISSET(i, &amp;working_set)) */
} /* End of loop through selectable descriptors */
} while (end_server == FALSE);
/*************************************************************/
/* Clean up all of the sockets that are open */
/*************************************************************/
for (i=0; i &lt;= max_sd; ++i)
{
if (FD_ISSET(i, &amp;master_set))
close(i);
}
}</pre>
</div>
</div>
<div>
<div class="familylinks">
<div class="parentlink"><strong>Parent topic:</strong> <a href="example.htm" title="These examples provide many sample programs that illustrate the more advanced socket concepts. You can use these sample programs to create your own applications that complete a similar task.">Examples: Socket application designs</a></div>
</div>
<div class="relconcepts"><strong>Related concepts</strong><br />
<div><a href="cnonblock.htm" title="When an application issues one of the socket input functions and there is no data to read, the function blocks and does not return until there is data to read.">Nonblocking I/O</a></div>
<div><a href="cmultiplex.htm" title="Because asynchronous I/O provides a more efficient way to maximize your application resources, it is recommended that you use asynchronous I/O APIs rather than the select() API. However, your specific application design may allow select() to be used.">I/O multiplexing—select()</a></div>
</div>
<div class="relref"><strong>Related reference</strong><br />
<div><a href="designrec.htm" title="Before working with socket applications, assess the functional requirements, goals, and needs of the socket application.">Socket application design recommendations</a></div>
<div><a href="generic.htm" title="This code example contains the code for a common client job.">Example: Generic client</a></div>
</div>
<div class="relinfo"><strong>Related information</strong><br />
<div><a href="../apis/accept.htm">accept()</a></div>
<div><a href="../apis/recv.htm">recv()</a></div>
<div><a href="../apis/ioctl.htm">ioctl()</a></div>
<div><a href="../apis/send.htm">send()</a></div>
<div><a href="../apis/listen.htm">listen()</a></div>
<div><a href="../apis/close.htm">close()</a></div>
<div><a href="../apis/socket.htm">socket()</a></div>
<div><a href="../apis/bind.htm">bind()</a></div>
<div><a href="../apis/sselect.htm">select()</a></div>
</div>
</div>
</body>
</html>