Translation description:
Completing ports basically recognize that it is not difficult to understand and write programs in a Windows service platform. At present, I am in carrying out this kind of practice, the code has not fully debugged and evaluated, only this kind of learning translation, I am laughing.
Translation This article is because I have recently learned some of the Socket service programs to find (attention, just learning, I am in this area experience, I can write a word, I can write a word: P), if I don't force myself Take this article from the head translation, I doubt whether I can seriously lead the content of this article: PPP. Put this article, not to make popularity, but because the level is indeed limited, although the overall difference is different, but There may still have a lot of details and words on the details. It is hoped that everyone can point out the translation error and understanding, communicate and help each other. thank you very much.
This article has not been contemplated by the original author, only used to learn and exchange on the Internet, and the translation level is poor, so do not use commercial use.
vcbear
2001.8 Windows Sockets 2.0: Using Complete Port High Performance, Scalable Winsock Sergers
Author: Anthony Jones and Amol Deshpande
Original in http://msdn.microsoft.com/msdnmag/issues/1000/winsock/winsock.asp
APIS and scalability completion port (Completion ports) typical WORKER THREAD Structure Windows NTS Architecture Structure Buffer Buffers Manage Resource Constraints About Accept Connection TransmitFile and TransmitPackets Functions to implement a service solution
This article assumes that you are already familiar with Winsock API, TCP / IP, Win32 API
Summary: The difficulty of writing a general web application is "scalability" of the program. The technique of overlapping I / O using completion ports provides real scalability on WindowsNT and Windows2000. Complete port and Windows Socket 2.0 combination can develop a network service program that supports a large number of connected connections.
This article begins with the implementation of the server, and discusses how to handle system resource constraints and high requirements, and general problems that are encountered during extensible service procedural development.
-------------------------------------------------- ------------------------------
text:
Developing web programs is never an easy thing, although only some rules & # 0; create a socket, initiate a connection, accept connection, send and accept data. Really difficult is: let your program adapt to a few thousand connections from a single single. This article focuses on the server-side program of the C / S structure, because in general, develop a large capacity, scalable Winsock program generally refers to the service program. We will discuss the code based on WindowsNT4.0 and Windows 2000, not including Windows3.x (when something), because this property of Winsock2 is only valid on Windows NT4 and the latest version.
APIS and scalability
Win32 overlapping I / O (Overlapped I / O) mechanism allows you to initiate an action and then accept information after the operation is completed. For the operation that takes a long time to complete, the overlapping IO mechanism is especially useful, because the thread that initiates overlapping operations can be freely doing after the overlapping request is issued.
On WinNT and Win2000, the real scalable I / O model provided is the overlapping I / O using completion ports. It is also more likely to be compatible with UNIX, but it is difficult to implement us. "Scalability". Moreover, Windows's completion port mechanism has been optimized inside the operating system, providing higher efficiency. So, we choose the completion of the port to start our server program development.
Completion ports
In fact, you can see a queue that completes the port as system maintenance. The operating system is put into the event notification completed by the overlapping IO operation. Since it is an event notification that is exposed to the "Operation", it is named "Completion Port". ). After a socket is created, you can linked at any time and a completion port.
In general, an application can create multiple working threads to process notification events on the completion port. The number of working threads depends on the specific needs of the program. However, in the ideal case, a thread should be created corresponding to a CPU. Because in completing the ideal model, each thread can get a "atom" time slice from the system, running and check the completion of the port, and the handoff of thread is additional overhead. When actually developed, it is also considered whether these threads involve other plugging operations. If a thread is plugging, the system hangs it, allowing other threads to get running time. Therefore, if there is such a case, you can create more threads to use time to use time.
Application Complete port is divided into two steps:
1 Create a completed port handle:
Handle Hiocp; Hiocp = CreateiocompletionPort (Invalid_Handle_Value, NULL, (Ulong_PTR) 0, 0); if (Hiocp == Null) {// error}
Note that in the first parameter (FileHandle) Invalid_File_Handle, the second parameter is inciving NULL, and the system will create a new completion port handle, without any IO handle associated with it.
2. After completing the port creation, it is established between socket and completion ports. Create the CreateiocMpletionPort function again, this time the first parameter fileHandle is incorporated into the created Socket handle, the parameter existingCompletionPort is the completed port handle that has been created.
The following code created a socket and linked it with the completed port.
Socket S; S = Socket (AF_INET, SOCK_STREAM, 0); if (s == invalid_socket) {// Error IF (CREATEIOCOMPLET ((Handle) S, Hiocp, (Ulong_PTR) 0, 0) == NULL) {///// Error} ???}
SoCket has been successfully associated with this Socket. The overlapping IO operation results performed on this socket use the completion port to issue a notification. Note: The third parameter of the CreateiocompletionPort function allows developers to pass on a data member of Ulong_PTR, we call it a complex key, which can be designed to point to one structure containing socket information. The pointer is used to connect the relevant environmental information and socket. Each time the notification is completed, the environment information is also returned to the developer with the notice.
After completing the port creation and after association with the socket, create one or more working threads to handle the completion notification, each thread can cycle the getQueuedCompletionStatus function, check the notification event on the port. Before an example, we will discuss the process of overlapping the IO before a typical working thread. When a overlap IO is initiated, a pointer to an Overlapped structure is passed to the system as a parameter. When the operation is complete, getQueueCompletionStatus can return a pointer to the same Overlapp structure. To identify and locate this completed operation, developers are best defined their own overlapped structure to include additional information about the operation itself. such as:
Typedef struct _overlapped {Overlapped OL; Socket S, SCLIENT; INT OPCODE; WSABUF WBUF; DWORD DWBYTES, DWFLAGS; // Other useful information} OverlappedPlus;
The first member of this structure is the default Overlapped structure, second, three for local service sockets and customer SOCEKT related to this operation, the fourth member is an operation type, for Socket, now defined
#define op_read 0 #define op_write 1 #define op_accept 2
3 types. Then there is also the information of the application's Socket buffer, operational data, flag, and other developers who are considered useful.
When overlapping IO operation, the OverlappedPlus structure is performed as a parameter LPOVERLAPP passing (such as WSasend, WasRecv, etc.), and there is a lpoverlapped parameter, which requires a pointer to an overlapp structure)
When the operation is complete, the getQueuedCompletionStatus function returns an LPOVERLAPPED type pointer, which is actually pointing to the extension OverlappedPlus structure defined by the developer, including all the information that developers earlier.
Note: Overlapped members are not necessarily required to be a member of the OverlappedPlus extension structure. After obtaining the Overlapped pointer, you can use the Containing_Record macro to get a pointer to the corresponding extended structure.
Typical Worker Thread structure
DWORD WINAPI WorkerThread (LPVOID lpParam) {ULONG_PTR * PerHandleKey; OVERLAPPED * Overlap; OVERLAPPEDPLUS * OverlapPlus, * newolp; DWORD dwBytesXfered; while (1) {ret = GetQueuedCompletionStatus (hIocp, & dwBytesXfered, (PULONG_PTR) & PerHandleKey, & Overlap, INFINITE); if (ret == 0) {// Operation failed continue;} OverlapPlus = CONTAINING_RECORD (Overlap, OVERLAPPEDPLUS, ol); switch (OverlapPlus-> OpCode) {case OP_ACCEPT: // Client socket is contained in OverlapPlus.sclient // Add client to completion port CreateIoCompletionPort ((HANDLE) OverlapPlus-> sclient, hIocp, (ULONG_PTR) 0, 0);. // Need a new OVERLAPPEDPLUS structure // for the newly accepted socket Perhaps // keep a look aside list of free structures. newolp = AllocateOverlappedPlus (); if (! newolp) {// Error} newolp-> s = OverlapPlus-> sclient; newolp-> OpCode = OP_READ; // This function prepares the data to be sent PrepareSendBuffer (& newolp-> wbuf) RET = Wsasend (newolp-> s, & newolp-> wbuf, 1, & newolp-> dwbytes, 0, & newolp.ol, null); if (ret == SOCKET_ERROR) {if (! WSAGetLastError () = WSA_IO_PENDING) {// Error}} // Put structure in look aside list for later use FreeOverlappedPlus (OverlapPlus); // Signal accept thread to issue another AcceptEx SetEvent ( hAcceptThread); break; case OP_READ: // Process the data read // ??? // Repost the read if necessary, reusing the same // receive buffer as before memset (& OverlapPlus-> ol, 0, sizeof (OVERLAPPED)) ; ret = WSARecv (OverlapPlus-> s, & OverlapPlus-> wbuf, 1, & OverlapPlus-> dwBytes, & OverlapPlus-> dwFlags, & OverlapPlus-> ol, NULL);! if (ret == SOCKET_ERROR) {if (WSAGetLastError () =
WSA_IO_PENDING) {// error}} Break; Case op_write: // process the data SENT, ETC. BREAK;} // Switch} // while} // workerthread ---------------------------------------------------------------------------------------------------- -------------------------------------------------- ---------------- View the above code, note that if the overlapped operation failed (for example, returning socket_error or other non-WSA_IO_PENDING error), no completion notification time will be completed Port queue. Conversely, there must be a corresponding notification time to be placed in the completed port queue.
A more complete completion of Winsock's complete port mechanism, you can refer to Microsoft PlatformSDK of MSDN, where there is an example of completing the port. Visit http://msdn.microsoft.com/library/techart/msdn_servrapp.htm. You can get more information.
Sockets architecture for Windows NT and Windows 2000
Learn some WinNT and Win2000 basic Sockets architecture beneficial and understanding of scalability rules. The figure below shows the current version of WIN2000 WINSOCK implementation. Applications should not depend on some of the underlying details (referring to drivers, dlls), as these may be changed in future versions of the operating system.
Socket architecture
Winsock 2.0 specification supports multiple protocols and related support services. These user mode service support can expand their own features based on other existing service providers. For example, a proxy layer service support (LSP) can install yourself in the existing TCP / IP service top. In this way, the proxy service can take and redirect a call to the underlying function.
Unlike other operating systems, the WinNT and Win2000 transfer protocol layers do not directly provide the application to the Socket style interface, and do not accept direct access to the application. Instead, more general APIs are called Transport Driver Interface (TDI). These APIs separated the WinNT subsystem from a wide variety of network programming interfaces. Then, the Sockets method is provided (implemented in AFD.sys) through the Winsock kernel mode driver. This driver is responsible for connecting and buffering management, providing the application of the Socket style programming interface. AFD.SYS drives layer AC data via TDI and transport protocol.
Who will manage the buffer?
As mentioned above, AFD.SYS is responsible for the management of buffers using the application that communicates with the Socket interface and the transfer protocol layer. That is, when a program calls the Send or Wsasend function, the data is copied to the internal buffer of AFD.SYS (the size is set according to the SO_SNDBUF), and then Send and WSasend immediately return. The data is then sent by AFD.SYS to the network, and is not related to the application. Of course, if the application wishes to send data larger than the buffer set than the SO_SNDBUF, the WSasend function will be blocked until all data is sent.
Similarly, when the data is received from the distance, if the application does not submit the Receive request, and the online data does not exceed the buffer size set by the S_RCVBUF, then AFD.SYS copies the data on the network to its own internal buffer save. . When the application calls the RECV or WSARECV function, the data is copied from the buffer of AFD.sys to the buffer provided by the application.
In most cases, this system works very well. Especially when the application uses a general transmission acceptance routine that does not involve using Overlapped. The developer can change the value of the two settings of SO_SNDBUF and SO_RCVBUF by using the SetsockOpt API function to 0 to turn off the internal buffer of AFD.SYS. However, this will bring some consequences: For example, the application sets the SO_SNDBUF to 0, turn off the send buffer (referring to the buffer in AFD.SYS), and issues a synchronous blockage-type transmission operation, the application provided by the application The area will be locked by the kernel, the Send function will not return until the other end of the connection receives the data of the entire buffer. This seems a very good way to judge whether your data has been charged by the other party. But in fact, this is very bad. The problem is that even if the network layer receives a confirmation of the remote TCP, it cannot guarantee that the data will be safely confirmed to the client application, because the client may happen, and the application cannot be from Afd.sys. Internal buffer replication gets data. The more significant problem is: Due to blocking, the program can only perform a Send operation in one thread, which is very no efficiency.
If the closed accept buffer (setting the value of SO_RCVBUF is 0), it is not true to improve efficiency. Accepting buffering 0 Forcing the received data is buffered in a lower layer than the Winsock core, and the buffer copy is performed when the Recv is called so that you turn off the fundamental intention of the AFD buffer (avoid buffering copy). The shutdown reception buffer is not necessary. As long as the application often consciously calls overlapping WSARECVS operations on a connection, avoiding AFD always buffering a large amount of arrival data.
Here, we should clearly turn off the buffer not much good for most applications.
However, a high-performance service program can turn off the send buffer without affecting performance. Such a program must ensure that it executes multiple overlapped sent at the same time, rather than waiting for an overlapped transmission to execute another. This allows the data buffer to be used immediately if a data buffer data has been submitted. If the program "Serial" execution overlapped is sent, it will waste another time before the sending is executed.
Resource constraint
Robust is a major design goal for each service program. That is, the service program should be able to deal with any burst problems, such as the peak of the client request, the temporary poor and other reliability issues. For the sake of peaceful resolution, developers must understand the resource constraints on the typical WindowsNT and Windows2000 platforms.
The most basic problem is the network bandwidth. The service program transmitted using the UDP protocol is high, as such a service program requires as little packet loss rate. Even using TCP connections, the server must also be careful not to abuse network resources. Otherwise, a large number of retransmission and connection cancel events will occur in the TCP connection. The specific bandwidth control is related to the specific procedures, exceeding the discussion scope of this article.
The virtual memory used by the program must be careful. The memory application and release should be conservative, perhaps you can use the next list (a buffer that records the "idle" memory that has been used, which is used to use, the user is used, and the idle memory can be used. The program avoids excessive repeated application, and guarantees that there is always as much free memory as possible. (Applications can also use the setworkingsetsize this Win32API function to increase the physical memory available to the system.)
There are two Winsock programs that do not face resource constraints directly. The first is the page lock limit. Whether the application initiates Send or Receive operation, the buffering of the data is locked in physical memory regardless of whether the application initiates Send or Receive operation. Because the kernel drives to access the memory data, the memory area cannot be unlocked during access. In most cases, this will not produce any problems. However, the operating system must confirm that there is also available canable memory to other programs. The purpose of doing this is to prevent a program that is wrong from requesting to lock all physical RAMs, causing the system to crash. This means that applications must be consciously avoided to cause excessive pages to lock or exceed system restrictions. In WinNT and Win2000, the total memory lock limitations allowed by the system are probably 1/8 of physical memory. This is just a rough estimate that cannot be used as an accurate calculation data. Just need to know, sometimes overlapping the IO operation will fail to fail, because there may be too many Send / Receives operations at the same time. The program should pay attention to avoid this.
Another resource restriction is that the program is running, the system reaches the limitations of the non-paged memory pool. Winnt and Win2000 drivers apply for memory from the specified non-paged memory pool. The memory allocated in this area is not fan-out because it contains multiple different kernel objects that may need access, while some kernel objects are not accessible to memory. Once the system creates a socket (or open a file), a certain number of non-paged memory is assigned. In addition, binding and connection socket also results in an additional non-paged memory pool. Further, an I / O request, such as Send or Receive, is also assigned a little pointless non-page memory pool (in order to track the I / O operation, including a small structure that must be information is assigned . There are fewer accumulation, and finally may lead to problems. Therefore, the operating system limits the number of non-paged memory. On WinNT and Win2000 platforms, the exact amount of non-page memory allocated by each connection is different, and it may also be different on the future Windows version. If you want to extend your programs, don't intend to accurately calculate and control your non-page memory in your program.
Although it cannot be accurately calculated, the program should pay attention to avoid impact non-page restrictions on the strategy. When the system's non-tap pool is exhausted, a driver that is completely unrelated to your program is likely to have problems because it cannot apply normally to non-page memory. In the worst case, it will cause the entire system to crash. For example, those third-party devices or systems themselves. Remember: On the same computer, there may be other service programs running, and also consume non-page memory. Developers should estimate resources with the most conservative policy and develop programs based on this policy.
Resource constraints are very complicated, because in fact, when the resource is inadequate, there may not be a specific error code to return to the program. The program may get wsaenobufs or
ERROR_INSUFFICIENT_RESOURCES's general return code. How to deal with these errors, first, reasonable additions of the program's work environment settings (Working SET, if you want more information, please refer to the MSDN John Robbins about Bugslayer chapter). If you still don't solve the problem, you may have encountered non-page memory pool restrictions. Then it is best to close some connections immediately and look forward to returning to normal.
About Accepting
One of the most common way to serve the client is to accept the client's connection. The ACCEPTEX function is the only function that can accept the socket connection using overlapping IO modes in the Winsock API. AccpeTex requires an incoming socket as its parameters. Ordinary synchronous accept functions, new sockets are worth it. The AcceptEx function is an overlapping operation that receives the socket should be created in advance (but do not need binding and or connection), and passed into this API. (ACCEPTEX original, thickened, Socket, needed
BOOL AcceptEx (SOCKET sListenSocket, SOCKET sAcceptSocket, PVOID lpOutputBuffer, DWORD dwReceiveDataLength, DWORD dwLocalAddressLength, DWORD dwRemoteAddressLength, LPDWORD lpdwBytesReceived, LPOVERLAPPED lpOverlapped);
)
The routine that uses acceptex may be this look:
Do {
-Wait for a previous acceptex to complete // Wait for the previous ACCEPTEX to complete
-Create a new socket and associate it with the completion port // Create a new Socket and associate it
/ / To complete the port
-Allocate context structure etc. // Initialization related environment information structure
-Post an accept. // Enter the AcceptEx request.
WHILE (TRUE);
A server has always had enough AcceptEx call, which can respond to the client's connection. The number of ACCEPTEX operations depends on the server's policy. If you want to meet the high connection (such as a large number of short-proof connections or explosive flows), it is of course more ACCEPTEX portals than the procedures that do not often occur. Smart strategies are based on traffic changes the number of ACCEPTEX calls, and avoid only one determinated number.
On Win2000, Winsock provides some help to determine if the number of acceptex calls cannot be able to keep up. After creating a listening socket, use the WSAEventselect function to associate it and an FD_ACCEPT event, if there is no calling that accept is not in progress, once there is a request, the event (fd_accept) will happen. So this event can be used to tell developers: more ACCEPTEX operations are required, or thereby detecting a remote entity with abnormal behavior. Note: This mechanism is invalid on NT.
Significant benefits using Acceptex is: You can get the client's data in a connection, see AcceptEx's LPOUTPUTBUFFER parameter. This means that if the client is connected and sent immediately, AcceptEx will be completed after the client connection is successful and the data transmission. The problem caused by this feature is that acceptex must wait for data to be completed to return. Because a ACCEPTEX function with an Output buffer is not a "atom" operation, but two steps: accept connection and wait data. So the program does not know the connection success before the data is accepted. Of course, the client can also connect to the server without sending data immediately. If this connection is too much, the server will begin to refuse legitimate connections because there is no universal ACCEPT operating entry. This is also a common method, which prevents malicious attacks and massive connections by refusing access.
In the thread that is being accepted, you can check that AcceptEx calls incoming socket, call getSockopt Check its SO_CONNECT_TIME, which is the time of the socket connection, and returns -1 when not connected. According to the features of the WSAEventSelect mechanism, we can easily determine whether the connection time of the Socket handle that is transmitted to the AcceptEx function should be checked. If in a certain period of time, AcceptEx does not receive data from a connection, and AcceptEx can disconnect by turning off the socket. In an unstoppless situation, the program should not turn off the unconnected Socket in an AcceptEx because the system considers performance issues, and the kernel data structure associated on AcceptEx is not released until a new connection arrived or listened. Socket itself is closed.
At first glance, a thread that issues an Acceptex request can also be an association to complete the port and process other working threads that complete the IO event. However, it is best not to design such a thread. There is a side effect on the hierarchy of Winsocket2, that is, a Socket / WSasocket API overhead is quite considerable, each Accepex needs to create a new Socket, so it is best to create a thread that is independent of other IO processing. Calling AcceptEx. Of course, you can also use this thread to make other work such as creating event logs.
The last thing to note about Acceptex is that other vendors of Winsock2 do not necessarily implement the AcceptEx function. The same situation also includes other Microsoft specific APIs such as TransmitFile, GetAcceptexsockAddrs, and other Microsoft will be in the later version of Windows. On systems running WINNT and WIN2000, these APIs are implemented in the DLL (Mswsock.dll) provided by Microsoft, which can be dynamically called these extended APIs by linking mswsock.lib or through WSAIOCTL SIO_GET_EXTENSION_FUNCTION_POINTER operation.
Uncommitted Function Pointer Call function (such as directly connected Mswsock..lib and directly calling acceptex), because AcceptEx is actually existing outside the Winsock2 structure system. Each application often tries to call AcceptEx on the service provider (MSWSock) to capture the function pointer through WSAIOCTL. If you want to avoid this impact performance, the application is best to get the pointer of these APIs directly from the service provider to WSAIOCTL.
TransmitFile and TransmitPackets function
Winsock provides two functions optimized for file and memory data transfer. The TransmitFile API is valid in WinNT and Win2000, while TransmitPackets will be implemented in future versions of Windows as a new extension.
TransmitFile can transfer the contents of the file via Socket. In general, if the application passes the file via the Socket, you first use createfile to open the file and cycle call the ReadFile and WSasend function, read a data and then send it until the entire file is sent. Such efficiency is very low, because readfile and wsasend calls need to be converted between user and core states. TransmitFile only needs to know the file handle of the need to transfer and the number of bytes to be transmitted. Only the CreateFile opens this additional overhead to the core state transition. If your program needs to send a lot of files via Socket, this function is recommended.
The original shape of the function is as follows:
BOOL TransmitFile (SOCKET hSocket, HANDLE hFile, DWORD nNumberOfBytesToWrite, DWORD nNumberOfBytesPerSend, LPOVERLAPPED lpOverlapped, LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers, DWORD dwFlags); TransmitPackets API than TransmitFile API Still further, allows the caller to specify multiple file handles and a memory buffer, and transmitted . The original shape is as follows:
Bool Transmitpackets (Socket HSocket, LPTransmit_Packet_Element LPPACKETARRAY, DWORD NELEMENT, DWORD NSENDSIZE, LPOVERLAPPED LPOVERLAPPED, DWORD DWFLAGS);
LPPACKetArray contains arrays of structures. Each entry point specifies a file handle or memory buffer that needs to be transmitted. The member of the structure is as follows:
Typedef struct _transmit_packets_erement {dWord dwelflags; dword cleyt; union {structure {large_integer nfileoffset; handle hfile;}; pvoid pBuffer;};
The names of each member are self-explanatory. DWEIFLAGS members specify the element in the structure is a file handle (TF_ELEMENT_FILE) or a memory buffer (TF_ELEMENT_MEMORY). CLENGTH members represent the number of bytes to be transmitted (for file handles, 0 represents all data in files). An unnamed consortium (Union) contains a memory buffer pointer or a file handle (and the specified offset).
Other benefits to using these two functions is that you can use the specified TF_REUSE_SOCKET flag (must specify the TF_DISCONNECT flag at the same time). Once the API function completes the data transfer, the connection is disconnected at the hierarchy of the transfer point, then the socket can be reused by AcceptEx. This reduces the number of times that repeatedly creates Socket and optimizes efficiency.
It should be noted that the Winnt Workstation version or Win2000 Professional version does not implement optimization performance. You must implement it on WinNT, Win2000 Server, Win2000 Advanced Server or Win2000 Data Center.
To achieve a service plan
In the first few chapters, we introduced some APIs and methods that benefit performance improvement, and resources that may encounter. Is this useful for you? Of course, first depends on your server and client design. When designing, you can better avoid bottlenecks to the server and client.
Let's look at a simple use case, in this case we design a server, this server handles the client's connection, then the client sends a data and looks forward to the server response, and the client is disconnected.
Our design is: The server creates a listener socket, and is associated with a completion port, then creates the same number of working threads equivalent to the CPU, and a thread dedicated to AccePtex calls. Since we know that once the client will send data immediately, prepare a buffer will be beneficial to work. Of course, don't forget to check the SO_CONNECT_TIME value that is being connected, avoiding death. An important item in this design is to decide how many ACCEPTEXs need to be developed. Because each AcceptEx operation requires a receive buffer, a large number of pages will be locked (I still remember that each overlapping operation consumes some non-paged memory, and some data buffer is locked to memory). There is no formula and specific guidelines how to determine how many ACCEPTEX operations are allowed. The best solution is to make this number adjustable, through performance test, look for the best value in a typical environment.
Now I have determined how the server handles the connection, and the next step is to send data. Important factors affecting sending data is that you expect the server to process the number of processing connections. In general, the server should limit the number of concurrent connections, as well as explicit Send calls. The more connections means the more non-paged memory usage, and the concurrent Send call should also be restricted to avoid the ability to hosted memory lock limit of the impact system. The number of connections and concurrent seund calls should also be the program adjustable.
In this case, it is not necessary to cancel the reception buffering of each socket because the receiving event occurs only in the ACCEPTEX call. Each Socket has a receive buffer that will not cause any hazard. Once the client / server interacts after the initial request (completed by AcceptEx), the cancellation of the buffer is a very bad practice. Unless you can ensure that these data are completed in the overlapping IO reception of each connection.
Conclusion:
Repeat: Develop an extensible Winsock server is not very difficult. Just starting a listening socket, receives the connection, and performs overlapping and receiving IO operations. The biggest challenge is to manage system resources, limit the number of overlapping IOs, and avoid memory crises. Follow these principles to help you develop high-performance, scalable service programs.
-------------------------------------------------- ------------------------------