• Aucun résultat trouvé

The Overlapped Model

Dans le document Copyright © 2002 by Microsoft Corporation (Page 149-156)

// Process FD_WRITE notification

if (NetworkEvents.lNetworkEvents & FD_WRITE) {

The WSAEventSelect model offers several advantages. It is conceptually simple and it does not require a windowed environment. The only drawback is its limitation of waiting on only 64 events at a time, which necessitates managing a thread pool when dealing with many sockets. Also, because many threads are required to handle a large number of socket connections, this model does not scale as well as the overlapped models discussed next.

The Overlapped Model

The overlapped I/O model in Winsock offers applications better system performance than any of the I/O models explained so far. The overlapped model's basic design allows your application to post one or more asynchronous I/O requests at a time using an overlapped data structure. At a later point, the application can service the submitted requests after they have completed. This model is available on all Windows platforms except Windows CE. The model's overall design is based on the Windows overlapped I/O mechanisms available for performing I/O operations on devices using the ReadFile and WriteFile functions.

Originally, the Winsock overlapped I/O model was available only to Winsock 1.1 applications running on Windows NT. Applications could take advantage of the model by calling ReadFile and WriteFile on a socket handle and specifying an overlapped structure. Since the release of Winsock 2, overlapped I/O has been incorporated into new Winsock functions, such as WSASend and WSARecv. As a result, the overlapped I/O model is now available on all Windows platforms that feature Winsock 2.

With the release of Winsock 2, overlapped I/O can still be used with the functions ReadFile and WriteFile under Windows NT and Windows 2000. However, this functionality was not added to Windows 95, Windows 98, and Windows Me. For compatibility across platforms, you should always consider using the WSARecv and WSASend functions instead of the Windows ReadFile and WriteFile functions. This section will only describe how to use overlapped I/O through the Winsock 2 functions.

To use the overlapped I/O model on a socket, you must first create a socket that has the overlapped flag set. See Chapter 2 for more information on creating overlapped enabled sockets.

After you successfully create a socket and bind it to a local interface, overlapped I/O operations can commence by calling the Winsock functions listed below and specifying an optional

WSAOVERLAPPED structure.

WSASend WSASendTo WSARecv WSARecvFrom WSAIoctl WSARecvMsg AcceptEx ConnectEx TransmitFile TransmitPackets DisconnectEx

WSANSPIoctl

To use overlapped I/O, each function takes a WSAOVERLAPPED structure as a parameter. When these functions are called with a WSAOVERLAPPED structure, they complete

immediately—regardless of the socket's mode (described at the beginning of this chapter). They rely on the WSAOVERLAPPED structure to manage the completion of an I/O request. There are

essentially two methods for managing the completion of an overlapped I/O request: your application can wait for event object notification or it can process completed requests through completion routines. The first six functions in the list have another parameter in common: a

WSAOVERLAPPED_COMPLETION_ROUTINE. This parameter is an optional pointer to a completion routine function that gets called when an overlapped request completes. We will explore the event notification method next. Later in this chapter, you will learn how to use optional completion routines instead of events to process completed overlapped requests.

Event Notification

The event notification method of overlapped I/O requires associating Windows event objects with WSAOVERLAPPED structures. When I/O calls such as WSASend and WSARecv are made using a WSAOVERLAPPED structure, they return immediately. Typically, you will find that these I/O calls fail with the return value SOCKET_ERROR and that WSAGetLastError reports a WSA_IO_PENDING error status. This error status simply means that the I/O operation is in progress. At a later time, your application will need to determine when an overlapped I/O request completes by waiting on the event object associated with the WSAOVERLAPPED structure. The WSAOVERLAPPED structure provides the communication medium between the initiation of an overlapped I/O request and its subsequent completion, and is defined as

The Internal, InternalHigh, Offset, and OffsetHigh fields are all used internally by the system and an application should not manipulate or directly use them. The hEvent field, on the other hand, allows an application to associate an event object handle with this operation.

When an overlapped I/O request finally completes, your application is responsible for retrieving the overlapped results. In the event notification method, Winsock will change the event-signaling state of an event object that is associated with a WSAOVERLAPPED structure from non-signaled to signaled when an overlapped request finally completes. Because an event object is assigned to the

WSAOVERLAPPED structure, you can easily determine when an overlapped I/O call completes by calling the WSAWaitForMultipleEvents function, which we also described in the WSAEventSelect I/O

model. WSAWaitForMultipleEvents waits a specified amount of time for one or more event objects to become signaled. We can't stress this point enough: remember that WSAWaitForMultipleEvents is capable of waiting on only 64 event objects at a time. Once you determine which overlapped request has completed, you need to determine the success or failure of the overlapped call by calling

WSAGetOverlappedResult, which is defined as BOOL WSAGetOverlappedResult(

SOCKET s,

LPWSAOVERLAPPED lpOverlapped, LPDWORD lpcbTransfer,

BOOL fWait,

LPDWORD lpdwFlags );

The s parameter identifies the socket that was specified when the overlapped operation was started.

The lpOverlapped parameter is a pointer to the WSAOVERLAPPED structure that was specified when the overlapped operation was started. The lpcbTransfer parameter is a pointer to a DWORD variable that receives the number of bytes that were actually transferred by an overlapped send or receive operation. The fWait parameter determines whether the function should wait for a pending overlapped operation to complete. If fWait is TRUE, the function does not return until the operation has been completed. If fWait is FALSE and the operation is still pending, WSAGetOverlappedResult returns FALSE with the error WSA_IO_INCOMPLETE. Because in our case we waited on a signaled event for overlapped completion, this parameter has no effect. The final parameter, lpdwFlags, is a pointer to a DWORD that will receive resulting flags if the originating overlapped call was made with the WSARecv or the WSARecvFrom function.

If the WSAGetOverlappedResult function succeeds, the return value is TRUE. This means that your overlapped operation has completed successfully and that the value pointed to by lpcbTransfer has been updated. If the return value is FALSE, one of the following statements is true:

The overlapped I/O operation is still pending (as we previously described).

The overlapped operation completed, but with errors.

The overlapped operation's completion status could not be determined because of errors in one or more of the parameters supplied to WSAGetOverlappedResult.

Upon failure, the value pointed to by lpcbTransfer will not be updated, and your application should call the WSAGetLastError function to determine the cause of the failure.

The following sample of code demonstrates how to structure a simple server application that is capable of managing overlapped I/O on one socket using the event notification described above.

#define DATA_BUFSIZE 4096 void main(void)

{

WSABUF DataBuf;

char buffer[DATA_BUFSIZE];

DWORD EventTotal = 0, RecvBytes=0, Flags=0;

WSAEVENT EventArray[WSA_MAXIMUM_WAIT_EVENTS];

WSAOVERLAPPED AcceptOverlapped;

SOCKET ListenSocket, AcceptSocket;

// Step 1:

// Start Winsock and set up a listening socket ...

// Step 2:

// Accept an inbound connection

AcceptSocket = accept(ListenSocket, NULL, NULL);

// Step 3:

// Set up an overlapped structure

EventArray[EventTotal] = WSACreateEvent();

ZeroMemory(&AcceptOverlapped, sizeof(WSAOVERLAPPED));

AcceptOverlapped.hEvent = EventArray[EventTotal];

DataBuf.len = DATA_BUFSIZE;

DataBuf.buf = buffer;

EventTotal++;

// Step 4:

// Post a WSARecv request to begin receiving data // on the socket

if (WSARecv(AcceptSocket, &DataBuf, 1, &RecvBytes, &Flags, &AcceptOverlapped, NULL) == SOCKET_ERROR) {

if (WSAGetLastError() != WSA_IO_PENDING) {

// Error occurred }

}

// Process overlapped receives on the socket while(TRUE)

{

DWORD Index;

// Step 5:

// Wait for the overlapped I/O call to complete Index = WSAWaitForMultipleEvents(EventTotal, EventArray, FALSE, WSA_INFINITE, FALSE);

WSAGetOverlappedResult(AcceptSocket, &AcceptOverlapped, &BytesTransferred,

ZeroMemory(&AcceptOverlapped, sizeof(WSAOVERLAPPED));

AcceptOverlapped.hEvent = EventArray[Index - WSA_WAIT_EVENT_0];

DataBuf.len = DATA_BUFSIZE;

DataBuf.buf = buffer;

if (WSARecv(AcceptSocket, &DataBuf, 1,

The application outlines the following programming steps:

Create a socket and begin listening for a connection on a specified port.

1.

Accept an inbound connection.

2.

Create a WSAOVERLAPPED structure for the accepted socket and assign an event object handle to the structure. Also assign the event object handle to an event array to be used later by the WSAWaitForMultipleEvents function.

3.

Post an asynchronous WSARecv request on the socket by specifying the WSAOVERLAPPED structure as a parameter.

4.

Call WSAWaitForMultipleEvents using the event array and wait for the event associated with the overlapped call to become signaled.

5.

Determine the return status of the overlapped call by using WSA-GetOverlappedResult.

6.

Reset the event object by using WSAResetEvent with the event array and process the completed overlapped request.

7.

Post another overlapped WSARecv request on the socket.

8.

Repeat steps 5–8.

9.

This example can easily be expanded to handle more than one socket by moving the overlapped I/O processing portion of the code to a separate thread and allowing the main application thread to service additional connection requests.

If a Winsock function is called in an overlapped fashion (either by specifying an event within the WSAOVERLAPPED structure or with a completion routine), the operation might complete immediately. For example, calling WSARecv when data has already been received and buffered causes WSARecv to return NO_ERROR. If any overlapped function fails with WSA_IO_PENDING or immediately succeeds, the completion event will always be signaled and the completion routine will be scheduled to run (if

specified). For overlapped I/O with a completion port, this means that completion notification will be posted to the completion port for servicing.

Dans le document Copyright © 2002 by Microsoft Corporation (Page 149-156)