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

442 lines
21 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: Use asynchronous I/O" />
<meta name="abstract" content="An application creates an I/O completion port using the QsoCreateIOCompletionPort() API." />
<meta name="description" content="An application creates an I/O completion port using the QsoCreateIOCompletionPort() API." />
<meta name="DC.Relation" scheme="URI" content="example.htm" />
<meta name="DC.Relation" scheme="URI" content="asynchi0.htm" />
<meta name="DC.Relation" scheme="URI" content="designrec.htm" />
<meta name="DC.Relation" scheme="URI" content="xcodesigns.htm" />
<meta name="DC.Relation" scheme="URI" content="generic.htm" />
<meta name="DC.Relation" scheme="URI" content="../apis/createiocompletionport.htm" />
<meta name="DC.Relation" scheme="URI" content="../apis/users_14.htm" />
<meta name="DC.Relation" scheme="URI" content="../apis/waitforiocompletion.htm" />
<meta name="DC.Relation" scheme="URI" content="../apis/startrecv.htm" />
<meta name="DC.Relation" scheme="URI" content="../apis/startaccept.htm" />
<meta name="DC.Relation" scheme="URI" content="../apis/startsend.htm" />
<meta name="DC.Relation" scheme="URI" content="../apis/destroyiocompletionport.htm" />
<meta name="DC.Relation" scheme="URI" content="xsignals.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="xasynchi0" />
<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: Use asynchronous I/O</title>
</head>
<body id="xasynchi0"><a name="xasynchi0"><!-- --></a>
<!-- Java sync-link --><script language="Javascript" src="../rzahg/synch.js" type="text/javascript"></script>
<h1 class="topictitle1">Example: Use asynchronous I/O</h1>
<div><p>An application creates an I/O completion port using the <span class="apiname">QsoCreateIOCompletionPort()</span> API.</p>
<div class="section"><p>This API returns a handle that can be used to
schedule and wait for completion of asynchronous I/O requests. The application
starts an input or an output function, specifying an I/O completion port handle.
When the I/O is completed, status information and an application-defined handle
are posted to the specified I/O completion port. The post to the I/O completion
port wakes up exactly one of possibly many threads that are waiting. The application
receives the following items:</p>
<ul><li>A buffer that was supplied on the original request </li>
<li>The length of data that was processed to or from that buffer</li>
<li>A indication of what type of I/O operation has been completed</li>
<li>Application-defined handle that was passed on the initial I/O request</li>
</ul>
<p>This application handle can be the socket descriptor
identifying the client connection, or a pointer to storage that contains extensive
information about the state of the client connection. Since the operation
was completed and the application handle was passed, the worker thread determines
the next step to complete the client connection. Worker threads that process
these completed asynchronous operations can handle many different client requests
and are not tied to just one. Because copying to and from user buffers occurs
asynchronously to the server processes, wait time for client request diminishes.
This can be beneficial on systems where there are multiple processors.</p>
</div>
<div class="section"><p><br /><img src="rzab6504.gif" alt="This graphic diagrams the sample programs that use Asynchronous I/O." /><br /></p>
</div>
<div class="section"><h4 class="sectiontitle">Flow of socket events: Asynchronous I/O server</h4><p>The
following sequence of the socket calls provides a description of the graphic.
It also describes the relationship between the server and worker examples.
Each set of flows contain links to usage notes on specific APIs. If you need
more details on the use of a particular API, you can use these links. This
flow describes the socket calls in the following sample application. Use this
server example with the generic client example.</p>
<ol><li>Master thread creates I/O completion port by calling <span class="apiname">QsoCreateIOCompletionPort()</span></li>
<li>Master thread creates pool of worker thread(s) to process any I/O completion
port requests with the <span class="apiname">pthread_create</span> function. </li>
<li>Worker thread(s) call <span class="apiname">QsoWaitForIOCompletionPort()</span> which
waits for client requests to process.</li>
<li>The master thread accepts a client connection and proceeds to issue a <span class="apiname">QsoStartRecv()</span> which
specifies the I/O completion port upon which the worker threads are waiting.
<div class="note"><span class="notetitle">Note:</span> You can also use accept asynchronously by using the <span class="apiname">QsoStartAccept()</span>.</div>
</li>
<li>At some point, a client request arrives asynchronous to the server process.
The sockets operating system loads the supplied user buffer and sends the
completed <span class="apiname">QsoStartRecv()</span> request to the specified I/O completion
port. One worker thread is awoken and proceeds to process this request. </li>
<li>The worker thread extracts the client socket descriptor from the application-defined
handle and proceeds to echo the received data back to the client by performing
a <span class="apiname">QsoStartSend()</span> operation.</li>
<li>If the data can be immediately sent, then <span class="apiname">QsoStartSend()</span> returns
indication of the fact; otherwise, the sockets operating system sends the
data as soon as possible and posts indication of the fact to the specified
I/O completion port. The worker thread gets indication of data sent and can
wait on the I/O completion port for another request or end if instructed to
do so. <span class="apiname">QsoPostIOCompletion()</span> can be used by the master
thread to post a worker thread termination event.</li>
<li>Master thread waits for worker thread to finish and then destroys the
I/O completion port by calling <span class="apiname">QsoDestroyIOCompletionPort()</span>. </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>
</div>
<div class="section"><pre> #include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;sys/time.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;sys/socket.h&gt;
#include &lt;netinet/in.h&gt;
#include &lt;errno.h&gt;
#include &lt;unistd.h&gt;
#define _MULTI_THREADED
#include "pthread.h"
#include "qsoasync.h"
#define BufferLength 80
#define Failure 0
#define Success 1
#define SERVPORT 12345
void *workerThread(void *arg);
/********************************************************************/
/* */
/* Function Name: main */
/* */
/* Descriptive Name: Master thread will establish a client */
/* connection and hand processing responsibility */
/* to a worker thread. */
/* Note: Due to the thread attribute of this program, spawn() must */
/* be used to invoke. */
/********************************************************************/
int main()
{
int listen_sd, client_sd, rc;
int on = 1, ioCompPort;
pthread_t thr;
void *status;
char buffer[BufferLength];
struct sockaddr_in serveraddr;
Qso_OverlappedIO_t ioStruct;
/*********************************************/
/* Create an I/O completion port for this */
/* process. */
/*********************************************/
if ((ioCompPort = QsoCreateIOCompletionPort()) &lt; 0)
{
perror("QsoCreateIOCompletionPort() failed");
exit(-1);
}
/*********************************************/
/* Create a worker thread */
/* to process all client requests. The */
/* worker thread will wait for client */
/* requests to arrive on the I/O completion */
/* port just created. */
/*********************************************/
rc = pthread_create(&amp;thr, NULL, workerThread,
&amp;ioCompPort);
if (rc &lt; 0)
{
perror("pthread_create() failed");
QsoDestroyIOCompletionPort(ioCompPort);
close(listen_sd);
exit(-1);
}
/*********************************************/
/* Create an AF_INET stream socket to receive*/
/* incoming connections on */
/*********************************************/
if ((listen_sd = socket(AF_INET, SOCK_STREAM, 0)) &lt; 0)
{
perror("socket() failed");
QsoDestroyIOCompletionPort(ioCompPort);
exit(-1);
}
/*********************************************/
/* Allow socket descriptor to be reuseable */
/*********************************************/
if ((rc = setsockopt(listen_sd, SOL_SOCKET,
SO_REUSEADDR,
(char *)&amp;on,
sizeof(on))) &lt; 0)
{
perror("setsockopt() failed");
QsoDestroyIOCompletionPort(ioCompPort);
close(listen_sd);
exit(-1);
}
/*********************************************/
/* bind the socket */
/*********************************************/
memset(&amp;serveraddr, 0x00, sizeof(struct sockaddr_in));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(SERVPORT);
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
if ((rc = bind(listen_sd,
(struct sockaddr *)&amp;serveraddr,
sizeof(serveraddr))) &lt; 0)
{
perror("bind() failed");
QsoDestroyIOCompletionPort(ioCompPort);
close(listen_sd);
exit(-1);
}
/*********************************************/
/* Set listen backlog */
/*********************************************/
if ((rc = listen(listen_sd, 10)) &lt; 0)
{
perror("listen() failed");
QsoDestroyIOCompletionPort(ioCompPort);
close(listen_sd);
exit(-1);
}
printf("Waiting for client connection.\n");
/*********************************************/
/* accept an incoming client connection. */
/*********************************************/
if ((client_sd = accept(listen_sd, (struct sockaddr *)NULL,
NULL)) &lt; 0)
{
perror("accept() failed");
QsoDestroyIOCompletionPort(ioCompPort);
close(listen_sd);
exit(-1);
}
/*********************************************/
/* Issue QsoStartRecv() to receive client */
/* request. */
/* Note: */
/* postFlag == on denoting request should */
/* posted to the I/O */
/* completion port, even if */
/* if request is immediately */
/* available. Worker thread */
/* will process client */
/* request. */
/*********************************************/
/*********************************************/
/* initialize Qso_OverlappedIO_t structure - */
/* reserved fields must be hex 00's. */
/*********************************************/
memset(&amp;ioStruct, '\0', sizeof(ioStruct));
ioStruct.buffer = buffer;
ioStruct.bufferLength = sizeof(buffer);
/*********************************************/
/* Store the client descriptor in the */
/* Qso_OverlappedIO_t descriptorHandle field.*/
/* This area is used to house information */
/* defining the state of the client */
/* connection. Field descriptorHandle is */
/* defined as a (void *) to allow the server */
/* to address more extensive client */
/* connection state if needed. */
/*********************************************/
*((int*)&amp;ioStruct.descriptorHandle) = client_sd;
ioStruct.postFlag = 1;
ioStruct.fillBuffer = 0;
rc = QsoStartRecv(client_sd, ioCompPort, &amp;ioStruct);
if (rc == -1)
{
perror("QsoStartRecv() failed");
QsoDestroyIOCompletionPort(ioCompPort);
close(listen_sd);
close(client_sd);
exit(-1);
}
/*********************************************/
/* close the server's listening socket. */
/*********************************************/
close(listen_sd);
/*********************************************/
/* Wait for worker thread to finish */
/* processing client connection. */
/*********************************************/
rc = pthread_join(thr, &amp;status);
QsoDestroyIOCompletionPort(ioCompPort);
if ( rc == 0 &amp;&amp; (rc = __INT(status)) == Success)
{
printf("Success.\n");
exit(0);
}
else
{
perror("pthread_join() reported failure");
exit(-1);
}
}
/* end workerThread */
/********************************************************************/
/* */
/* Function Name: workerThread */
/* */
/* Descriptive Name: Process client connection. */
/********************************************************************/
void *workerThread(void *arg)
{
struct timeval waitTime;
int ioCompPort, clientfd;
Qso_OverlappedIO_t ioStruct;
int rc, tID;
pthread_t thr;
pthread_id_np_t t_id;
t_id = pthread_getthreadid_np();
tID = t_id.intId.lo;
/*********************************************/
/* I/O completion port is passed to this */
/* routine. */
/*********************************************/
ioCompPort = *(int *)arg;
/*********************************************/
/* Wait on the supplied I/O completion port */
/* for a client request. */
/*********************************************/
waitTime.tv_sec = 500;
waitTime.tv_usec = 0;
rc = QsoWaitForIOCompletion(ioCompPort, &amp;ioStruct, &amp;waitTime);
if (rc == 1 &amp;&amp; ioStruct.returnValue != -1)
/*********************************************/
/* Client request has been received. */
/*********************************************/
;
else
{
printf("QsoWaitForIOCompletion() or QsoStartRecv() failed.\n");
perror("QsoWaitForIOCompletion() or QsoStartRecv() failed");
return __VOID(Failure);
}
/*********************************************/
/* Obtain the socket descriptor associated */
/* with the client connection. */
/*********************************************/
clientfd = *((int *) &amp;ioStruct.descriptorHandle);
/*********************************************/
/* Echo the data back to the client. */
/* Note: postFlag == 0. If write completes */
/* immediate then indication will be */
/* returned, otherwise once the */
/* write is performed the I/O Completion */
/* port will be posted. */
/*********************************************/
ioStruct.postFlag = 0;
ioStruct.bufferLength = ioStruct.returnValue;
rc = QsoStartSend(clientfd, ioCompPort, &amp;ioStruct);
if (rc == 0)
/*********************************************/
/* Operation complete - data has been sent. */
/*********************************************/
;
else
{
/*********************************************/
/* Two possibilities */
/* rc == -1 */
/* Error on function call */
/* rc == 1 */
/* Write cannot be immediately */
/* performed. Once complete, the I/O */
/* completion port will be posted. */
/*********************************************/
if (rc == -1)
{
printf("QsoStartSend() failed.\n");
perror("QsoStartSend() failed");
close(clientfd);
return __VOID(Failure);
}
/*********************************************/
/* Wait for operation to complete. */
/*********************************************/
rc = QsoWaitForIOCompletion(ioCompPort, &amp;ioStruct, &amp;waitTime);
if (rc == 1 &amp;&amp; ioStruct.returnValue != -1)
/*********************************************/
/* Send successful. */
/*********************************************/
;
else
{
printf("QsoWaitForIOCompletion() or QsoStartSend() failed.\n");
perror("QsoWaitForIOCompletion() or QsoStartSend() failed");
return __VOID(Failure);
}
}
close(clientfd);
return __VOID(Success);
} /* end workerThread */</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="asynchi0.htm" title="Asynchronous I/O APIs provide a method for threaded client server models to perform highly concurrent and memory efficient I/O.">Asynchronous I/O</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="xcodesigns.htm" title="There are a number of ways that you can design a connection-oriented socket server on the iSeries. These example programs can be used to create your own connection-oriented designs.">Examples: Connection-oriented designs</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><a href="xsignals.htm" title="Signals allow you to be notified when a process or application becomes blocked.">Example: Use signals with blocking socket APIs</a></div>
</div>
<div class="relinfo"><strong>Related information</strong><br />
<div><a href="../apis/createiocompletionport.htm">QsoCreateIOCompletionPort()</a></div>
<div><a href="../apis/users_14.htm">pthread_create</a></div>
<div><a href="../apis/waitforiocompletion.htm">QsoWaitForIoCompletionPort()</a></div>
<div><a href="../apis/startrecv.htm">QsoStartRecv()</a></div>
<div><a href="../apis/startaccept.htm">QsoStartAccept()</a></div>
<div><a href="../apis/startsend.htm">QsoStartSend()</a></div>
<div><a href="../apis/destroyiocompletionport.htm">QsoDestroyIOCompletionPort()</a></div>
</div>
</div>
</body>
</html>