Some instructions for writing completion port network servers (1)

zhaozj2021-02-17  75

Some instructions for writing completion port network servers (1)

ACCEPTEX:

BOOLPASCAL FARAcceptEx (IN SOCKET sListenSocket, IN SOCKET sAcceptSocket, IN PVOID lpOutputBuffer, IN DWORD dwReceiveDataLength, IN DWORD dwLocalAddressLength, IN DWORD dwRemoteAddressLength, OUT LPDWORD lpdwBytesReceived, IN LPOVERLAPPED lpOverlapped);

Used to initiate an asynchronous call, accept the connection request to be issued by the client. Unlike Accept, you must first manually create a socket to provide to AcceptEx, used to accept the connection (Accept is innerly created a socket to accept connection, and Return value). And the Socket created by Accept will automatically inherit the properties of the Socket, but the AcceptEx will not. So if necessary, after the AcceptEx successfully accepted a connection, we must call:

Setsockopt (Hacceptsocket, SOL_Socket, SO_UPDATE_ACCEPT_CONTEXT, (CHAR *) & (HLISTENSOCKET), SIZEOF (HLISTENSOCKET);

Come this.

AcceptEx allows the first group of data from the other party while receiving the connection, which is of course for performance considerations. But at this time, it will return to data to receive a byte, once it encounters malicious connections. Never return. The way to turn this feature is to turn the parameters dwreceivedatalength to 0, turn on the opposite. Of course, if you must enable this feature, we also have a defense method. Start a line-of-time to detect each ACCEPTEX Whether it has been connected, how long is the connection time, to determine if the other party is a terrorist:

INT ISECs; int bytes = sizeof (int); getSockopt (HacceptSocket, SOL_Socket, SO_CONNECT_TIME, (CHAR *) & ISECS, & IBYTES

ISECs indicates that the connection is not established, otherwise it is the time that has been connected.

Ways to call acceptex:

#include // for WSAID_ACCEPTEX typedef BOOL (WINAPI * PFNACCEPTEX) (SOCKET, SOCKET, PVOID, DWORD, DWORD, DWORD, LPDWORD, LPOVERLAPPED); PFNACCEPTEX pfnAcceptEx; DWORD dwBytes; GUID guidAcceptEx = WSAID_ACCEPTEX; :: WSAIoctl (HListensocket, SiO_GET_EXTENSION_Function_Pointer, & GuidAcceptex, Sizeof (GuidAcceptex), & PfnAcceptex, SizeOf (PFNAcceptex), & DWBYTES, NULL, NULL;

DWORD uAddrSize = sizeof (SOCKADDR_IN) 16; DWORD uDataSize = 0; BOOL bRes = pfnAcceptEx (hListenSocket, hAcceptSocket, buffer, uDataSize, uAddrSize, uAddrSize, & uAddrSize, (LPWSAOVERLAPPED) overlapped); wherein, buffer and overlapped according to your own The use is set, it is just mixed here.

Once the ACCEPTEX call is complete (you inform you by completing the port), the next step is 1. SO_UPDATE_ACCEPT_CONText;

2. Bind the HACCEPTSOCKET to the completion port.

2. Transmitfile

TransmitFile As the name is the function used to transfer file transfer, all automatically does not need to interfere. Can't play all performance in WIN NT Professional / Family Edition. Only one of its features are discussed here: Turn off a socket and initialize it again. Create a Socket is very time consuming, so doing this to save a lot of time:

#include // for WSAID_TRANSMITFILE typedef BOOL (WINAPI * PFNTRANSMITFILE) (SOCKET, HANDLE, DWORD, DWORD, LPOVERLAPPED, LPTRANSMIT_FILE_BUFFERS, DWORD); PFNACCEPTEX pfnTransmitFile; DWORD dwBytes; GUID guidTransmitFile = WSAID_TRANSMITFILE; :: (hListenSocket WSAIoctl , SiO_GET_EXTENSION_Function_Pointer, & GuidTransmitfile, Sizeof (Guidtransmitfile), & Pfntransmitfile, Sizeof (Pfntransmitfile), & DWBYTES, NULL, NULL;

Pfntransmitfile (Hacceptsocket, NULL, 0, 0, NULL, NULL, TF_DISCONNECT | TF_REUSE_SOCKET);

Sockets that have been processed by this function can be submitted to AcceptEx as an accepted Socket. When such a Socket is successfully connected, if the completion of the port is binding, it is wrong - because the last received connection is successful, it has been binded. This error can be ignored.

3. FD_ACCEPT

Even if we launched more AccePtex when the program starts, it is possible that the number is not enough. In the Win2000 or higher of the system, we can register an FD_ACCEPT event via WSAEventselect. When the number of ACCEPTEX is not enough This event will be triggered when dealing with a large number of connection requests. So we can issue more Acceptex, and we can also take the space to identify why acceptex uses light so soon, is it in touch with an attacker (see you see As described above)?

Handle HacceptExthreadEvent = :: CreateEvent (NULL, TRUE, FALSE, _T ("AcceptExThreadEvent"))) ;: WSAEventSelect (Hlistensocket, HaccePtexthReadEvent, fd_accept);

DWORD WINAPI ACCEPTEXTHREAD (LPVOID LPPARETER) {// is responsible for ensuring that there is enough AcceptEx to accept threads requested

For (uint i = 0; i <10; i ) // initiated acceptex {pfnacceptex (hlistenSocket, ...);} while {dword dwres = :: waitforsingleObject (HaccePtexThreadEvent, Infinite) ; If (dwres == wait_failed) {Break;} :: resetEvent (HacceptExtHreadEvent); if (m_sbwaitforeXIT) {// Of course, the exit thread is also this Event notification Break;} pfnacceptex (hlistensocket, ...);

// // ... At this time, check whether it is attacked //} return 0;} It is to be explained that the Event created by WSAEventSelect () is universal.

4. Wsasend and WSARECV

By default, each Socket has a transmission and receiving buffer in the underlying system.

When we send data, it is actually copied to the send buffer, then WSasend returns. But if the send buffer is already full, then the buffer we specified in WSasend will be locked to the system's non-page memory pool. In the middle, WSasend returns WSA_IO_PENDING. Once the network is idle, the data will be directly sent from the buffer we submitted, and the "our buffer -> Send buffer -> network" saves a copy operation.

WSARECV is also the same, and directly copy the data in the received buffer when receiving data. If there is no data in the receive buffer, the buffer we specified in WSARECV will be locked to the system's non-page memory pool to wait for data, WSarecv Returns to WSA_IO_PENDING. If there is data on the network, these data will be saved directly into the buffer we provide. If a server is connected to many clients, there are many WSARECVs for each client, so a lot Memory will be locked to a non-paged memory pool. When these memory is locked, it is locked according to the page boundary, that is, even if you wsarecv's cache size is 1 byte, the locked memory will also be 4K. Non-paging memory The pool is shared by the entire system. The worst case is the system crash. One solution is to call WSARECV using a buffer of size 0. Wait until the call is successful, then replace the non-blocking RECV receipted data. Until it returns WSAEWOULDBLOCK to indicate that the data is all read. There is no memory in this process to be locked, but the damage is a slightly less efficient.

See: << Windows Network Programming (Second Edition) >> Chapter 6

Download: http://www.guxiang.com/epubcn/readings/diannaotushu/500/download/1107/neetwork_prog_for_win_2nd.zip Decomposition Password: www.epubcn.com

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

New Post(0)