Teach you to play the SOCKET model overlap I / O
"As a beginner, you can often feel the hardships of beginners. So I always want to take the time to do what I can help those who need help. I also hope that everyone can learn and others. Share together, don't despise others to get greed, because you should not be despised, you should not pay. "
----- Inventive By PiggyXP (Pig)
Forehead
In fact, I should first apologize, because I am in July, I want to write a set of entrance articles about Socket model and the matching code, but I didn't expect to go out to vacation by the beauty of the beauty, just returned. . . . . . -_- b In fact, I have been basically written, but I don't write a set of text, but I think it is a little difficult model, because other models are entitled to be simple.
However, since it is also an initiator, he is still looking forward to it.
This article condenses the author's heart, if you want to reprint, please indicate the original author and the source, thank you! ^ _ ^
OK, Let's Go! Have Fun! ! q ^ _ ^ P
Sample source code download address for this article
(The multi-client MFC code written by VC.NET 2003 is equipped with detailed comments, just a simple display of the characters from the client, and a little improvement is a chat room):
http://www.haha567.com/piggyxp/overlappedmodel.rar
(UNIX system, pay attention to link case)
I am very grateful to the space for the network version of the Limin Brother to provide the space provided by my unpaid, and I am very grateful to him, thank him, thank you, I am grateful ~~~~~ t_t
Also welcome everyone to visit the BLOG to discuss network technology
http://blog.haha567.com/
(This article is assumed to have the ability to program the simple model of Socket, if you don't know if you don't know about this series, please pay attention to this series of other articles)
table of Contents:
1. Advantages of overlapping models
2. Basic principle of overlapping model
3. Basic knowledge about overlapping models
4. Implementation steps for overlapping models
5. Multiple client conditions
One. Advantages of overlapping models
1. You can run all Windows platforms that support Winsock2, and unlike completed ports just support NT systems.
2. Compare the I / O (Overlapped I / O) model to make the application to better system performance than a model such as blocking, select, wsaasyncselect, and WSAEventSelect, and WSAEventSelect, which enables applications to achieve better system performance.
Because it and the four models are different, the application that uses overlapping models notifies the buffer transceiver system directly using data, that is, if the application delivers a 10kb size buffer to receive data, and data has arrived The data will be directly copied to the delivery buffer.
And these four models, data arrive and copy into a single-socket receiving buffer, at which time the application will be informed of the capacity to be read. When the application calls the reception function, the data is copied from a single-set buffer buffer to the application's buffer, and the difference is reflected.
3. You can see in the test results provided in Windows Network Programming, in which P4 is used.
1.7G
Xero processor (CPU is very strong) and 768MB response servers can handle more than 40,000 Socket connections, and the CPU usage is only about 40% when processing 10,000 connections - very good performance, Already completed the port ^ _ ^
two. Basic principle of overlapping model
Said so many benefits, you must also jump, but we still have to mention the basic principles of overlapping models.
Summary, the overlapping model is to allow the application to use the overlapping data structure (WSAOVERLAPPED), deliver one or more WINSOCK I / O requests at a time. For these requests, after they are completed, the application will receive a notification, so you can process these data through your own code. It should be noted that two methods can be used to manage the completion of overlapping IO requests (that is, notification to the overlapping operations):
1. Event object notification
2. Completion routines, pay attention, not completing the port here
This article only tells how to use event notifications to achieve overlapping IO models, and the method of completion routines is ready to put it :) (Too much content, one writing is not finished), if there is no special instructions, The overlapping model of this paper defaults to an overlapping model based on an event notification.
Since it is based on event notifications, the Windows event object is required to associate with the WSAOverlapped structure (there is a corresponding parameter in the WSAOVERLAPPED structure), which is popular, that is. . . . Yes, forgot to say, since it is necessary to use overlapping structure, we often use Send, Sendto, RECV, and Recvfrom is also replaced by Wsasend, Wsasendto, WSARECV, Wsarecvfrom, and their usage I will talk, here only It is necessary to pay attention to a point, there is an overlapped parameter in their parameters. We can assume that the operation of our WSARECV is "bind" to this overlap structure, submit a request, other things will be handed over to overlapping structure And the overlapping structure is "binding" with Windows event object so that we can "enjoy it" after the WSARECV will "share it", wait until the overlapping operation is completed, naturally there will be corresponding events to notify us to do , Then we can take our desired data according to the result of overlapping operations.
Maybe I haven't understood it for a long time, then continue to look back. . . . . . . -_- b, language expressibility is limited ~~~
three. Basic knowledge about overlapping models
Here is to introduce and exemplify several critical functions that will be used in the program to write overlapping models.
WSAOVERLAPPED structure
This structure is naturally the core in the overlapping model, which is called so definition
Typedef struct _wsaoverlapped {
DWORD INTERNAL
DWORD INTERNALH;
DWORD OFFSET;
DWORD OFFSETHIGH;
WSAEVENT HEVENT; / / The only parameter that needs attention to associate WSAEVENT objects
} WSAOVERLAPPED, * LPWSAOVERLAPPED;
We need to deliver WSARECV and other operations to a overlapping structure, and we need an event object "binding" with overlapping structure to inform us to complete the completion of the operation, see and hevent parameters, don't tell you, you should know How to bring the event object to the overlapping structure? Roughly is as follows:
WSAEVENT EVENT; / / Define events
WSAOVERLAPPED ACCEPTOVERLAPPED; / / Define overlapping structure
Event = wsacreateEvent (); // Establish an event object handle
ZeromeMory (& AcceptoverLapped, Sizeof (Wsaoverlapped)); // Initializing overlapping structure acceptoverlapped.hevent = event; // done !!
2. WSARECV Series Function
In the overlapping model, the received data is to rely on it, and its parameters are more than the RECV, because the knife is used to overlap the structure, it is defined:
INT WSARECV (
Socket S, // is of course a socket that delivers this operation
LPWSABUF LPBUFFERS, / / Receive buffer, different from the RECV function
// This requires an array that is composed of a WSABUF structure.
DWord dwbuffercount, // The number of WSABUF structures in the array
LPDWORD LPNUMBEROFBYTESRECVD, // If the receiving operation is complete, you will return a function call here.
// Number of bytes received
LPDWORD LPFLAGS, // said that the length is long, we set it here to 0
LPWSAOVERLAPPED LPOVERLAPPED, / / "Bind" overlap structure
LPWSAOVERLAPPED_COMPLETION_ROUTINE LPCOMPLETIONROUTINE
// The parameters that will be used in the completion routine will be set here as NULL.
);
return value:
WSA_IO_PENDING: The most common return value, which means that our WSARECV operation is successful, but
I / O operation has not been completed, so we need to bind an event to notify us when to do
For example: (the order of the definition of the variable and the order of the above description are corresponding, the same)
Socket S;
WSABUF DATABUF; / / Define buffers for WSABUF structures
// Initialize DataBuf
#define data_bufsize 5096
Char buffer [data_bufsize];
ZeromeMory (buffer, Data_bufsize);
DataBuf.len = DATA_BUFSIZE;
DataBuf.buf = buffer;
DWORD dwbuffercount = 1, dwrecvbytes = 0, FLAGS = 0;
/ / Establish needed overlapping structure
WSAOVERLAPPED Acceptoverlapped; // If you want to handle multiple operations, here is of course a need
// WSAOVERLAPPED array
WSAEVENT Event; // If you want multiple events, here, there is of course a WSAEVENT array
// Need to note is that a socket will have more than one overlap request at the same time.
// will also correspond to more than one WSAEVENT
Event = wsacreateevent ();
ZeromeMory (& AcceptoverLapped, Sizeof (Wsaoverlapped);
Acceptoverlapped.hevent = event; // Key one step, "bind" to the overlapping structure
// Make so much work, I can finally use WSARECV to deliver our request to overlapping structure, call. . . .
WSARECV (S, & DataBuf, dwbuffercount, & dwrecvbytes,
& Flags, & acceptoverlapped, null;
Other functions, I will introduce it here, because we have MSDN so good helper, and I will talk about some ^ _ ^ 3. WSAWAITFORMULTIPEEVENTS function when the completion routine and completion of the port.
Friends who are familiar with the WSAEventSelect model will definitely be unfamiliar with this function. In fact, everyone should not be unfamiliar, this function is still like a WaitFormultiPleObjects function commonly used in the thread, because all are waiting for an event. Trigger.
Because we need events to notify us of the completion of the overlapping operation, it naturally requires the function of this waiting event with it.
DWORD WSAWAITFORMULTIPEEVENTS
DWORD CEVENTS, / / Waiting Events Total Quantity
CONST WSAEVENT * LPHEVENTS, / / Event array pointer
Bool fwaitall, // This should be said more questions:
// If set to True, all events are sent to the event when all events are communicated.
// False, any event is sent to the signal to return
// We must set it to false here.
DWORD DWTIMEOUT, // Timeout, if the timeout, the function returns WSA_WAIT_TIMEOUT
// If set to 0, the function will return immediately
// If set to WSA_INFINITE, only the event will be returned after being sent.
/ / Not recommended here for WSA_INFINITE because. . . Let's talk about it later ..-_- b
Bool falrtable // This parameter will be used in the completion routine, here we set it to false
);
return value:
WSA_WAIT_TIMEOUT: The most common return value, what we need to do is to continue WAIT
WSA_WAIT_FAILD: An error occurred, please check if both CEVENTS and LPHEVENTS are valid.
If an event in an event array is communicated, the function returns the index value of this event, but this index value requires minus predefined values WSA_WAIT_EVENT_0 is the location in the event array.
The specific example will not be held here, and will also say
Note: The WSAWAITFORMULTIPEEVENTS function can only support a maximum of the WSA_Maximum_Wait_Events object, is 64, that is, WSAWAITFORMULTIPEEvents can only wait for 64 events, if you want to wait more than 64 events, you will create additional worker threads, you must Don't manage a thread pool, this is not as follows by the following completion routine model.
4. WsagetoverlappedResult function
Since we can get a notification completed by the WSAWAITFormultipleEvents function, then we naturally need a function to query the result of overlapping operations, defined as follows
Bool WsagetoverlappedResult
Socket S, // Socket, no need to say
LPWSAOVERLAPPED LPOVERLAPPED, / / This is a pointer to the overlapping structure we want to query the result
LPDWORD LPCBTRANSFER, / / / / The number of bytes of actual reception (or send) this overlap operation
Bool fwait, // Set to true unless the overlapping operation is completed, otherwise the function will not return
/ / Set False, and the operation is still in the suspended state, then the function will return false
// Error is WSA_IO_Incomplete
// But because we are waiting for the event to notify us to do this, we set up
// It doesn't have any effects in it ... ..-_- b Don't still egg, I also want to say some ...
LPDWORD LPDWFLAGS / / Pointer to DWORD, responsible for receiving results logo
);
This function is not difficult. We don't need to pay attention to its return value, you can fill in the parameters directly, here will not exist first.
The only thing to pay attention to is if the WSAGETOVERLAPPEDRESULT is complete, the third parameter returns to 0, then the communication other party has closed the connection. The Socket on our side has turned off. four. Steps to achieve overlapping model
I have made so many preparations, and so many pens, we can finally start to encode. In fact, you will understand that you will understand that the internal principles of dialysis of the overlapping structure may be a good job, but just learn how to use it, but it is really not difficult, the only thing that needs to be cleared, it is a lot of In the case of the client interaction, we get the event notification, how to know which overlap operation is completed, then know which socket is handled, which buffer should go to get data, everything Will Be OK ^ _ ^.
Below we cooperate with the code, explain how to handle a overlapping model in step by step.
[First step] Define variables .........
#define data_bufsize 4096 // Receive buffer size
Socket Listensocket, // Listening Socket
Acceptsocket; // Sockets communicating with the client
Wsaoverlapped acceptoverlapped; // overlapping structure
WSAEVENT EVENTARRAY [WSA_MAXIMUM_WAIT_EVENTS];
// Event handle array used to notify overlapping operations
WSABUF DATABUF [DATA_BUFSIZE];
DWORD dweventtotal = 0, // Total number of events in the program
DWRECVBYTES = 0, // Received Character Length
Flags = 0; // WSARECV parameters
[Step 2] Create a socket and start listening to the connection request on the specified port
And other Socket initialization all the whole, direct movement, there is not much lips, you need to pay attention to it, I have dropped the wrong handling, usually don't like this, although the chance of error here is relatively small. .
Wsadata wsadata;
WSASTARTUP (Makeword (2, 2), & WSADATA);
Listensocket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); // Create TCP socket
SockAddr_in ServerAddr; // Assign port and protocols and bind
ServerAddr.sin_Family = AF_INET;
ServerAddr.sin_addr.s_un.s_addr = htonl (INADDR_Any);
ServerAddr.sin_Port = HTONS (11111);
Bind (Listensocket, (LPSOCKADDR) & ServerAddr, SizeOf (ServerAddr)); // Binding Socket
Listen (Listensocket, 5); // Start listening [third step] Accept a connection request
An accept is finished, all is the same as the same, ~~~~~~~~~~
As for the use of Acceptex, I will talk in the completion of the port, here is not so much in turn, it is not digested ^ _ ^
Acceptsocket = accept (listensocket, null, null);
Of course, here is what I lazy, if you want to get a client's information (remember to ask someone on the forum), the last two parameters of Accept do not use null, but this
SockAddr_in clientdr; // Defines a client's address structure as a parameter
Int addr_length = sizeof (clientaddr);
Acceptsocket = accept (listensocket, (sockaddr *) & clientaddr, & addr_length;
// What can we easily learn about the client.
LPCTSTR LPIP = INET_NTOA (ClientAddr.sin_ADDR); // ip
Uint nport = clientaddr.sin_port; // port
[Fourth step] Establish and initialize overlapping structure
To connect this socket, a wsaoverlapped overlapping structure is newly established, as mentioned earlier, picking out an idle object handle "binding" from the event handle array as before.
// Create an event
// DWEventTotal can temporarily act as an index of an EVENT array
EventArray [dweventtotal] = wsacreateevent ();
ZeromeMory (& Acceptoverlapped, Sizeof (Wsaoverlapped); //
Acceptoverlapped.hevent = EventArray [dweventtotal]; // Association event
Char buffer [data_bufsize];
ZeromeMory (buffer, Data_bufsize);
DataBuf.len = DATA_BUFSIZE;
DataBuf.buf = buffer; // Initialize a WSABUF structure
DWEVENTTOAL ; // Total number plus one
[Fifth] The WSAOVERLAPPED structure is parameter, and the WSARECV request is delivered on the socket.
After each variable has initialized OK, we can start Socket operation, then let WSAOverlapped structure manage I / O requests for us, we only use the trigger of the waiting event to be OK.
IF (WSarecv (Acceptsocket, & DataBuf, 1, & Dwrecvbytes, & flags,
& Acceptoverlapped, NULL) == Socket_ERROR)
{
// Returns WSA_IO_PENDING is normal, indicating that the IO operation is in progress, and cannot be completed immediately.
// If it is not a WSA_IO_PENDING error, it is not good ~~~~~~! ! !
IF (wsagetlasterror ()! = WSA_IO_PENDING)
{
// Then you can only turn off the bigjet CloseSocket (ACCEPTSOCKET);
WSACloseEvent (EventArray [dweventtotal]);
}
}
[Step 6] WosawaitFormultiPleEvents function Waiting the result of overlapping operations returned
We have already assigned an event object handle, so we have to wait for the trigger and cooperation of the event object, and need to determine which event in the event array is triggered according to the return value of the WSAWAITFormultiPevents function. The usage and return values of this function refer to the basics part of the previous.
DWORD DWINDEX;
// Waiting for overlapping I / O end
// Because we bind events and overlapped, we will receive event notification after the overlapping operation is complete.
Dwindex = WSAWAITFORMULTIPEEVENTS (DWEventTotal,
EventArray, False, WSA_INFINITE, FALSE;
// Note that INDEX returned here is not an incident in an incorption, but it is necessary to subtract WSA_WAIT_EVENT_0
Dwindex = dwindex - WSA_WAIT_EVENT_0;
[Seventh step] Use the WSARESETEVENT function to reset the current useful event object
After the incident has been triggered, it has not used value for us, so you have to reset it to leave it next time, it is very simple, one step, even return value does not have to consider
WSARESETEVENT (EventArray [dwindex]);
[Eighth Steps] Use the WSAGETOVERLAPPEDRESULT function to get the return status of overlapping calls
This is our most concerned, what is the result of this overlap operation? In fact, for this model, the only thing to check is whether the other party's Socket connection has been closed.
DWORD DWBYTESTRANSFERRED;
WsagetoverlappedResult (Acceptsocket, Acceptoverlapped,
& DWBYTESTRANSFERRED, FALSE, & FLAGS;
// Check if the communication other party has closed the connection
// If == 0 indicates that the connection has been connected, turn off the socket.
IF (DWBYTESTRANSFERRED == 0)
{
CloseSocket (ACCEPTSOCKET);
WSACloseEvent (EventArray [dwindex]); // Close event
Return;
}
[Ninth Step] "Enjoy" received data
If the program executes here, then explain that everything is normal, the WSABUF structure has the data from our WSARECV, and finally the time to enjoy the results! Cup of tea, take a break ~~~ ^ _ ^
DataBuf.buf is a char * string pointer, listen to your handle, I don't say much.
[Chapter 10] Like the fifth step, continue to deliver WSARECV requests on the socket, repeat steps 6 ~ 9
This way, we can finally receive data from the client, but recall it, yeah ~~~~~, is this not only available, then the program is not over? ......-_- b so we have to repeat the work of the fourth steps and fifth steps, and then deliver another WSARECV request on this socket, and make the entire process loop, Are u clear? ?
Everyone can refer to my code, here is not written here, because everyone must be better than me smart, after understanding the key, slightly thinking is flexible. Fives. Multiple client conditions
After completing the above cycle, the overlapping model has basically constructed 80%, why isn't it 100%? Because I think it carefully, it is ~~~~~~~, can I only connect one client? ? Yes, if only one client is processed, the overlapping model is not there, and we are using the overlapping model to handle multiple clients.
So we have to make some changes to the structure.
1. First of all, it is definitely a set of socket arrays, used to communicate with each Socket, respectively.
Secondly, because each Socket operation in the overlap model is to "bind" a overlapping structure, you need to match a WSAOverlapped structure for each Socket operation, but this is not strict, because if every Socket is only one operation For example, wsarecv, then a socket can correspond to a WSAOverlapped structure, but if there is WSARECV and WSasend two operations on a socket, then a socket must correspond to two WSAOVERLAPPED structures, so how many Socket operations will be WSAOVERLAPPED structure.
Then, it is also a WSAEVENT event for each WSAOverlapped structure, so how many WSAEVERLAPPED structures should be said, how many WSAEVENT events should be made, and the SOCKET - WSAOVERLAPPED - The association of three WSAEVENTs, it will not be in danger of critical moments :)
2. Have to divide two threads:
A connection to loop listening ports, receive requests, and then deliver the first WSARECV request on this socket, then deliver the first WSARECV request, and then enter the second thread waiting to be completed.
The second thread is used to keep the WSAEVENT array WSAWAITFORMULTIPEEVENTS, waiting for any overlapping operation, and then processes according to the returned index value, and then continue to deliver another WSARECV request.
It is important to note that, I am setting the parameters of the WSAWAITFORMULTIPEEvents function to WSA_
Infinite, but in multiple clients, it is not OK. You need to set a timeout. If you wait for timeout, you will re-wsawaitFormultiPleevents, because the wsawaitformultipleevents function is blocked when there is no trigger, we can imagine, this If the listening line is entered into a new connection, it will naturally add an EVENT for this connection, but WSAWAITFORMULTIPEEVENTS still blocks it there will be newly connected Event. I don't know if I understand. . . . . . -_- b may not be here, you will understand when you really encode.
Others can also refer to my code, there are more detailed notes in the code, enjoy ~~~
However, it is a pity to take care of most people, use the MFC code, and the code is somewhat mess.
six. Question
This known issue is to say that the known issue in my code is not a known issue of overlapping structure :)
This sample code has been written for a long time. When these two days did the final test, they found that there were two bugs, but not every time, 5555, I recently really didn't have energy to change, if you have a friend It can be modified by these two bugs, it is really benefiting everyone. This article is dangerous. I have not experienced the bug that I have to go to the code. I have to ask for forgetting. I have written here. Let's have you. It's just a throwing brick, and I think it is more precious than the code or the text is more precious ^ _ ^, because the code online of the overlapping model is still a lot. Two bugs are like this: 1. When multiple clients are continuously exit, they sometimes appear;
2. Sometimes the receiving buffers of multiple clients will be overlap together, that is, the data sent by the A client will have the data from the b client to be last time. . . . . -_- b
Improved algorithm: There are still many ways in actual code. Limin friends will mention several very good improvement algorithms to me, such as how to find idle sockets in a socket array, but I don't have Add to this code, because the code that the overlapping model is more comparable, plus these things may bring difficulties to beginners. But very welcome and I discuss the improved algorithm for overlapping models and problems in my code! ^ _ ^
Just say so much, I hope that you can use this article to play the illegal IO model, there is no effort to spend this effort. ^ _ ^
Please look forward to this series of the next article "Hand teaches you to play the SOCKET model" completion routine "
------ Finished in dlut | DIP
--------
2004-09-22