Reading Notes for Windows network and communication programming-IOCP and scalable network programs

Source: Internet
Author: User

Complete the port I/O model

The I/O completion port is a mechanism by which the application uses the thread pool to process I/O requests. When processing multiple concurrent asynchronous I/O requests, using I/O to complete the port is faster and more effective than creating a thread in an I/O Request.

 

The CreateIoCompletionPort function is a bit complicated.

The CreateIoCompletionPort function has two functions.

1. Create a complete port object.

2. Associate one or more file handles (socket handles) with an I/O completion port object.

In step 2, the first three parameters must be used to associate the socket handle for the port.

Filehandle
Socket handle to be associated

ExistingCompletion the port object handle that has been created

CompletionKey
Specify the unique (per-handle) data of a handle,It is associated with the FIleHandle socket handle. An application can store any type of information here, usually a pointer.

The CompletionKey parameter is usually used to describe socket-related information, so it is called the unique (per = handle) data of the handle.

 

After associating a socket handle to a port, you can send overlapping messages and receive requests to process I/O. When these I/O operations are completed, the I/O system will send a complete notification packet to the completed port object. The I/O completion port is queued for these packets in an advanced way. Applications can use the GetQueuedCompletionSatus function to obtain packets in these queues. This function should be called in the service thread that handles the completed port object I/O.

GetQueuedCompletionStatus (HANDLECompletionPort, // complete the port object handle LPDWORDlpNumberOfBytes // obtain the number of bytes transmitted during the I/O operation PULONG_PTRlpCompletionKey, // obtain the unique data (pointer) of the handle specified when associating the socket) LPOVERLAPPED * lpOverlapped, // specify the OVERLAPPED structure DWORD dwMilliseconds when the shipping I/O operation is obtained // If the completion port does not complete the packet, this parameter specifies the waiting event, INFINIE is infinite)

The I/O service thread calls the GetQueuedCompletionStatus function to obtain information about the socket where an event occurs. The number of bytes transmitted is obtained through the lpNumberOfBytes parameter,The lpCompletionKey parameter is used to obtain the unique (per-handle) data associated with the socket. The lpOverlapped parameter is used to obtain the overlapping object address used for shipping I/O requests, further obtain the unique I/O (per-I/O) data.

The lpCompletionKey parameter contains data called per-Handle, because this data is associated with a socket Handle when the socket is first associated with the completion port. This is the CompletionKey parameter passed to the CreateIoCompletionPort function.

The lpOverlapped parameter points to an OVERLAPPED structure. The structure is followed by the data we call per-I/O. This can be any information the worker thread wants to know when processing packets.

 

I personally feel that the design of these two data structures is closely related to the overall design of the program.

 

A simple example of the specific programming process:

1. Create a complete port object and create one or more service threads. The service thread calls GetQueuedCompletionStatus to obtain the complete I/O notification information. The main thread receives the connection, associates the new socket with the completion port, and then ships the Read I/O asynchronous request on the new connection.

2. After the service thread returns from the GetQueuedCompletionStatus function, it processes the data according to the information in the per-handle I/O data and continues to deliver the next Read I/O asynchronous request.


# Define _ WIN32_WINNT 0x0400 # include <windows. h> # include <cstdio> # include "InitSocket. h "# define BUFFER_SIZE 2048 CInitSock initSock; // initialize typedefstruct _ PER_HANDLE_DATA/per-handle data {SOCKET s; // corresponding socket handle sockaddr_in addr; // client address} PER_HANDLE_DATA, * PPER_HANDLE_DATA; /*************************************** * *************** // contains the typedefstruct _ PER_IO_DATA // per-I/O data {OVERLAPPED ol; // overlapping structure, It must be placed as the first structure. It is better to use the C ++-derived method to char buf [BUFFER_SIZE]; // data buffer int nOperationType; // operation type # defineOP_READ 1 // operation type code # defineOP_WRITE 2 # defineOP_ACCEPT 3} PER_IO_DATA, * PPER_IO_DATA; /*************************************** *******************//******************* **************************************** * derived version class _ PER_IO_DATA: public OVERLAPPED {public: char buf [BUFFER_SIZE]; int nOperationType; # defineOP_READ 1 // Operation Type Code # defineOP_WRITE 2 # defineOP_ACCEPT 3}; typedef _ PER_IO_DATA; typedefPER_IO_DATA * PPER_IO_DATA; **************************************** * **********/dword winapi ServerThread (LPVOID lpParam ); int main (void) {int nPort = 4567; // create a finished port object. Create a working thread to process the event HANDLE hCompletion = CreateIoCompletionPort (INVALID_HANDLE_VALUE, 0) in the finished port object ); createThread (NULL, 0, ServerThread, (LPVOID) hCompletion, 0, 0 );/ /Create a listening SOCKET, bind it to the local address, and start listening to socket sListen = SOCKET (AF_INET, SOCK_STREAM, 0); SOCKADDR_IN si; si. sin_family = AF_INET; si. sin_port = ntohs (nPort); si. sin_addr.s_addr = INADDR_ANY; bind (sListen, (sockaddr *) & si, sizeof (si); listen (sListen, 5); // cyclically process incoming connections while (TRUE) {// wait for accepting the pending connection request SOCKADDR_IN saRemote; int nRemoteLen = sizeof (saRemote); SOCKET sNew = accept (sListen, (sockaddr *) & saRemote, & nRemoteLen ); // After receiving the new connection Create a per-handle data and associate them with the completion port object PPER_HANDLE_DATA pPerHandle = (PPER_HANDLE_DATA) GlobalAlloc (GPTR, sizeof (PER_HANDLE_DATA); pPerHandle-> s = sNew; memcpy (& pPerHandle-> addr, & saRemote, nRemoteLen); CreateIoCompletionPort (HANDLE) pPerHandle-> s, hCompletion, (DWORD) pPerHandle, 0); // Association, not created. during transformation, the pointer is converted to DWORD. The only data associated with pPerHandle-> s is PerHandle // deliver a receiving request PPER_IO_DATA pPerIO = (PPER_IO_DATA) GlobalAlloc (GPTR, sizeof (PER_IO_DATA); pPerIO-> nOperationType = OP_READ; WSABUF buf; buf. buf = pPerIO-> buf; buf. len = BUFFER_SIZE; DWORD dwRecv; DWORD dwFlags = 0; // receives the request as an introduction, causing receiving operations. // OVERLAPPED structure related to the socket WSARecv (pPerHandle-> s, & buf, 1, & dwRecv, & dwFlags, & pPerIO-> ol, NULL);} return 0 ;}// service thread dword winapi ServerThread (LPVOID lpParam) {// get the finished port object HANDLE 'handle hCompletion = (HANDLE) lpParam; DWORD dwTrans; PPER_HANDLE_DATA pPerHandle; PPER_IO_DATA pPerIO; while (TRUE) {// wait for I/O to be completed on all sockets associated with the completion port, the penultimate parameter is actually very inappropriate BOOL bOK = GetQueuedCompletionStatus (hCompletion, & dwTrans, (LPDWORD) & pPerHandle, (LPOVERLAPPED *) & pPerIO, WSA_INFINITE ); if (! BOK) // an error occurs on this socket {closesocket (pPerHandle-> s); GlobalFree (pPerHandle); GlobalFree (pPerIO); continue ;} // if the socket is disabled by the other party (dwTrans = 0 & (pPerIO-> nOperationType = OP_READ | pPerIO-> nOperationType = OP_WRITE )) {closesocket (pPerHandle-> s); GlobalFree (pPerHandle); GlobalFree (pPerIO); continue;} switch (pPerIO-> nOperationType) // use the nOperationType field in the per-I/O data to check what I/O requests have completed {case OP_READ: // complete a receiving request {pPerIO-> buf [dwTrans] = '\ 0'; printf (pPerIO-> buf); // continue shipping and receive the I/O Request WSABUF buf; buf. buf = pPerIO-> buf; buf. len = BUFFER_SIZE; pPerIO-> nOperationType = OP_READ; DWORD nFlags = 0; WSARecv (pPerHandle-> s, & buf, 1, & dwTrans, & nFlags, & pPerIO-> ol, NULL); // continue to trigger the receiving operation on the socket // post a sending request I/O, I add it myself, in order to test OR_WRITE, PPER_IO_DATA pSendPerIO = (PPER_IO_DATA) globalAlloc (GPTR, sizeof (PER_IO_DATA); pSendPerIO-> nOperationType = OP_WRITE; memcpy (pSendPerIO-> buf, pPerIO-> buf, dwTrans); WSABUF dbuf; dbuf. buf = pSendPerIO-> buf; dbuf. len = dwTrans; // if it is greater than the client's receiving buffer, the client needs to repeat multiple times to receive all data WSASend (pPerHandle-> s, & dbuf, 1, & dwTrans, nFlags, & pSendPerIO-> ol, NULL); // The sending operation on the socket} break; case OP_WRITE: {printf ("data sending completed \ n ");} break; case OP_ACCEPT: // This is redundant, because the main thread has break;} return 0 ;}

For more information about the IOCP mechanism, please refer to another blog: Windows core programming 5th part of Reading Notes-Chapter 10th synchronous device I/O and asynchronous device I/O

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.