Socket API, casyncsocket, csocket insider and usage

Source: Internet
Author: User
Socket API, casyncsocket, csocket insider and usage [go]
Socket can be used in synchronous blocking mode or asynchronous non-blocking mode. In fact, synchronous and asynchronous may encounter a lot in our programming career, and socket is nothing special. Although synchronization is easy to use, it is not difficult, but it cannot meet the needs of some application scenarios, and its efficiency is also very low.
Maybe programmers at the beginning cannot understand "synchronization (or blocking)" or "Asynchronous (or non-blocking)". In fact, they can clearly explain it in two simple sentences, synchronization and Asynchronization are usually for a function. "synchronous" means that the function is returned only when all the functions to be executed are completed, while "Asynchronous" means that, the function only performs some simple work and then returns immediately. The function to be implemented is left to other threads or functions. For example, sendmessage is the "synchronous" function, which not only sends messages to the message queue, but also needs to wait until the message is executed to return; on the contrary, postmessage is an asynchronous function, which only sends a message, no matter whether the message is processed or not, it will be returned immediately.

I. Socket API
First, you should know that there are original API functions provided by socket1.1, and a set of extension functions provided by socket2.0, two sets of functions. These two functions are repeated, but 2.0 provides more powerful functions and more functions. These two sets of functions can be flexibly mixed, including Winsock. h and winsock2.h in the header files, which must be imported into wsock32.lib and ws2_32.lib respectively.

1. the default method is synchronous blocking, that is, when you never call wsaioctl () or ioctlsocket () to change the socket Io mode, or call wsaasyncselect () and wsaeventselect () to select the socket event to be processed. It is precisely because the functions accept (), wsaaccept (), connect (), wsaconnect (), send (), wsasend (), Recv (), wsarecv () and other functions are used as blocking methods, so you may need to put them in a dedicated thread, so as not to affect the running of the main program and refresh the main window.
2. If it is used asynchronously, the program mainly needs to handle the event. There are two ways to handle events:
First, it is often associated with a window, that is, the asynchronous socket event will be sent as a message to this window, which is implemented by the wsaasyncselect () function in the Winsock extension specification and window Association. In the end, you only need to process window messages to send and receive data.
Second, another event-related function wsaeventselect () in the extended specification is used to handle socket events using event objects. That is, you must first use wsacreateevent () create an event object and call wsaeventselect () to associate the socket event with the event object. In the end, you will use wsawaitformultipleevents () in a thread to wait for the event object to be triggered. This process is also a little complicated.
Ii. 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: // The Levent parameter specifies the socket event you are concerned about.
{
M_hsocket = socket (pf_inet, sock_stream, 0); file: // create the socket itself

Csocketwnd * psockwnd = new csocketwnd; file: // 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); 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 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.

Iii. 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) file: // The socket returns this error because the asynchronous operation takes time and cannot be completed immediately.
{
File: // 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) file: // bblocking is just a sign to see if you have 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 (); file: // process other messages in the Message Queue
Pthread-> onidle (-1 );
}
}
}
Bool csocket: onmessagepending ()
{
MSG;
If (peekmessage (& MSG, null, wm_paint, wm_paint, pm_remove ))
{File: // only the wm_paint message is concerned here to process the repainting 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 ).

Iv. csocketfile
In addition, for socket programming, the csocketfile class cannot be mentioned. In fact, it is not used to send files on both sides of the socket, but to send serialized data, such as some struct data to the other party. In this way, the serialization function of the program's cdocument () can be fully associated with csocketfile. For example, if you have a cmydocument that implements serialize (), you can pass your document data to the other side of the socket as follows:

Csocketfile file (psocket );
Carchive AR (& file, carchive: Store );
Pdocument-> serialize (AR );
Ar. Close ();

Similarly, the receiver can only change the above Code to carchive AR (& file, carchive: load.
Note that although the csocketfile class is derived from cfile, It shields cfile: open () and other functions, and only throws one exception in the function. That is to say, you cannot call the OPEN function of csocketfile to open a real file. Otherwise, exceptions may occur. If you need to use csocketfile to transfer files, you must provide the implementation of these functions in the csocketfile class.
Additionally, carchive does not support serializing data on the socket connection of datav.

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.