Troubleshooting of MFC: casyncsocket and csocket
MFC fully supports socket programming, but its documentation is not detailed. So that most of the functions written in VC are slightly
Complex network programs still use APIs. As a result, casyncsocket and csocket have become difficult and the masses are far away from each other. Yu
This is a special annotation.
I. Differences between casyncsocket and csocket
The former is asynchronous communication, the latter is synchronous communication, the former is non-blocking mode, and the latter is blocking mode. In addition, the asynchronous non-blocking mode has
The synchronous blocking mode is also called short connection. To better understand the differences between the two, for example:
Imagine that you are a PE Instructor and need to test the 100-meter score of 400 students. Of course, you won't let 100 students start together, because when
When the students return to the endpoint, you have no time to record their scores.
If you start a student every time and wait for him to return to the end, write down the score and then let the next student start until all the students finish running. Gong
Hi, you have mastered the synchronous blocking mode.
You have designed a function. The input parameter is the student ID and start time, and the return value is the time at the end. You call this function 100 times,
This quiz task can be completed. This function is synchronized, because you only need to call it to get the result. This function is also blocked,
Because once you call it, you have to wait until it gives you results and cannot do anything else.
If you start a student every 10 seconds until all the students start, and each student on the other returns to the end, it is recorded
Until all the students finish running. Congratulations, you have mastered the asynchronous non-blocking mode.
You have designed two functions, one of which records the start time and student number. You will call this function 100 times.
Recording arrival time and student number. This function is an event-driven callback function. When a student reaches the end, you call it passively.
The function you call is asynchronous, because you call it, it does not tell you the result; this function is also non-blocking, Because you
Once you call it, it will return immediately, and you can call it again without waiting. But you have not finished calling this function for 100 times.
As your quiz task, you still need to passively wait for 100 calls to another function.
Of course, you will immediately realize that the efficiency of the synchronous blocking mode is significantly lower than that of the asynchronous non-blocking mode. Then, who else will use synchronous blocking?
What about the mode?
Yes, the asynchronous mode is highly efficient, but it is more troublesome. You need to record the data of the Start student while recording the data of the arrival student.
The order in which students return to the destination is not the same as the starting order, so you have to keep searching for student numbers in your book. Busy
You will often wear.
You may come up with a smarter way: you bring a lot of stopwatches and let students group and test each other. Congratulations! You have mastered multiline
Synchronization mode!
Every person with a stopwatch can independently call your synchronization function, which is neither prone to errors nor highly efficient, as long as the stopwatch is sufficient.
More, synchronization efficiency can reach or even exceed asynchronous.
As you can understand, the question may be: is there a need for asynchronous mode since multi-thread synchronization is fast and good?
Unfortunately, the asynchronous mode is still very important, because in many cases, you cannot get a lot of stopwatches. The peer system you need to communicate with May
Only one socket connection is allowed. Many large business systems in the Financial and telecom industries have such requirements.
Now, you should have understood that casyncsocket is used to process a large number of services without step-dependent in a small number of connections. Csocket
It is used to process step-dependent services, or to work with multiple threads when multiple connections are available.
Ii. casyncsocket asynchronous mechanism
After you get an asynchronous connection, you actually remove the dependency between the sending and receiving actions. So you can send packets at any time,
You may receive the package at any time. The sending and receiving functions are both asynchronous and non-blocking functions, so they can be returned immediately. Therefore, the sending and receiving functions are staggered. You can
Keep working and maintain high efficiency. However, because the sending and receiving functions are asynchronous and non-blocking, it is not allowed to call them only.
Ensure the completion of sending or receiving. For example, if the send function is sent, four results may be returned for calling it:
1. error, send () = socket_error, getlasterror ()! = Wsaewouldblock, which may be caused by various network problems
Therefore, you need to immediately decide whether to abandon this operation or enable some countermeasures.
2. Busy, send () = socket_error, getlasterror () = wsaewouldblock. The cause of this situation is that your sending
The buffer has been filled or the recipient's accept buffer has been filled. In this case, you do not need to ignore it immediately. Because casyncsocket will
Remember that your send wsaewouldblock will write the data to be sent to the sending buffer inside casyncsocket, and will be busy
Automatically call onsend to send data in the internal buffer zone.
3. partially completed, 0 <send (pbuf, nlen) <nlen, the cause of this situation is that your sending buffer or recipient's receiving buffer
The remaining space in is insufficient to accommodate all the data you need to send this time. In this case, the usual practice is to continue sending unsent messages.
Data is still completed or wsaewouldblock. This situation is easily confusing. Since the buffer space is insufficient
The sending has already filled up the buffer. Why should we continue sending it? Just like wsaewouldblock, it will be handed over to onsend for processing.
Isn't the sending of residual data more reasonable? However, it is a pity that casyncsocket does not remember that you have completed only part of the sending task and
Onsend is triggered because you do not have wsaewouldblock. You may think that since the buffer has been filled up, continuing to send will inevitably
Wsaewouldblock is actually not the case. If wsaewouldblock is caused by the receiving buffer not timely read by the other party, continue to send
It is possible that wsaewouldblock will be used, but if wsaewouldblock is because the sending buffer is filled up, it is not necessary because you
The speed at which the network adapter processes data in the sending buffer is not necessarily slower than the speed at which you copy data to the sending buffer. This depends on your competition.
CPU, memory, and bandwidth resources. If the CPU load is large and the NIC load is low
The sending buffer is full, and you will not continue sending wsaewouldblock.
4. Complete. Send (pbuf, nlen) = nlen
Like onsend, onrecieve, onconnect, and onaccept will also assist recieve, connect,
Accept. All of this is done through the message mechanism:
Before using casyncsocket, you must call afxsocketinit to initialize the Winsock environment, and afxsocketinit will create
The hidden csocketwnd object, which is derived from cwnd, can receive Windows messages. So it can become a senior
The bridge between the casyncsocket object and the Winsock underlying layer. For example, when a casyncsocket sends wsaewouldblock, it will
Send a message to csocketwnd as a report. csocketwnd maintains a report registration form when it receives
When a message is idle, the report registration form is retrieved and the onsend function of the reporter is called directly. So casyncsocket will
The automatic onxxx call is actually incorrect. The real caller is csocketwnd-it is a cwnd object and runs on an independent line.
.
When casyncsocket is used, the send process and recieve process are different. If you do not understand this, it is impossible to use casyncsocket smoothly.
Msdn's explanation of casyncsocket makes it easy for you to understand that only when onsend is triggered can you send the message. You should send the message,
Similarly, You Should recieve only when onrecieve is triggered. Unfortunately, you are wrong:
You will find that onsend is triggered for the first time when the connection is established. Well, this is good, but you do not want to send it now.
Return, do other things, wait for the next onsend to try? In fact, you can no longer wait until onsend is triggered. Because,
Except for the first time, any onsend trigger is because you have called send, but you have encountered wsaewouldblock!
Therefore, when casyncsocket is used, the process logic for sending should be: you need two member variables, one sending task table and one
Record the sending progress. You can, or you should, actively call send to send data whenever you need it, and update the task table and
Sending progress. Onsend is your assistant responsible for wiping your ass. What it will do when triggered is based on the task table and sending
Progress call send to continue sending. If you fail to send all the task tables, update the sending progress and exit. Wait for the next onsend. If
If all task tables have been sent, the task table and sending progress are cleared.
The logic of the receiving process using casyncsocket is different: you never need to actively call recieve, you should only be in the onrecieve Medium
Wait. Since it is impossible for you to know the data type and order to arrive, you need to define a received data table as a member variable to store it.
Data that has been received but has not been processed. Every time onrecieve is triggered, you only need to passively call recieve once to accept data of a fixed length,
And add it to your received data table. Then you need to scan the received data table. If one or more complete parsed services exist
The data packet is intercepted, and the processing function of the business processing window is called to process the data packet or send it to the business processing window as a message parameter. Only collect
The remaining data in the data table will be combined, scanned, and processed in the next onrecieve.
In persistent connection applications, the connection may be interrupted for various reasons, so you need to automatically reconnect. You need to change
M_hsocket is used to determine the current connection status: If (m_hsocket = invalid_socket ). Of course, it is strange that even if the connection has
Interrupt, onclose has also been triggered, you still need to actively call close in onclose, otherwise m_hsocket will not be automatically assigned
Is invalid_socket.
In many persistent connection applications, in addition to establishing a connection, you also need to log in before you can perform business processing. Connection and login are a step.
In the process of transient dependency, processing in asynchronous mode is troublesome, while casyncsocket supports switching to synchronous mode.
When appropriate, switch to the same asynchronous mode:
DWORD dw;
// Switch to synchronization mode
DW = 0;
IOCTL (fionbio, & DW );
...
// Switch back to asynchronous mode
DW = 1;
IOCTL (fionbio, & DW );
Iii. csocket usage
On the basis of casyncsocket, csocket modifies the send, recieve and other member functions to help you build a built-in round robin buffer for sending and receiving.
To the synchronous short connection mode.
The short connection application is simple and clear. csocket can be directly used without Derivation, but there are also some problems:
1. When used as a listener
We once saw someone creating a thread on their own, creating a csocket object in the thread for listen and accept. If the accept is successful, start another line.
... It can be said that he does not understand csocket at all. In fact, the csocket listening mechanism has a built-in multi-thread machine.
You only need to derive from csocket, and then reload onaccept:
// Clistensocket header file
Class clistensocket: Public csocket
{
Public:
Clistensocket (hwnd = NULL );
Hwnd m_hwnd; // event processing window
Virtual void onaccept (INT nerrorcode );
};
// Clistensocket implementation file
# Include "listensocket. H"
Clistensocket: clistensocket (hwnd) {m_hwnd = hwnd ;}
Void clistensocket: onaccept (INT nerrorcode)
{
Sendmessage (m_hwnd, wm_socket_msg, socket_clnt_accept, 0 );
Csocket: onaccept (nerrorcode );
}
// Main thread
...
M_plistensocket = new clistensocket (m_hwnd );
M_plistensocket-> Create (...);
M_plistensocket-> listen ();
...
Lresult cxxxdlg: onsocketmsg (wparam, lparam)
{
Uint type = (uint) wparam;
Switch (type)
{
Case socket_clnt_accept:
{
Csocket * psocket = new csocket;
If (! M_plistensocket-> Accept (* psocket ))
{
Delete psocket;
Break;
}
...
}
...
}
}
2. Used for Multithreading
It is often said that csocket cannot be used in sub-thread, but it is not. The actual situation is:
Directly use a csocket dynamically created object and pass its pointer as a parameter to the sub-thread. All operations such as sending and receiving are performed in the sub-thread.
No problem. However, if the object is created using the csocket derived class, it depends on the methods you have overloaded. If you only reload onclose,
You can also send and receive data normally in the Child thread, but you cannot close it!
Because csocket uses internal loops for synchronization and does not depend on onxxx, it does not need to interact with csocketwnd. But when you export both
After onxxx is loaded, it must interact with csocketwnd to provide a message mechanism. When you call afxsocketinit, your main thread will get
Obtain a csocketwnd access handle. Access to csocketwnd is automatically completed by MFC and hidden. And you create
The sub-thread does not automatically have the mechanism to access csocketwnd. Therefore, all operations that need to access csocketwnd in the sub-thread will fail.
The solution is to pass the socket handle to the sub-thread instead of the csocket Object Pointer, and then create a csocket temporary
Object and attach the incoming handle. after use, dettach and delete the temporary object. I have never done this, probably because of the attach method.
Contains built-in functions for obtaining csocketwnd handles.
Your solution still uses custom messages. For example, if you cannot close the sub-thread, you can send a message to the main thread,
It is convenient for the message processing function of the main thread to complete close.
Csocket is generally used with multiple threads. If you want to send and receive data, you can create a csocket object and create a sub-thread
For sending and receiving. Therefore, only the subthread is blocked, and the main thread can always create a subthread at any time to help it work. Because there may be many
Multiple csocket objects are working. Therefore, you need to create a list to store the IDs of these csocket objects.
Retrieve the identifier in the list to identify each csocket object. Of course, because of the uniqueness of the memory address, the object pointer itself can be used as the identifier.
Compared with casyncsocket, The csocket operation process is more intuitive and simple.
Address: http://blog.csdn.net/gxj1680/article/details/3715337