Imaging: Winsock Application for Developing a Needled Size in Completion Port (1)

zhaozj2021-02-16  60

Usually developing a web application is not a relaxing thing, but in fact, as long as you master a few key principles - create and connect a socket, try to connect, then send and receive data. It's really difficult to write a web application that can be accepted, one thousand connected network applications. This article will discuss how to develop high-extension WINSOCK applications through Winsock2 on Windows NT? And Windows 2000. The main focus of the article is in the server / server model server, of course, many of them apply to both sides of the model.

API and response scale

With the overlapping I / O mechanism of Win32, the application can draw an I / O operation, overlapping operation requests are completed in the background, and the thread of the same time is done to do other things. The thread receives the relevant notice after the overlapping operation is completed. This mechanism is especially useful for those time consuming operations. However, the functions like WSaasyncselect () and UNIX on Windows 3.1 are easy to use, but they cannot meet the needs of the response scale. The completion of the port mechanism is optimized for the operating system. On Windows NT and Windows 2000, the overlapping I / O mechanism to complete the port can truly expand the system's response scale.

Complete port

A completion port is actually a notification queue that places a notification of the completed overlapping I / O request by 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 completion port at any time.

Typically, we create a certain number of worker threads in the application to handle these notifications. The number of threads depends on the specific needs of the application. Ideally, the number of threads is equal to the number of processors, but this also requires any threads should not perform an operation such as synchronous read and write, waiting event notification, etc., to avoid thread blocking. Each thread will be divided into a certain CPU time, during which the thread can run, then another thread will be divided into a time slice and start execution. If a thread performs blocking operations, the operating system will deprive its unused time slice and let other threads begin. That is, the previous thread does not fully use its time slice. When this happens, the application should prepare other threads to make full use of these time films.

The use of the port is divided into two steps. First create a completed port, as shown in the following code: Handle Hiocp;

Hiocp = CreateiocompletionPort (INVALID_HANDLE_VALUE, NULL, (ULONG_PTR) 0, 0); if (hiocp == null) {// error}

After completing the port creation, you want to associate the socket that will use the completion port. The method is to call the createioCompletionPort () function again, the first parameter fileHandle is set to the handle of the socket, and the second parameter existingCompletionPort is set to the handle of the completed port just created. The following code creates a socket and associates it and the previously created completion port: Socket S;

s = socket (AF_INET, SOCK_STREAM, 0); if (s == invalid_socket) {// Errorif (CreateiocompletionPort ((Handle) S, Hiocp, (Ulong_PTR) 0, 0) == NULL) {// error} ?? At this time, the association operation of the socket and the completion port is completed. Any overlapping operations on this socket will make a completion notification by completing the port. Note that the third parameter in the CreateiocompletionPort () function is used to set a "completion key" (Translator Note) (the translator note) (the translator)) is set to any data type. Whenever the notification is completed, the application can read the corresponding completion key, so the completion key can be used to pass some background information to the socket. After creating a completed port, after the one or more sockets is associated with it, we have to create several threads to process completion notifications. These threads continue to circulate the getQueuedCompletionStatus () function and return to the completion notification.

Below, let's take a look at how the app tracks these overlapping operations. When the application calls a overlapping operation function, the pointer to an Overlapped structure is included in its parameters. When the operation is complete, we can take this pointer through the getQueuedCompletionStatus () function. However, the order is based on the Overlapped structure pointed to by this pointer, and the application cannot distinguish which operation is completed. To implement tracking of the operation, you can define an Overlapped structure to join the required tracking information.

Whenever the overlapping operation function is called, a OverlappedPlus structure (such as WSasend, WSARECV) is always passed through its LPOVERLAPPED parameters. This allows you to set some operating status information for each overlapping call operation. When the operation is over, you can get a pointer to your custom structure through the getQueuedCompletionStatus () function. Note that the Overlapped field does not require a first field of this extended structure. After getting a pointer to the Overlapped structure, you can take a pointer to the extended structure with the containing_record macro (the translator Note: The above two segments will be the OverlappedPlus structure, which will be the overlapped structure, I don't understand it, please master Enlighten me

The definition of the overlapped structure is as follows: typedef struct_overlappedplus {Overlapped OL; Socket S, Sclient; int Opcode; Wsabuf WBUF; DWORD DWBYTES, DWFLAGS; // Other Useful Information} OverlappedPlus;

#define op_read 0 # define op_write 1 # define op_accept 2

Let's take a look at the situation of the worker thread in Figure 2.

Figure 2 Worker Thread

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- > splient; newolp-> opcode = op_read;

// this function 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 latter USE FreeoverlappedPlus (overlapplus); // Signal Accept thread to Issue Another AccepTex SetEvent (HACCEPTTHREAD); BREAK;

Case op_read: // process the data d ///••

// 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

The content of each handle key is the completion key parameter set when the completion port is associated with the socket; the OVERLAP parameter returns a pointer to the OverlappedPlus structure that is used when emitting overlapping operations.

To remember, if the overlapping operation call fails (that is, the return value is socket_error, and the error is not WSA_IO_PENDING, then the completion port will not receive any completion notification. If the overlapping operation calls success, or if the cause is WSA_IO_PENDING error, the completion port will always be able to receive the completion notification. (Endlessly)

Translator: Liu Xiqi

转载请注明原文地址:https://www.9cbs.com/read-24555.html

New Post(0)