Socket IO model full contact

xiaoxiao2021-03-06  22

This article briefly introduces the current various Socket I / O models supported by Windows. If you find something wrong, please enlighten me.

1: SELECT model 2: WSAASYNCSELECT model three: WSAEventselect model 4: Overlapped I / O event notification model 5: Overlapped I / O completion routine model six: IOCP model

Lao Chen has a daughter working in the field, can't come back, Lao Chen and she contacts her letter. Their letter will be delivered to their mailbox by the postman. This is very similar to the Socket model. Below I will explain the Socket I / O model as an example of receiving letters ~~~

1: SELECT model

Lao Chen wants to see daughter's letter. So, every 10 minutes will check the mailbox, see if there is a daughter's letter ~~~~~ In this case, "downstairs check the mailbox" and then returned to the upstairs to delay the time, So old Chen can't do other work. The SELECT model and this situation of Lao Chen is very similar: the week is beginning to check ... If there is data ... Receive / send .......

Used to select a thread should be common practice: procedure TListenThread.Execute; var addr: TSockAddrIn; fd_read: TFDSet; timeout: TTimeVal; ASock, MainSock: TSocket; len, i: Integer; begin MainSock: = socket (AF_INET, SOCK_STREAM, Ipproto_tcp); addr.sin_family: = afd_inet; addr.sin_port: = htons (5678); addr.sin_addr.s_addr: = htonl (inaddr_any); Bind (MAINSOCK, @addr, sizeof (addr); Listen (MAinsock, 5 );

While (NOT TERMINATED) DO BEGIN FD_ZERO (fd_read); fd_set (MAINSOCK, FD_READ); timeout.tv_sec: = 0; timeout.tv_usec: = 500; if SELECT (0, @fd_read, nil, nil, @timeout)> 0 THEN / At least one Waiting for Accept's Connection Begin if fd_isset (mainsock, fd_read) Then Begin for i: = 0 to fd_read.fd_count-1 do // Note, fd_count <= 64, that is, SELECT can only manage simultaneously Up to 64 connected Begin Len: = sizeof (addr); asock: = accept (mainsock, addr, len); if asock <> invalid_socket dam created a new thread for Asock, in the new thread Keep SELECT End; end; end; end; // while (not self.terminated)

Shutdown (MAINSOCK, SD_BOTH); CloseSocket (MAINSOCK); END;

Two: WSAASYNCSELECT model

Later, old Chen used Microsoft's new mailbox. This mailbox is very advanced. Once there is a new letter in the mailbox, Gates will give the old Chen: Hello, uncle, you have new letters! Since then, Lao Chen will no longer have to check the mailbox again, and the teeth are not hurt. You are sure, blue sky ... is not, Microsoft ~~~~~~~~ Microsoft provides the WSaasyncselectElect model of Microsoft. meaning. The WSaasyncselect model is the simplest and easy-to-use Socket I / O model under Windows. When using this model, Windows will notify the application in the situation of the message. First define a message indication constant: const wm_socket = WM_USER 55; add a function declaration that handles this message in the primary form of the master form: Private Procedure WMSocket; Message WM_Socket; then you can use WSaasyncselect: VAR Addr: TsockAddr; SOCK: TSOCKET;

sock: = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); addr.sin_family: = AF_INET; addr.sin_port: = htons (5678); addr.sin_addr.S_addr: = htonl (INADDR_ANY); bind (m_sock, @addr, sizeof ( SockAddr));

WSaasyncselect (m_sock, handle, wm_socket, fd_accept or fd_close);

Listen (M_Sock, 5); ....

The application can analyze the WM_Socket message, which is determined which socket generates a network event and an event type:

Procedure tfmmain.wmsocket (var sock: tsocket; addr: tsockaddrin; addr: integer; buf: array [0..4095] of char; begin // msg WPARAM is a Socket handle that produces network events , LParam contains the event type case WSAGetSelectEvent (Msg.LParam) of FD_ACCEPT: begin addrlen: = sizeof (addr); sock: = accept (msg.WParam, addr, addrlen); if sock <> INVALID_SOCKET then WSAAsyncSelect (sock, Handle, WM_Socket, fd_read or fd_write or fd_close);

FD_close: CloseSocket (Msg.wParam); FD_READ: RECV (Msg.wParam, BUF [0], 4096, 0); fd_write:;

Three: WSAEventSelect Model

Later, Microsoft's mailbox was very popular, and people who purchased Micro-mailboxs were counting millions ... so that Gates called customers 24 hours a day, tired back pain, drink ants and gods are not good ~ ~~~~~ Microsoft improved their mailbox: add an additional device in the customer's home, this device will monitor the customer's mailbox, every new letter is coming, this device will issue "new letters to arrive", remind the old Chen Received. Gates can finally sleep. To use the same thread: procedure TListenThread.Execute; var hEvent: WSAEvent; ret: Integer; ne: TWSANetworkEvents; sock: TSocket; adr: TSockAddrIn; sMsg: String; Index, EventTotal: DWORD; EventArray: Array [0..WSA_MAXIMUM_WAIT_EVENTS- 1] of wsaevent; begin ... socket ... bind ... hevent: = wsacreateEvent (); wstensock, hevent, fd_accept or fd_close); ... listen ...

while (not Terminated) do begin Index: = WSAWaitForMultipleEvents (EventTotal, @EventArray [0], FALSE, WSA_INFINITE, FALSE); FillChar (ne, sizeof (ne), 0); WSAEnumNetworkEvents (SockArray [Index-WSA_WAIT_EVENT_0], EventArray [ Index-WSA_WAIT_EVENT_0], @ne);

IF (Ne.LnetWorkevents and fd_accept> 0 THEN BEGIN if Ne.ierrorcode [fd_accept_bit] <> 0 THEN CONTINUE;

ret: = sizeof (adr); sock: = accept (SockArray [Index-WSA_WAIT_EVENT_0], adr, ret); if EventTotal> WSA_MAXIMUM_WAIT_EVENTS-1 then // here also WSA_MAXIMUM_WAIT_EVENTS 64 begin closesocket (sock); continue; end;

HEVENT: = WSACREATEEVENT (); WSAEventSelect (Sock, HEVENT, FD_READ OR FD_WRITE [Eventtotal]: = SOCK; EventArray [Eventtotal]: = HEVENT;

if (ne.lNetworkEvents and FD_READ)> 0 then begin if ne.iErrorCode [FD_READ_BIT] <> 0 then continue; FillChar (RecvBuf [0], PACK_SIZE_RECEIVE, 0); ret: = recv (SockArray [Index-WSA_WAIT_EVENT_0], RecvBuf [0], PACK_SIZE_RECEIVE, 0); ... End; end; end; 4: Overlapped I / O event notification model

Later, Microsoft found that Lao Chen did not like to go upstairs to send and receive letters, because the upstairs is actually a waste of time. So Microsoft improved their mailbox again. The new mailbox has adopted a more advanced technology. As long as the user tells Microsoft's own home, the new mailbox will transfer the letters directly to the user's home, then tell the user, your letters have already been put in your home. ! Lao Chen is very happy, because he doesn't have to personally send and receive the letter again!

The Overlapped I / O event notification model and the WSAEventSelect model are very similar, mainly different in "overlapped", the Overlapped model is to allow the application to use overlapping data structures (WSAOVERLAPPED), deliver one or more WINSOCK I / O requests at a time. The application will receive a notification after the request is completed. What does that mean? That is to say, if you want to receive data from the socket, just tell the system, receive data for you, and you need to do just provide a buffer ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~ The Send thread is completely different: procedure toverlapthread.execute; var dwtemp: dword; ret: integer; index: dword; begin ...

while (not Terminated) do begin Index: = WSAWaitForMultipleEvents (FLinks.Count, @ FLinks.Events [0], FALSE, RECV_TIME_OUT, FALSE); Dec (Index, WSA_WAIT_EVENT_0); if Index> WSA_MAXIMUM_WAIT_EVENTS-1 then // timeout or other Error Continue;

Wsareseteevent (Flinks.Events [index]); WsageToverlappedResult (Flinks.Sockets [Index], Flinks.Poverlaps [Index], @dwtemp, false, flinks.pdwflags [index] ^);

If DWTEMP = 0 THEN / / Connection has been turned off ... Continue; end else begin fmmain.listbox1.items.add (flinks.pbufs [index] ^. buf);

// Initialization buffer flinks.pdwflags [index] ^: = 0; Fillchar (Flinks.Poverlaps [index] ^, sizeof (wsaoverlapped), 0); flinks.poverlaps [index] ^. HEVENT: = flinks.events [Index ]; Fillchar (Flinks.pbufs [index] ^. Buf ^, buffer_size, 0); // Hand a receive data request wsarecv (Flinks.Sockets [index], flinks.pbufs [index], 1, flinks.pdwrecvd [index ] ^, Flinks.pdwflags [INDEX] ^, Flinks.Poverlaps [index], nil); End;

Five: Overlapped I / O completion routine model

After receiving new letters, the general procedure is: Open Envelope ---- Out of the Letter ---- Read Letter ---- Reply Letters ... In order to further reduce the user burden, Microsoft is developing A new technology: Users only tell Microsoft's handling of letters, Microsoft mail box will process letters according to these steps, no longer need users to dismantle / reading / reply! Lao Chen finally lived in small life!

Overlapped I / O completion routines require users to provide a callback function, and the system will perform this function when the new network event: Procedure workerRoutine (const dword; const lpoverlapped: lpwsaoverlapped; const dwflags: dword); stdcall; Then tell the system to process the received data with the workerRoutine function: wsarecv (m_socket, @fbuf, 1, dwtemp, dwflag, @m_overlap, workerroutine); then ... Nothing then, the system is done ! Microsoft is really considerate! While (not Terminated) do // This is a RECV / Send thread to do ... don't do anything! ! ! Begin if Sleepex (RECV_TIME_OUT, TRUE) = Wait_io_completion dam (END ELSE BEGIN Continue; "

Six: IOCP model

The Microsoft mailbox seems to be perfect, and the old Chen is also very satisfied. But in some big companies, it is completely different! These big companies have tens of thousands of mailboxes, hundreds of letters need to be handled per second, so that Microsoft mailboxes often crashed due to overload! Need to restart! Microsoft had to make the killing ... Microsoft sent a super robot named "Completion Port" to each big company, letting this robot to deal with those letters!

"The Windows NT team noted that the performance of these applications is as high as high. Special, how many simultaneous client requests mean that many threads are running in the system. Because all of these threads are running [no hanging What happened to and waited], Microsoft realized that the NT core spent too much time to convert the context of running thread [Context], threads did not get a lot of CPU time to do their work. You may also feel parallel models The bottleneck is that it creates a new thread for each customer request. Creating a thread is smaller than the creation process overhead, but it is far from not expensive. We may wish to imagine: If you start N thread in advance, let them That Hold [Clog], then you can deliver all users to a message queue. Then the N thread takes the message from the message queue one by one. You can avoid the request for each user request. Not only, the resources of threads are not only improved. The utilization rate is improved. Theoretical is very good, you think that I can think about the problem, how can Microsoft does not take into account? "----- From Nonocast's "Understanding I / O Completion Port" first look at the implementation of the IOCP model:

// Create a completion port FCOMPLETPORT: = CREATEIOCOMPLET (INVALID_HANDLE_VALUE, 0, 0, 0);

// Accept the remote connection and bind this connected Socket handle to Aconnect: = Accept (Flistensock, ADDR, LEN); CreateiocTensock, NIL, 0);

// Create a CPU number * 2 2 thread for i: = 1 to si.dwnumberofprocessors * 2 2 dobegin athread: = TRECVSENDTHREAD.CREATE (false); athread.completport: = fcompletport; // Tell this thread, you want Go to this IOCP to access the data END;

OK, it's as simple, what we have to do is to create an IOCP, bind the remote connection Socket handle to the IOCP you just created, and finally create N threads and tell this N threads to access data on this IOCP. .

Let's take a look at the TRECVSENDTHREAD thread:

procedure TRecvSendThread.Execute; var ...... begin while (not self.Terminated) do begin // IOCP status query (data write operation is finished) GetQueuedCompletionStatus (CompletPort, BytesTransd, CompletKey, POVERLAPPED (pPerIoDat), TIME_OUT) ;

IF BYTESTRANSD <> 0 Then ....; // Data reading and writing

// Remit one read data request WSARECV (CompletKey, @ (pperiodat ^ .bufdata), 1, BytesRecv, Flags, @ (pperiodat ^ .overlap), NIL); end;

The read and writing thread simply checks if IOCP completed the read and write operations we delivered. If it is completed, it will be delivered to a new read and write request. It should be noted that all TRECVSendThread we created is accessing the same IOCP (because we only create an IOCP) and we did not use the critical area! Don't you conflict? Don't you consider synchronous problems? Oh, this is the mystery of IOCP. IOCP is not an ordinary object and does not need to consider thread security issues. It automatically provides access to its thread: If there is a thread A on a socket is being accessed, the access request of thread B is assigned to another Socket. All this is automatically stored by the system, we don't have to ask. Oh, finally finished, so tired ... All source code can be seen from here: http://community.9cbs.net/expert/topic/3844/3844679.xml? Temp = 5.836123E- 02 However, the code is very simple, please include!

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

New Post(0)