Full-contact good of socket I/O model based on Delphi

Source: Internet
Author: User
Tags htons

Lao Chen had a daughter who worked outside and could not come back often, and she contacted her by letter. Their letter will be delivered to their mail box by the postman.

This is very similar to the socket model. I'll take the letter from Lao Chen as an example to explain the socket I/O model.

  One: Select model

Lao Chen wanted to see his daughter's letter very much. So that he went downstairs every 10 minutes to check the mailbox to see if there is a daughter's letter, in this case, "go downstairs to check the mailbox" and then back upstairs to delay the old Chen too much time, so that Lao Chen can not do other work.

The Select model is very similar to that of old Chen: Go round and round to check ... If there is data ... Receive/Send ....

Using threads Select should be a 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: = af_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) does
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 1 connection waiting for accept
Begin
If Fd_isset (Mainsock, Fd_read) Then
Begin
For i:=0 to Fd_read.fd_count-1 do//note, Fd_count <= 64, which means select can manage up to 64 connections at the same time
Begin
Len: = sizeof (addr);
Asock: = Accept (Mainsock, addr, Len);
If Asock <> Invalid_socket Then
....//Create a new thread for Asock, and then continue to select in the new thread
End
End
End
End While, not self. Terminated)

Shutdown (Mainsock, sd_both);
Closesocket (Mainsock);
End


  Two: WSAAsyncSelect model

Later, Lao Chen used the new mailbox of Microsoft Corporation. This kind of mailbox is very advanced, once the new letter in the mailbox, Gates will call old Chen: Hello, Grandpa, you have a new letter! From then on, Lao Chen no longer have to check the mailbox frequently, the tooth also does not ache, you look quasi, the blue sky ... No, Microsoft ...

The WSAAsyncSelect model provided by Microsoft is what this means.

The WSAAsyncSelect model is the most easy-to-use socket I/O model under Windows. With this model, Windows notifies the application of network events in the context of the message.

First define a message-marking constant:

Const Wm_socket = Wm_user + 55;


Then add a function declaration that processes this message in the private domain of the main form:

Private
Procedure Wmsocket (var msg:tmessage); Message Wm_socket;


Then you can use the 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 parse the received Wm_socket message to determine which socket generated the network event and the type of event:

procedure Tfmmain.wmsocket (var msg:tmessage);
var
sock:tsocket;
Addr:tsockaddrin;
Addrlen:integer;
Buf:array [0..4095] of Char;
  The Begin
//msg wparam is the socket handle that generated the network event, and 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_clos E);
End;  

Fd_close:closesocket (msg.wparam);
Fd_read:recv (Msg.wparam, buf[0], 4096, 0);
Fd_write:;
end; 
End;

Three: WSAEventSelect model

Later, Microsoft's mailbox is very popular, the number of people who buy Microsoft mailbox is counted in millions ... So that Gates 24 hours a day to call customers, tired of the back pain, drinking ant force God is not good. Microsoft has improved their mailbox by adding an add-on device to the customer's home that monitors the customer's mailbox, and whenever a new letter arrives, the device sends a "new letter arrival" to remind Lao Chen to collect the letter. Finally, gates can sleep.

Also to use threads:

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 ();
WSAEventSelect (Listensock, hevent, fd_accept or fd_close);
..... listen ...

while (not Terminated) does
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 wsa_maximum_wait_events is also 64
Begin
Closesocket (sock);
Continue
End

Hevent: = Wsacreateevent ();
WSAEventSelect (sock, hevent, fd_read or Fd_write or fd_close);
Sockarray[eventtotal]: = sock;
Eventarray[eventtotal]: = hevent;
INC (eventtotal);
End

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


  Four: Overlapped I/O event notification model

Later, Microsoft through the investigation found that Lao Chen does not like to go downstairs to send and receive letters, because the upper and lower floors are actually a waste of time. So Microsoft is improving their mailbox again. New mailboxes use more advanced technology, as long as users tell Microsoft their home in the number of floors, the new mailbox will send the letter directly to the user's home, and then tell the user, your letter has been put in your home! Lao Chen is very happy because he doesn't have to send and receive letters himself!

The Overlapped I/O event notification model and the WSAEventSelect model are very similar in implementation, primarily in the "Overlapped", where the Overlapped model is to let applications use overlapping data structures (wsaoverlapped), One or more Winsock I/O requests are posted at one time. When these submitted requests are complete, the application receives a notification. What do you mean? That is, if you want to receive data from the socket, just tell the system that the system is receiving the data for you, and all you need to do is provide a buffer for the system ~~~~~
The listen thread is identical to the WSAEventSelect model, and the recv/send thread is completely different:

Procedure Toverlapthread.execute;
Var
Dwtemp:dword;
Ret:integer;
Index:dword;
Begin
......

while (not Terminated) does
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

Wsaresetevent (Flinks.events[index]);
WSAGetOverlappedResult (Flinks.sockets[index], Flinks.poverlaps[index], @dwTemp, false,flinks.pdwflags[index]^);

If dwtemp = 0 then//the connection is closed
Begin
......
Continue
End Else
Begin
FMMAIN.LISTBOX1.ITEMS.ADD (FLINKS.PBUFS[INDEX]^.BUF);
End

Initializing buffers
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);

Pass one receive data request
WSARecv (Flinks.sockets[index], Flinks.pbufs[index], 1, flinks.pdwrecvd[index]^, flinks.pdwflags[index]^, Flinks.poverlaps[index], nil);
End
End



V: Overlapped I/O completion routine model

Old Chen received a new letter, the general procedure is: Open the envelope----out the stationery----Read the letter----reply to the letter ... In order to further alleviate the user burden, Microsoft has developed a new technology: Users just tell Microsoft about the steps of the letter, Microsoft Mailbox will follow these steps to process the letter, no longer require users to personally eagerness/read/reply! Lao Chen finally had a petty bourgeoisie life!

The Overlapped I/O completion routine requires the user to provide a callback function that the system executes when a new network event occurs:

Procedure WorkerRoutine (const dwerror, Cbtransferred:dword;
Const
lpoverlapped:lpwsaoverlapped; Const Dwflags:dword); stdcall;


It then tells the system to process the received data with the WorkerRoutine function:

WSARecv (M_socket, @FBuf, 1, dwtemp, Dwflag, @m_overlap, workerroutine);


And then...... Nothing Then, the system has done everything to you! Microsoft Real Considerate!

while (not Terminated) do This is what a recv/send thread is going to do ... You don't have to do anything!!!  
Begin
If SleepEx (recv_time_out, True) = Wait_io_completion then//
begin
;
End else
Begin
Continue
End;
End;


Six: IOCP model

Microsoft mailbox seems perfect, old Chen is also very satisfied. But in some big companies the situation is completely different! These big companies have tens of thousands of mailboxes, each with hundreds of letters to deal with, so Microsoft mailbox often crashes due to overloaded operation! Need to reboot! Microsoft had to make a killer ...

Microsoft sent a super robot named "Completion Port" to each big company to get the robot to handle the letters!

The Windows NT team noticed that the performance of these applications was not as high as expected. In particular, handling many simultaneous customer requests means that many threads run concurrently in the system. Because all these threads are operational [not being suspended and waiting for what happens],microsoft realizes that the NT kernel spends too much time translating the context of running threads [context], the threads do not get much CPU time to do their work. You may also feel that the bottleneck of the parallel model is that it creates a new thread for each customer request. Creating a thread is less expensive than creating a process, but it is far from overhead. We might as well imagine: if you open n threads in advance, let them jam in that hold[, then you can post all the user's requests to a message queue. The n threads then remove the message from the message queue and process it. You can avoid threads for every user request. Not only reduce the resources of the thread, but also improve the utilization of the thread. It's good in theory, you want me to wait for a general to come up with a problem, how can Microsoft not consider it? " -----from Nonocast, "Understanding I/O completion Port"

Take a look at the implementation of the IOCP model first:

Create a completion port
Fcompletport: = CreateIoCompletionPort (Invalid_handle_value, 0,0,0);

Accept the remote connection and bind the connected socket handle to the IOCP you just created
Aconnect: = Accept (Flistensock, addr, Len);
CreateIoCompletionPort (Aconnect, Fcompletport, nil, 0);

Number of CPUs created * + 2 threads
For I:=1 to Si.dwnumberofprocessors*2+2 do
Begin
Athread: = Trecvsendthread.create (false);
Athread.completport: = fcompletport;//Tell this thread that you're going to go to this IOCP to access the data
End


Just so simple, all we have to do is build a IOCP, bind the socket handle of the remote connection to the IOCP you just created, create n threads, and tell the N threads to go up to the IOCP to access the data.

And look at what Trecvsendthread threads do:

Procedure Trecvsendthread.execute;
Var
......
Begin
While, not self. Terminated) do
Begin
Querying IOCP status (data read and write operations completed)
GetQueuedCompletionStatus (Completport, BYTESTRANSD, Completkey, poverlapped (Pperiodat), TIME_OUT);

If BYTESTRANSD <> 0 Then
....//Data read/write operation completed
  
Post a read data request again
WSARecv (Completkey, @ pperiodat^. Bufdata), 1, BYTESRECV, Flags, @ (pperiodat^. overlap), nil);
End
End


The read-write thread simply checks to see if the IOCP has completed the read-write operation we posted, and then delivers a new read-write request if it completes.

It should be noted that all of the trecvsendthread we create are accessing the same IOCP (because we have only created one IOCP), and we are not using a critical section! Is there no conflict? Do you need to consider synchronization issues?

That's what IOCP is all about. IOCP is not an ordinary object and does not need to be considered for thread safety issues. It automatically deploys the thread that accesses it: if a socket has a thread A is accessing, then thread B's access request is assigned to another socket. All of this is automatically provisioned by the system, and we don't have to ask.

A total of 3 pages.

Http://www.cnblogs.com/qiubole/archive/2006/03/24/358081.html

Full-contact good of socket I/O model based on Delphi

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.