MFC socket programming Basics

Source: Internet
Author: User

Casyncsocket
You can see the class name. It is an asynchronous non-blocking Socket encapsulation class. casyncsocket: Create () has a parameter that specifies which socket events you want to handle, after an event is specified, the socket is used as an Asynchronous Method by default. So how does casyncsocket send events to you?
The create () function of casyncsocket not only creates a socket, but also creates a csocketwnd window object, and uses wsaasyncselect () to associate the socket with the window object, so that the window object can process the event (Message) from the socket. However, after csocketwnd receives the socket event, it simply calls back casyncsocket: onreceive (), casyncsocket: onsend (), casyncsocket: onaccept (), casyncsocket: onconnect () and other virtual functions. Therefore, the derived classes of casyncsocket only need to add the sending and receiving code in these virtual functions.

The simplified code is as follows:
Bool casyncsocket: Create (long Levent) // The Levent parameter specifies the socket event you are concerned about.
{
M_hsocket = socket (pf_inet, sock_stream, 0); // create the socket itself
Csocketwnd * psockwnd = new csocketwnd; // create the event response window. The actual window is created when afxsockinit () is called.
Psockwnd-> Create (...);
Wsaasyncselect (m_hsocket, psockwnd-> m_hwnd, wm_socket_notify, Levent); // socket event and window Association
}

Static void Pascal casyncsocket: docallback (wparam, lparam)
{
Casyncsocket socket;
Socket. Attach (socket) wparam); // wparam is the socket handle that triggers this event
Int nerrorcode = wsagetselecterror (lparam); // lparam is the combination of error codes and event codes.
Switch (wsagetselectevent (lparam ))
{
Case fd_read:
Psocket-> onreceive (nerrorcode );
Break;
Case fd_write:
Psocket-> onsend (nerrorcode );
Break;
Case fd_oob:
Psocket-> onoutofbanddata (nerrorcode );
Break;
Case fd_accept:
Psocket-> onaccept (nerrorcode );
Break;
Case fd_connect:
Psocket-> onconnect (nerrorcode );
Break;
Case fd_close:
Psocket-> onclose (nerrorcode );
Break;
}
}

The csocketwnd class is roughly:

Begin_message_map (csocketwnd, cwnd)
On_message (wm_socket_notify, onsocketnotify)
End_message_map ()

Lresult csocketwnd: onsockety y (wparam, lparam)
{
Casyncsocket: docallback (wparam, lparam); // receives the socket event message and calls back the docallback () function of casyncsocket.
Return 0l;
}

However, it is not easy for beginners to understand socket programming. This article also reminds customers that when using casyncsocket: connect, A wsaewouldblock error is often returned (this is also true for some other function calls). In fact, this error is not counted as an error. It is a socket reminder because you use the non-blocking Socket method, therefore, the (connection) operation takes time and cannot be established instantly. In this case, we can wait until the connection is successful, so many programmers just call connect (), sleep (0), and then keep using wsagetlasterror () or casyncsocket:: getlasterror () Check the errors returned by the socket until the return is successful. This is a wrong practice, asserted that you cannot achieve the intended purpose. In fact, we can wait for the casyncsocket: onconnect () event to be triggered after the connect () call. casyncsocket: onconnect () indicates that the socket is successfully connected, or the connection fails completely. So far, after casyncsocket: onconnect () is called, we will know whether the socket connection is successful or fails.
Similarly, if send () returns the wsaewouldblock error, we will wait at onsend (). If receive () returns the wsaewouldblock error, we will wait at onreceive (), and so on.
Another point may be that the customer calls connect () to connect to the service provider, so how does the service provider Access () to establish a connection. When the listening socket receives onaccept (), it uses a new casyncsocket object to establish a connection. For example:

Void cmysocket: onaccept (INT errcode)
{
Cmysocket * psocket = new cmysocket;
Accept (* psocket );
}
Therefore, the above psocket establishes a connection with the customer, and the subsequent communication is the psocket object to be connected with the customer, and the listening socket continues to be monitored, once another customer wants to connect to the service provider, the onaccept () above will be called again. Of course, psocket is the service provider that communicates with the customer. It does not trigger the onaccept () event because it is not a listener socket.

Csocket
Csocket is an encapsulation class of synchronous blocking Socket derived from MFC on the basis of casyncsocket. How does it change casyncsocket to synchronous and respond to the same socket event?
In fact, it is very simple. When csocket returns the wsaewouldblock error in connect (), it does not wait in the onconnect (), onreceive () event terminal functions. You must first understand how socket events arrive in these event functions. These event processing functions are called back by the csocketwnd window object, and the window object receives the event from the socket, which is distributed by the thread message queue. In short, the socket event is first sent to the csocketwnd window object as a message. This message must be distributed by the thread message queue, finally, when the csocketwnd window object receives these messages, it calls the corresponding callback function (onconnect ).
Therefore, after csocket calls connect (), if a wsaewouldblock error is returned, it immediately enters a message loop, that is, it retrieves the messages of interest from the message queue of the current thread, if the wm_paint message is obtained, refresh the window. if the message is received from the socket, call the corresponding callback function (onconnect () based on whether the socket has an operation error code ).
The simplified code is as follows:

Bool csocket: connect (...)
{
If (! Casyncsocket: connect (...))
{
If (wsagetlasterror () = wsaewouldblock) // The socket returns this error because the asynchronous operation takes time and cannot be completed immediately.
{
// Enter the message loop to view the fd_connect message from the thread message queue until the fd_connect message is received and the connection is considered successful.
While (pumpmessages (fd_connect ));
}
}
}
Bool csocket: pumpmessages (uint uevent)
{
Cwinthread * pthread = afxgetthread ();
While (bblocking) // bblocking is just a sign to see if the user has canceled the call to connect ().
{
MSG;
If (peekmessage (& MSG, wm_socket_notify ))
{
If (msg. Message = wm_socket_policy & wsagetselectevent (msg. lparam) = ustopflag)
{
Casyncsocket: docallback (msg. wparam, MSG. lparam );
Return true;
}
}
Else
{
Onmessagepending (); // process other messages in the Message Queue
Pthread-> onidle (-1 );
}
}
}
Bool csocket: onmessagepending ()
{
MSG;
If (peekmessage (& MSG, null, wm_paint, wm_paint, pm_remove ))
{// Here, only the wm_paint message is concerned to process the re-painting of the main window during blocking.
: Dispatchmessage (& MSG );
Return false;
}
Return false;
}

Other csocket functions, such as send (), receive (), and accept (), all enter the pumpmessages () message loop when the wsaewouldblock error is received. This is an asynchronous casyncsocket, the csocket of the derived class is synchronized.
After understanding, we can use csocket freely. For example, some programmers put the csocket operation into a thread to implement multi-thread asynchronous socket (usually, synchronous + multithreading is similar to asynchronous ).

Casyncsocket

Casyncsocket
You can see the class name. It is an asynchronous non-blocking Socket encapsulation class. casyncsocket: Create () has a parameter that specifies which socket events you want to handle, after an event is specified, the socket is used as an Asynchronous Method by default. So how does casyncsocket send events to you?
The create () function of casyncsocket not only creates a socket, but also creates a csocketwnd window object, and uses wsaasyncselect () to associate the socket with the window object, so that the window object can process the event (Message) from the socket. However, after csocketwnd receives the socket event, it simply calls back casyncsocket: onreceive (), casyncsocket: onsend (), casyncsocket: onaccept (), casyncsocket: onconnect () and other virtual functions. Therefore, the derived classes of casyncsocket only need to add the sending and receiving code in these virtual functions.

The simplified code is as follows:
Bool casyncsocket: Create (long Levent) file: // parameter/number Levent is the socket event you are concerned about.
{
M_hsocket = socket (pf_inet, sock_stream, 0); file: // create/create the socket itself

Csocketwnd * psockwnd = new csocketwnd; file: // create/create a window to respond to events. The actual window is created when afxsockinit () is called.
Psockwnd-> Create (...);

Wsaasyncselect (m_hsocket, psockwnd-> m_hwnd, wm_socket_notify, Levent); file: // socket/event and window Association
}

Static void Pascal casyncsocket: docallback (wparam, lparam)
{
Casyncsocket socket;
Socket. Attach (socket) wparam); file: // wparam/is the socket handle that triggers this event
Int nerrorcode = wsagetselecterror (lparam); file: // lparam/is the combination of error codes and event codes.
Switch (wsagetselectevent (lparam ))
{
Case fd_read:
Psocket-> onreceive (nerrorcode );
Break;
Case fd_write:
Psocket-> onsend (nerrorcode );
Break;
Case fd_oob:
Psocket-> onoutofbanddata (nerrorcode );
Break;
Case fd_accept:
Psocket-> onaccept (nerrorcode );
Break;
Case fd_connect:
Psocket-> onconnect (nerrorcode );
Break;
Case fd_close:
Psocket-> onclose (nerrorcode );
Break;
}
}

The csocketwnd class is roughly:

Begin_message_map (csocketwnd, cwnd)
On_message (wm_socket_notify, onsocketnotify)
End_message_map ()

Lresult csocketwnd: onsockety y (wparam, lparam)
{
Casyncsocket: docallback (wparam, lparam); file: // receives/receives the socket event message and calls back the docallback () function of casyncsocket.
Return 0l;
}

However, it is not easy for beginners to understand socket programming. This article also reminds customers that when using casyncsocket: connect, A wsaewouldblock error is often returned (this is also true for some other function calls). In fact, this error is not counted as an error. It is a socket reminder because you use the non-blocking Socket method, therefore, the (connection) operation takes time and cannot be established instantly. In this case, we can wait until the connection is successful, so many programmers just call connect (), sleep (0), and then keep using wsagetlasterror () or casyncsocket:: getlasterror () Check the errors returned by the socket until the return is successful. This is a wrong practice, asserted that you cannot achieve the intended purpose. In fact, we can wait for the casyncsocket: onconnect () event to be triggered after the connect () call. casyncsocket: onconnect () indicates that the socket is successfully connected, or the connection fails completely. So far, after casyncsocket: onconnect () is called, we will know whether the socket connection is successful or fails.
Similarly, if send () returns the wsaewouldblock error, we will wait at onsend (). If receive () returns the wsaewouldblock error, we will wait at onreceive (), and so on.
Another point may be that the customer calls connect () to connect to the service provider, so how does the service provider Access () to establish a connection. When the listening socket receives onaccept (), it uses a new casyncsocket object to establish a connection. For example:

Void cmysocket: onaccept (INT errcode)
{
Cmysocket * psocket = new cmysocket;
Accept (* psocket );
}
Therefore, the above psocket establishes a connection with the customer, and the subsequent communication is the psocket object to be connected with the customer, and the listening socket continues to be monitored, once another customer wants to connect to the service provider, the onaccept () above will be called again. Of course, psocket is the service provider that communicates with the customer. It does not trigger the onaccept () event because it is not a listener socket.

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.