1 Detailed completion port basic use
1 Creating the completion port
HANDLE IOCP = CreateIoCompletionPort (invalid_handle_value,null,0,0);
The parameter is actually -1,0,0,0. The last parameter represents the
NumberOfConcurrentThreads, which is the number of threads that allow the app to execute concurrently,
The future avoids context switching, which means that only one thread per CPU is allowed, set to 0
Is how many processors there are, and how many are working threads.
The reason is if a machine has two CPUs (two cores), if you let the system run simultaneously
Thread, more than the number of native CPUs, it makes no sense to waste CPU precious cycles,
Reduce efficiency, not worth the candle.
A handle is then returned as long as it is not null and the completion port is established successfully.
2 Create socket bindings listen, not much.
socket lo_sock = invalid_socket;//creation failed if (iocp == null) {goto failed;} Create a thread IOCP into the thread function H_threads = createthread (null, 0, serverthread, ( LPVOID) iocp, 0, 0);// Prevent memory leaks closehandle (h_threads);//end//Create Socketlo_sock = socket (AF _inet,sock_stream,0);if (lo_sock == invalid_socket) {goto failed;} Struct sockaddr_in addr;memset (&addr, 0, sizeof (addr)); addr.sin_addr.s_addr =  INET_ADDR ("127.0.0.1"); Addr.sin_port = htons (port); addr.sin_family = af_inet;int ret = bind (lo_sock, (const struct sockaddr*) &addr, sizeof (addr)); (ret != 0) {printf ("bind %s:%d error \n", "127.0.0.1", port); goto failed;} printf ("bind %s:%d success \n", "127.0.0.1", port);p rintf ("Starting listener on %d\n ", port);// SOMAXCONN  Specify the maximum queue length by listen Ret = listen (lo_sock, somaxconn);if (ret != 0) {printf (" Listening on port failed\n "); goto failed;} printf ("listening on success\n");
3 listen for accept in main thread
struct sockaddr_in c_addr;int len = sizeof (c_ Addr)///No client access, thread hangs blocking int client_fd = accept (lo_sock, (struct sockaddr*) &c_addr, &len);if (client_fd != invalid_socket) { //here is a new socket connected to printf ("new client %s:%d coming\n", Inet_ntoa (C_ADDR.SIN_ADDR), ntohs (C_addr.sin_port)); } else {continue;} Save session Information struct session* s = save_session (Client_fd, inet_ntoa (c_addr.sin_ Addr), ntohs (C_addr.sin_port)); Save the information in a structure that stores the user's ip port port The structure is like this:/* This structure defines the STRUCT  SESSION{CHAR C_IP[32]; //IP address int c_port; //Port int c_ Sock; //socket handle int removed;//Delete tag struct session * _next; //linked list pointer};*/
4 then bind the acquired client socket to the IOCP
This code is performed in a while (1) dead loop
Let's introduce this function and create a completion port with an API
Handle winapi createiocompletionport (__in handle filehandle, // This is where the customer is connected socket__in_opt handle existingcompletionport,//is the completion port created earlier,__in ulong_prt completionkey,//This parameter can be passed a struct, a custom structure body //you just pass the structure in, the worker thread can take it out, // I'm using the structure I defined above _in dword dword numberofconcurrenthreads//said above, set to 0 on the line);//Add to this completion port CreateIoCompletionPort ((HANDLE) CLIENT_FD, IOCP, (DWORD) s, 0The;client_fd is the client socket above or IOCP the completion port, and s is the struct with the client session information
5 posting an asynchronous RECV request
(That is, tell the completion port if I have this client have the package over, you want to receive the completion, then tell me)
Before you do this, define a struct as a sign, because when you start, you deliver a lot of
I/O requests, to bind each I/O operation with a flag so that after the network operation is complete,
The data returned by this group are found in this flag:
Be sure to put wsaoverlapped first, other casual
Buffer size # max_recv_size 8092struct io_package{wsaoverlapped overlapped; Overlapped I/O network operation is to use this overlapping structure int opt; The type of the token request int pkg_size; The length of the package wsabuf Wsabuffer; A buffer that stores data that is used to pass data to overlapping operations char Pkg[max_recv_size]; The buffer};//listener event corresponding to the WSABUF is used to mark the type of request Enum{iocp_accept = 0,iocp_recv,iocp_write,};
WSARecv function
int WSARecv (socket s,//is of course the socket for this operation Lpwsabuf Lpbuffers,//Receive buffer DWORD Dwbuffercount,//Array WSABUF structure Number, set to 1 Lpdword LPNUMBEROFBYTESRECVD,//If the receive operation is completed immediately, this returns the number of bytes received by the function call Lpdword lpflags,//set to 0 Lpwsaoverl apped lpoverlapped,//This socket corresponds to the overlapping structure lpCompletionRoutine//This parameter only the completion of the routine mode will be used,) Wsa_io_pending: The most common return value, stating that the WSA Recv succeeded, but I/O operation was not completed
Post this request
struct io_package* io_data = malloc (sizeof (struct io_package))//only need to be emptied once, so that the overlapping structure can be emptied memset (io_data, 0, sizeof ( struct io_package)); io_data->wsabuffer.buf = Io_data->pkg;io_data->wsabuffer.len = Max_recv_size-1;io_ data->opt = IOCP_RECV; Mark request type we set to receive DWORD DwFlags = 0;//..... WSARecv (CLIENT_FD, &io_data->wsabuffer, 1, Null,&dwflags, &io_data->overlapped, NULL);
5 Waiting for the completion event in the worker thread
GetQueuedCompletionStatus function prototype, is the work thread to
Using the API, once he enters, the worker thread will be suspended, knowing
The completed event appears on the completion port. or network timeout
Then this thread will be awakened immediately, executing subsequent code
BOOL WINAPI getqueuedcompletionstatus (__in HANDLE completionport,//This is the only completion port we've built. __out Lpdword Lpnumberofbytes,//This is the number of bytes returned after the operation is completed __out pulong_ptr lpCompletionKey,//This is the custom struct parameter that is bound when the port is set to complete __out Lpoverl apped *lpoverlapped,//This is the overlapping structure that is established together when the socket is connected __in DWORD dwmilliseconds//waits for the completion port timeout, Wsa_inf Inite is to wait for an event before returning
Take a look at this code operation
Thread function Static dword winapi serverthread (lpvoid lparam) {//Get completion port handle iocp = (HANDLE) lparam;//the number of bytes returned dword dwtrans;//the struct with the socket handle because it was previously added This function can be removed struct session* s;//structure with overlapping structure struct io_package* io_data;//wait for iocpwhile (1) { s = null;dwtrans = 0;io_data = null;//calls this api wait event int ret = getqueuedcompletionstatus (iocp, &dwtrans, (Lpdword) &s, (lpoverlapped*) &io_ Data, wsa_infinite);if (ret == 0) {printf ("iocp error");//IOCP port error continue;} To tell all users that the socket completion event occurred with printf ("iocp have event\n");//Bytes received ==0 indicate client disconnects if (dwtrans == 0) {//socket closed closesocket (s->c_sock); //Release Memory free (io_data); continue;} Here means the data as well as read to//Here is the event type switch (io_data->opt) {case iocp_recv:{ // received the data and completed the io_data->pkg[dwtrans] = 0;printf ("iocp %d: recv %d,%s\n ", s->c_port,dwtrans,io_data->pkg);//When a read request is completed, must post a read request again dword dwflags = 0;int RET = WSARECV (S->c_sock, &io_data->wsabuffer, 1, null, &dwflags, &io_data->overlapped, null);} Break;case iocp_write:{}break;case iocp_accept:{}break;default:break;}} return 0;}
In fact, we have finished the use of this IOCP, which will be added later.
Windows completion port IOCP Model (ii)