Introduction
The basic idea of port completion is very similar to the DMA in the computer composition principle. The customer calls the overlap operation to throw a read/write request and waits for the completion of the port in the worker thread, the customer performs subsequent read/write operations based on the returned values. After the user throws an asynchronous read/write request, you can do other things.
1. define the structure of data stored in asynchronous requests
Enum io_operation {io_read = 1, io_send = 2, io_accept = 3,}; struct io_data {wsaoverlapped overlapped; // atomic lock DWORD dwlock; // time when data was last received, determine the inactive connection time DWORD dwentertick; // operation code io_operation opcode; // network socket handle socket activesocket; // network address DWORD dwipaddr; // port word wport; // request type char creqtype; // proxy_http; proxy_none; // buffer wsabuf; // Number of Io bytes processed DWORD dwrecved; // total number of buffer bytes DWORD dwrecvbuftail; // The buffer char recvbuffer [max_buff_size] directed by wsabuf; // Number of Io bytes processed DWORD dwsent; // The total number of buffer bytes DWORD dwsendbuftail; // The buffer char sendbuffer [max_buff_size] pointed by wsabuf;};
2. initialize listen
Void listenthread (void * ARGs) {// init Winsock2 wsadata; zeromemory (& wsadata, sizeof (wsadata); int retval =-1; if (retval = wsastartup (makeword (2, 2), & wsadata ))! = 0) {putlog ("wsastartup failed: Reason code: % u \ n", retval); Return ;}{// init TLS index if (! Inittlsindex () return ;}{// create socket g_serversocket = wsasocket (af_inet, sock_stream, ipproto_tcp, null, 0, wsa_flag_overlapped); If (g_serversocket = invalid_socket) {putlog ("server socket creation failed: Reason code: % u \ n", wsagetlasterror (); Return ;}{// bind sockaddr_in service; service. sin_family = af_inet; service. sin_addr.s_addr = htonl (inaddr_any); service. sin_port = Hton S (phone_port); int retval = BIND (g_serversocket, (sockaddr *) & service, sizeof (Service); If (retval = socket_error) {putlog ("server soket bind failed: Reason code: % u \ n", wsagetlasterror (); Return ;}{// listen int retval = listen (g_serversocket, 100); If (retval = socket_error) {putlog ("server socket listen failed: Reason code: % u \ n", wsagetlasterror (); return ;} putlog ("server socket Listen at: % d \ n ", phone_port) ;}{// create iocp system_info sysinfo; zeromemory (& sysinfo, sizeof (system_info); getsysteminfo (& sysinfo ); g_threadcount = sysinfo. dwnumberofprocessors + 1; g_hiocp = createiocompletionport (invalid_handle_value, null, 0, g_threadcount); If (g_hiocp = NULL) {putlog ("createiocompletionport () failed: reason :: % u \ n ", getlasterror (); return;} If (createiocompletionp ORT (handle) g_serversocket, g_hiocp, 0, 0) = NULL) {putlog ("binding server socket to Io completion port failed: Reason code: % u \ n ", getlasterror (); Return ;}{// create worker threads for (DWORD dwthread = 0; dwthread <g_threadcount; dwthread ++) {handle hthread; DWORD dwthreadid; hthread = createthread (null, 0, workerthread, 0, 0, & dwthreadid); closehandle (hthread) ;}{// accept new Conne Ction // load the acceptex function into memory using wsaioctl. // The wsaioctl function is an extension of the ioctlsocket () // function that can use overlapped I/O. the function's 3rd // through 6th parameters are input and output buffers Where // we pass the pointer to our acceptex function. this is used // so that we can call the acceptex function directly, rather // than refer to the mswsock. Lib library. guid guidacceptex = signature; DWORD dwbytes = 0; int iresult = wsaioctl (g_serversocket, signature, & guidacceptex, sizeof (guidacceptex), & signature, sizeof (signature), & dwbytes, null, null); If (iresult = socket_error) {wprintf (L "wsaioctl failed with error: % u \ n", wsagetlasterror (); closesocket (g_serversocket); wsacleanup (); return ;}// Delivery accept operation Enum {nmaxacceptrequest = 1,}; io_data * piodata = new io_data [nmaxacceptrequest]; memset (piodata, 0, sizeof (io_data) * nmaxacceptrequest ); for (INT xreq = 0; xreq <nmaxacceptrequest; xreq ++) {If (! Postacceptrequest (piodata + xreq) break;} // end of Post accept }}
2, 3 shipping functions,
2. A delivery accept request
bool PostAcceptRequest(IO_DATA * pIoData){ DWORD dwBytes = 0; // Create an accepting socket SOCKET AcceptSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (AcceptSocket == INVALID_SOCKET) { PUTLOG("Create accept socket failed with error: %u\n" , WSAGetLastError()); return false; } // Empty our overlapped structure and accept connections. memset(&pIoData->Overlapped, 0, sizeof(pIoData->Overlapped)); pIoData->opCode = IO_ACCEPT; pIoData->activeSocket = AcceptSocket; BOOL bRetVal = g_lpfnAcceptEx(g_ServerSocket , AcceptSocket , pIoData->RecvBuffer , 0 //, sizeof(pIoData[nCocurrent].Buffer) // -((sizeof(sockaddr_in)+16)*2) , sizeof (sockaddr_in) + 16 , sizeof (sockaddr_in) + 16 , &dwBytes , &pIoData->Overlapped); if (bRetVal == FALSE && GetLastError() != ERROR_IO_PENDING) { PUTLOG("AcceptEx failed with error: %u\n" , WSAGetLastError()); closesocket(AcceptSocket); return false; } // associate if (NULL == (CreateIoCompletionPort((HANDLE) AcceptSocket , g_hIOCP , (u_long) 0 , 0))) { PUTLOG("CreateIoCompletionPort associate failed with error: %u\n" , GetLastError()); closesocket(AcceptSocket); return false; } return true;}
3. B throws a Recv request
bool PostRecvRequest(IO_DATA * const ioReq, SOCKET sockfd){ IO_DATA * data = ioReq; data->activeSocket = sockfd; ZeroMemory(&data->Overlapped,sizeof(data->Overlapped)); data->opCode = IO_OPERATION(IO_READ); data->wsabuf.buf = data->RecvBuffer + data->dwRecved; data->dwRecvBufTail = sizeof(data->RecvBuffer); data->wsabuf.len = data->dwRecvBufTail - data->dwRecved; DWORD dwRecvNumBytes=0; DWORD dwFlags=(MSG_PEEK & (~MSG_PEEK)); int nRet = WSARecv(data->activeSocket , &data->wsabuf , 1 , &dwRecvNumBytes , &dwFlags , &data->Overlapped , NULL); if(nRet == SOCKET_ERROR && (ERROR_IO_PENDING != WSAGetLastError())) { PUTLOG("WASRecv Failed::Reason Code:: %u\n" , WSAGetLastError()); return false; } return true;}
3. c throws a send request
bool PostSendRequest(IO_DATA * const ioReq, SOCKET sockfd){ IO_DATA * data = ioReq; data->activeSocket = sockfd; ZeroMemory(&data->Overlapped,sizeof(data->Overlapped)); data->opCode = IO_OPERATION(IO_SEND); data->wsabuf.buf = data->SendBuffer + data->dwSent; data->wsabuf.len = data->dwSendBufTail - data->dwSent; DWORD dwSendNumBytes=0; DWORD dwFlags=(MSG_PEEK & (~MSG_PEEK)); int nRet = WSASend(data->activeSocket , &data->wsabuf , 1 , &dwSendNumBytes , dwFlags , &data->Overlapped , NULL); if(nRet == SOCKET_ERROR && (ERROR_IO_PENDING != WSAGetLastError())) { PUTLOG("WSASend Failed::Reason Code:: %u\n" , WSAGetLastError()); return false; } return true;}
4. Working thread
DWORD winapi workerthread (lpvoid workthreadcontext) {for (;) {bool bsuccess = false; DWORD dwiosize = 0; void * lpcompletionkey = NULL; lpwsaoverlapped lpoverlapped = NULL; bsuccess = getqueuedcompletionstatus (g_hiocp, & dwiosize, (lpdword) & lpcompletionkey, (lpoverlapped *) & lpoverlapped, infinite); If (! Bsuccess) {putlog ("getqueuedcompletionstatus () failed: % u \ n", getlasterror ();} io_data * lpiocontext = (io_data *) lpoverlapped; // new socket connection up if (lpiocontext-> opcode = io_accept) // a read operation complete {// update the socket status int errorcode = setsockopt (lpiocontext-> activesocket, sol_socket, so_update_accept_context, (char *) & g_serversocket, sizeof (g_serversocket); // submit the Read Request io_data * Data = New io_data; If (data) {postrecvrequest (data, lpiocontext-> activesocket);} else {closesocket (data-> activesocket); data-> activesocket = invalid_socket; delete data;} // submit a new accept postacceptrequest (lpiocontext); continue;} If (dwiosize = 0) // socket closed? {Putlog ("client dis-connected. \ n "); closesocket (lpiocontext-> activesocket); lpiocontext-> activesocket = invalid_socket; continue;} // read completed if (lpiocontext-> opcode = io_read) {// reset the timeout lpiocontext-> dwentertick = gettickcount (); // accumulate the total length of the Request lpiocontext-> dwrecved + = dwiosize; bool isreqready = true; //// if the data packet has been read, /// start processing. // after processing, send the request ////... if (isreqready) {lpiocontext-> dwsent = 0; lpiocontext-> dwsendbuftail = 0; memcpy (lpiocontext-> sendbuffer + lpiocontext-> dwsendbuftail, "\ r \ n \ r \ nserverecho:", 16); lpiocontext-> protocol + = 16; memcpy (lpiocontext-> sendbuffer + lpiocontext-> dwsendbuftail, lpiocontext-> recvbuffer, lpiocontext-> dwrecved); lpiocontext-> signature + = lpiocontext-> dwrecved; memcpy (lpiocontext-> sendbuffer + lpiocontext-> signature, "\ r \ n ", 4); lpiocontext-> dwsendbuftail + = 4; postsendrequest (lpiocontext, lpiocontext-> activesocket );} //// if the read is not completed // continue shipping the Read Request ////... else {postrecvrequest (lpiocontext, lpiocontext-> activesocket);} continue;} // If (lpiocontext-> opcode = io_send) {// reset timeout lpiocontext-> dwentertick = gettickcount (); lpiocontext-> dwsent + = dwiosize; bool isrespready = (lpiocontext-> dwsent = lpiocontext-> timeout ); //// if the data packet is sent, // after the call is started, // after the request is sent, the read request is sent ////... if (isrespready) {lpiocontext-> dwrecved = 0; lpiocontext-> Signature = sizeof (lpiocontext-> recvbuffer); postrecvrequest (lpiocontext, lpiocontext-> activesocket );} //// if the request is not sent, /// send another request ////... else {postsendrequest (lpiocontext, lpiocontext-> activesocket) ;}continue ;}} return 0 ;}
5. Start with a main program to see the effect.
int main(int argc, char * argv []){ ListenThread(NULL); PUTLOG("Press any key to quit server."); getchar(); return 0;}
Output:
========================================================== ==================================
Download project files:
Http://hi.csdn.net/attachment/201112/26/0_1324859981Zd6C.gif