Of course, the model of the TCP mode has an event selection model. That is to quote all online events and events defined in our programs. This has its benefit, which may allow us to better write a thread to manage reception and send. Now let's talk about a complete port model.
Completing a completion port is actually a notification queue that places a notification of the completed overlapping I / O request from the operating system. When an I / O operation is completed, a notification will be received by a worker thread that can process the results of the operation. After the socket is created, you can associate with a completed port at any time. Step: 1. Create an empty completion port; 2. Get the number of CPUs of the local machine; TCP listening to Socket, use event bonding, create listening threads; 5. When someone is connected, save the Client Socket to a key key we define itself, and associate it with the completed port of our creation; 6, use WSARECV and WSasend functions deliver some requests, which use overlapping I / O methods; 7, repeat 5 ~ 6;
Note: 1. In the manner of overlapping I / O, when receiving the data packet, be sure to deliver the request. This is the characteristics of their architecture. This is the characteristics of this architecture. The completion port uses some models in the system, so we only need to follow The order of call can be completed. 3. Completion port is used in this case, when there are thousands of users, it guarantees that performance is not reduced.
#include
#define port 5150 # Define data_bufsize 8192
// Key Typedef struct {overlapped overlapped; wsabuf data_buf; dword bytessend; dword bytessend; dword bytesrecv;} per_io_operation_data, * lpper_io_operation_data;
Typedef struct {socket;} per_handle_data, * lpper_handle_data;
DWORD WINAPI ServerWorkerthread (LPVOID CompletionPortID);
void main (void) {SOCKADDR_IN InternetAddr; SOCKET Listen; SOCKET Accept; HANDLE CompletionPort; SYSTEM_INFO SystemInfo; LPPER_HANDLE_DATA PerHandleData; LPPER_IO_OPERATION_DATA PerIoData; int i; DWORD RecvBytes; DWORD Flags; DWORD ThreadID; WSADATA wsaData; DWORD Ret;
IF ((RET = WSASTARTUP (0x0202, & WSADATA))! = 0) {Printf ("WsaStartup Failed with Error% D / N", RET); Return;}
// Open an empty completion port
if ((CompletionPort = CreateIoCompletionPort (INVALID_HANDLE_VALUE, NULL, 0, 0)) == NULL) {printf ( "CreateIoCompletionPort failed with error:% d / n", GetLastError ()); return;} // Determine how many processors are On the system.
GetSystemInfo (& SystemInfo);
/ / Turn on 2 times the number of CPUs
For (i = 0; i // Create a Server Worker Thread and pass the completion port to the thread. IF ((ThreadHandle = Createthread, Completionport, 0, & threadID) == null) {Printf ("CreateThread () Faled with Error% D / N", getLastError ()); return;} // close the thread handle closehandle (threadhandle); // Open a server socket IF ((listen = wsasocket (AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED) == Invalid_socket) {Printf ("Wsasocket () failed with error% d / n", wsagetlasterror ()); return;} InternetAddr.sin_Family = AF_INET; Internetddr.sin_addr.s_addr = HTONL (INADDR_Any); Internetddr.SIN_PORT = HTONS (port); IF (Bind (Listen, (PSockAddr) == SOCKET_ERROR) {Printf ("Bind () failed with error (); wsagetlasterror (); return;} IF (Listen, 5) == Socket_ERROR) {Printf ("Listen () failed with error% d / n", wsagetlasterror (); return;} // Start receiving the connection from the client While (True) {IF ((Accept = WSAACCEPT (Listen, NULL, NULL, NULL, 0) == SOCKET_ERROR) {Printf ("WsaAccept () failed with error% d / n", wsagetlasterror (); return; } // Create a key entry for saving this client information, user receives the overlapping structure of the transmitted, // also uses the buffer IF ((PerhandaTa = (LPPer_Handle_Data) GlobalLoc (GPTR, SIZEOF (per_handle_data)) == NULL) {Printf ("GlobalAlloc () Failed with Error% D / N", getLastError ()); return;} // Associate The Accept Socket with The Original Completion Port. Printf ("Socket Number% D Connected / N", Accept; PerhandaTa-> Socket = Accept; / / Associate with our completion port to associate key items with a specified completion port association IF (Createiocompletionport, CompletionPort, (DWORD) PerhandaTa, 0) == null) {printf (" Createiocompletionport Failed with error% D / N ", getLastError ()); return;} // Delivery to receive it, because this function needs to be used to deliver a receive preparation IF (((LPPER_IO_OPERATION_DATA) GlobalAlloc (GPTR, SIZEOF (Per_io_operation_data)) == NULL) {Printf ("GlobalAlloc () Failed With Error% D / N", getLastError ()); return;} ZeroMemory (& (PerIoData-> Overlapped), sizeof (OVERLAPPED)); PerIoData-> BytesSEND = 0; PerIoData-> BytesRECV = 0; PerIoData-> DataBuf.len = DATA_BUFSIZE; PerIoData-> DataBuf.buf = PerIoData-> Buffer ; Flags = 0; if (WSARecv (Accept, & (PerIoData-> DataBuf), 1, & RecvBytes, & Flags, & (PerIoData-> Overlapped), NULL) == SOCKET_ERROR) {if (! WSAGetLastError () = ERROR_IO_PENDING) {printf ( "WSARecv () failed with error% d / n", WSAGetLastError ()); return;}}}} // worker threads DWORD WINAPI ServerWorkerThread (LPVOID CompletionPortID) {HANDLE CompletionPort = (HANDLE) CompletionPortID; DWORD BytesTransferred; LPOVERLAPPED Overlapped ; LPPER_HANDLE_DATA PerHandleData; LPPER_IO_OPERATION_DATA PerIoData; DWORD SendBytes, RecvBytes; DWORD Flags; while (TRUE) {// completion port news come if (GetQueuedCompletionStatus (CompletionPort, & BytesTransferred, (LPDWORD) & PerHandleData, (LPOVERLAPPED *) & PerIoData, INFINITE) = = 0) {Printf ("getqueuedcompletionStatus failed with error% d / n", getLastError ()); return 0;} // Is there anyone quit? IF (Bytestransferred == 0) {Printf ("Closing Socket% D / N", PerhandaTa-> Socket; IF (CloseData-> Socket) == SOCKET_ERROR) {Printf ("CloseSocket () Failed with Error% D / N", WsageTlasterror (); Return 0;} GlobalFree (Perhandata); GlobalFree (PERIODATA); Continue;} // IF (Periodata-> BYTESRECV == 0) {PERIODATA-> BYTESRECV = bytestransferred; periodata-> Bytessend = 0;} else {periodata-> bytessend = bytestransferred;} IF (Periodata-> BytesRecv> Periodata-> Bytessend) { // Post another WSASend () request. // Since WSASend () is not gauranteed to send all of the bytes requested, // continue posting WSASend () calls until all received bytes are sent.ZeroMemory (& (PerIoData-> Overlapped) , SizeOf (overlapped); PERIODATA-> DATABUF.BUF = Periodata-> Buffer Periodata-> BYTESSEND; Periodata-> DATABUF.LEN = Periodata-> Bytessend; IF (Wsasend (Perhandata-> Socket, & (Periodata-> DataBuf), 1, & SendBytes, 0, & (Periodata-> Overlapped), NULL) == SOCKET_ERROR) {IF (Wsagetlasterror ()! = error_io_pending) {Printf "Wsasend () failed with error% d / n", wsagetlasterror ()); return 0;}}} else}}}} else}}}} else}}}} else}}} else}}} else}}} Else}}}} else} // Now That there is no more bytes to send post another wsarecv () Request. Flags = 0; ZeromeMory (& (Periodata-> overlapped), sizeof (overlapped); PERIODATA-> DATABUF.LEN = DATA_BUFSIZE; Periodata-> DATABUF.BUF = Periodata-> Buffer; if (WSARecv (PerHandleData-> Socket, & (PerIoData-> DataBuf), 1, & RecvBytes, & Flags, & (PerIoData-> Overlapped), NULL) == SOCKET_ERROR) {if (WSAGetLastError ()! = ERROR_IO_PENDING) {printf ( "Wsarecv () failed with error% d / n", wsagetlasterror ()); return 0;}}}}}