Self-study Winsocket I / O Methods
1. First, you need to know what is "socket model", what is "socket I / o models"? Socket Modes: DETERMINESHOW WINSOCK FUNCKET.SOCKET I / O Models: Describes How an Application Manages and Processes I / O On A Socket.2. So What kind of "Socket Modes" have provided programmers for programmers? A.Blocking Mode (non-blocking) 3. Detailed explanation Blocking and non-blocking. Our most commonly used Send and RECV two functions ... For example, you call the send function to send a certain Byte, in the system's internal Send works actually to transfer data transfer (COPY) to TCP / The Output buffer of the IP protocol stack, it does not mean that the data has been successfully sent. If the TCP / IP protocol stack does not have enough available buffers to save the data you Copy ... This time is reflected in this time The difference between blocking and non-blocking: The Socket Send function of the blocking mode will not return until the system buffer has enough space to return the data you want to send, and the Socket for blocking will be immediately Returns WSAEWOULDDBLOCK to tell the caller: "Send operation is blocked !!! You want to handle it ..." For the RECV function, the same truth, the internal work mechanism of this function is actually waiting for the TCP / IP protocol stack The area notifies it: Hey, your data is coming. For the Socket of the blocking mode, if the TCP / IP protocol stack receives the buffer that does not know a result to it, it has not returned: the system resource .... Socket this function will return immediately, then tell you: WSaewouldDblock.3. For blocking mode, don't I get it? Don't get it, and don't use me to judge the basic receipt / what Time to complete, more people? Yes, this prawn said the way the way the way is as follows: We divide the application into a Working Thread, two threads are synchronized Object (Synchronization Object, can be Event, Mutex ...) to share a data buffer, read thread (Read ING THREAD) is responsible for reading data from the network and placing it in a shared buffer, triggering an event, notifying / waking up working thread, notifying / waking up a working thread in an appropriate timing (such as receiving the data required by the reading thread). ), the following is a simple code of the character to achieve: CRITICAL_SECTION g_data; HANDLE g_hEvent; TCHAR g_szBuffer [MAX_BUFFER_SIZE]; int g_nBytes; void ReadThread (void) {int nTotle = nRead = nLeft = nBytes = 0; while (done) {nTotal! = 0; NLEFT = NUM_BYTES_REFT = NUM_BYTES_REQUIRED; / / To read how much bytes while (NTOTAL! = Num_Byte_Required) {// Because of thread and global variables, you need to use critical segments EntercriticalSECTION (& g_data); NREAD = Recv (SOCK, & (g_szbuffer [max_buffer_size] - nbytes), NLEFT); if (-1 ==
NREAD) {Printf ("socket% d error./n", wsagetlaserror ()); exitthread ();} ntotal = nread; nLEFT - = NREAD; NBYTES = NREAD; LeaveCriticalSelection (& g_data);} // From network WorkThread start notification SetEvent (g_hEvent) after completing reception of the specified (NUM_BYTES_REQUIRED) Bytes;}} void WorkThread (void) {WaitForSingleObject (g_hEvent); EnterCriticalSection (& g_data); // main processing ... DoSomeWorkOnData (g_szBuffer); g_nBytes - = Num_byte_required; LeavecriticalSelection;} This way is that the application is difficult to communicate very difficult to connect through multiple Socket communication. Of course, let's come back to each connected socket to open a Reading Thread. And Workthread, but this will bring great overhead, and the scalability is very poor. Imagine that if you build a server with such a model to open at least two threads ... Day .. If the business burden is large / How to do a lot of Socket ?? So don't think more ... This way is very uncomfortable to do server-side. (Note: The server I said refers to the S-terminal logic in C / S).
Interpret the most complex IOCP model in IO from the perspective of writing code
One of the following paragraphs is an example in Microsoft Win32 SDK. This is an echo server program: //// This will not be said, in order to use the header file that must be included in Winsock2 ... // # include
= NULL) {Printf ("CreateiocompletionPort Failed with Error:% D / N", getLastError ()); Return;} //// The following code is said to be: several CPUs on the machine running according to the server 2 * CPU number of thread.// This involves how many problems should be created by completing the port working thread, in the early stage (MSDN 2000) Microsoft said // is Workthreadnums = 2 * CPU 2, the current MSDN 2003 is Workthreadnums = 2 * CPU; // GetSystemInfo; for (i = 0; i } /// Receive a connection to New Socket and under the next reception / processing of the Socket connected to the SOCKET // Why don't you use new? I think it is because the memory management function provided by Windows, this If the memory is large, there is no abnormality in the case of lack of memory, how is it that the memory allocation failed ... // if ((Perhandata = (lpper_handle_data) GlobalLococ (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 connection / n ", accept; perhandata-> socket = accept; //// The Accept Socket and IO complete the port association / binding / binding, and passing the Accept Socket to the IOCP mechanism. // When calling getQueuedCompletionStatus You can get this value. Return;} // The following structure will also be passed to the working thread, how to pass? Note the red part of the following red ((PERIODATA = (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-> Database; periodata-> databuf.buf = periodata-> buffer; flags = 0; //// In Accept Socket IO request: wsarecv () to stimulate the IOCP working mechanism ../ Note the fifth parameters of WSARECV, that is, I tell WSAarecv at this time, not only // periodata-> Overlapped address is also the address of Periodata. ..//IF (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 // 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) {//// This function explains that the whole mechanism will also understand ... // First, we should see that CompletionPort should have no problem, which is passed from the main thread of the creation thread. // Bytestransferred indicates this IO How many bytes ... // perhandaTA is time to Createiocompletionport, the MSDN is called completionKey.//, please pay attention to this parameter, the explanation of MSDN is as follows: // "Pointer to a variable That Receives The Address of ADDRESS OF The overlapped structure That Was // Specified WHEN The Completed I / O Operation WAS Started. "Actually, the LPoverLapped is the overlapped address of the overlapped ... // This is understood: reputation overlapped by threads pass over a structure pointer ..: -) // if (GetQueuedCompletionStatus (CompletionPort, & BytesTransferred, (LPDWORD) & PerHandleData, (LPOVERLAPPED *) & PerIoData, INFINITE) == 0) {printf ( "GetQueuedCompletionStatus Failed with error% D / N ", getLastError ()); return 0;} ///first check to see if an erro r has occured on the socket and if so // then close the socket and cleanup the SOCKET_INFORMATION structure // associated with the socket.//if (BytesTransferred == 0) {printf ( "Closing socket% d / n", PerHandleData- > Socket); if (CloseData-> Socket) == SOCKET_ERROR) {Printf ("CloseSocket () failed with error% d / n", wsagetlasterror ()); return 0;} GlobalFree (Perhandata); globalfree ); continue;.} //// Check to see if the BytesRECV field equals zero If this is so, then // this means a WSARecv call just completed so update the BytesRECV field // with the BytesTransferred value from the completed WSARecv ( Call.//IF (periodata-> bytesRecv ==