An example of non-blocking network programming in the ACL communication library

Source: Internet
Author: User

I. Overview

The AIO module of the C library (lib_acl) of the ACL library designs a complete non-blocking asynchronous Io communication process, in the C ++ library of the ACL (lib_acl_cpp) the asynchronous communication function is encapsulated and enhanced. This article mainly describes the design and usage of the non-blocking Io library in the acl c ++ library. the design idea of this asynchronous stream is as follows: asynchronous stream class and asynchronous stream interface class, in which the asynchronous stream Class Object completes the network set interface listening, connection, and read/write operations, asynchronous stream interface objects define interfaces such as network read/write success/timeout callback, connection success callback, and receiving client connection callback. During asynchronous programming, first, you must implement the pure method defined in the interface class, and then register the interface class object in the asynchronous Stream object, in this way, the asynchronous framework of acl_cpp automatically calls user-defined interface methods when the callback conditions of interface objects are full.

Shows the class continuation relationship of asynchronous streams in acl_cpp:

It can be seen that the basic class aio_stream defines basic methods such as stream close, registration/Cancellation stream close callback, and stream timeout callback; aio_istream and aio_ostream define the basic methods for asynchronous stream reading and writing. aio_istream contains methods for adding/deleting callback interface objects of successful stream reading, aio_ostream contains methods for adding/deleting callback interface objects for successful stream writing; aio_socket_stream class objects are client streams after successful connection to the server, or the server receives client connection streams created by client connections, the method defined as the method for remote connection when connecting the stream and the method for adding the callback interface for successful connection; The aio_listen_stream class is the listener stream class, the method is defined to listen to a network address (or the domain set interface address in UNIX), and to register a method for receiving a successful interface.

The relationships between acl_cpp asynchronous stream interface class inheritance are as follows:

In the design of the asynchronous stream interface class: aio_accept_callback is the callback interface class of the listening stream. The user should inherit this class to obtain the connection stream from the external client, and also need to define the class inherited from aio_callback, used to obtain results such as network read/write operations. aio_open_callback is used only when the client is connected to a remote server.

Ii. Instances

1. Asynchronous Server

# Include <iostream> # include <assert. h> # include "aio_handle.hpp" # include "aio_istream.hpp" # include "aio_listen_stream.hpp" # include "aio_socket_stream.hpp" using namespace ACL; /*** subclass of callback class of asynchronous client stream */class io_callback: Public aio_callback {public: io_callback (aio_socket_stream * client): client _ (client), I _ (0) {}~ Io_callback () {STD: cout <"delete io_callback now... "<STD: Endl;}/*** implements virtual functions in the parent class, callback process for successful reading of client stream * @ Param data {char *} data address * @ Param Len {int} Data Length * @ return {bool} return true to continue, otherwise, you want to disable the asynchronous stream */bool read_callback (char * data, int Len) {I _ ++; if (I _ <10) STD :: cout <"> gets (I:" <I _ <"):" <data; // If the remote client wants to exit, if (strncasecmp (data, "quit", 4) = 0) {client _-> Format ("Bye! \ R \ n "); client _-> close () ;}// if the remote client wants the server to be disabled, the asynchronous event process else if (strncasecmp (data, "Stop", 4) = 0) {client _-> Format ("Stop now! \ R \ n "); client _-> close (); // close Remote Asynchronous stream // notify asynchronous engine to close the loop process client _-> get_handle (). stop () ;}// return the received data client _-> write (data, Len); Return (true );} /*** implement the virtual function in the parent class. The callback process for successful write of the client stream * @ return {bool} returns true to continue, otherwise, you want to disable the asynchronous stream */bool write_callback () {return (true);}/*** to implement the virtual function in the parent class, client stream timeout callback process */void close_callback () {// The dynamically allocated callback class object must be deleted here to prevent memory leakage Delete this ;} /*** implement the virtual function in the parent class. The timeout callback process of the client stream * @ return {bool} returns true to continue. Otherwise, you want Close the asynchronous stream */bool timeout_callback () {STD: cout <"timeout... "<STD: Endl; Return (true);} PRIVATE: aio_socket_stream * client _; int I _;}; /*** subclass of callback class for asynchronous listening stream */class io_accept_callback: Public aio_accept_callback {public: io_accept_callback (){}~ Io_accept_callback () {printf ("> io_accept_callback over! \ N ");}/*** base class virtual function, when a new connection arrives, call this callback process * @ Param client {aio_socket_stream *} asynchronous client stream * @ return {bool} returns true to notify the listener stream to continue listening */bool accept_callback (aio_socket_stream * client) {// create a callback object for the asynchronous client stream and bind it with the asynchronous stream io_callback * callback = new io_callback (client ); // register the asynchronous stream read callback process client-> add_read_callback (callback); // register the asynchronous stream write callback process client-> add_write_callback (callback ); // register the callback process for closing asynchronous streams client-> add_close_callback (callback); // register the callback process for asynchronous streams Client-> add_timeout_callback (callback) in the callback process; // read a row of data from the asynchronous stream client-> gets (10, false); Return (true );}}; int main (INT argc, char * argv []) {// initialize the ACL Library (this function must be called especially in Win32, but not on UNIX platforms) acl_cpp_init (); // construct an asynchronous engine Class Object aio_handle handle (engine_kernel); // create a listening asynchronous stream aio_listen_stream * sstream = new aio_listen_stream (& handle ); const char * ADDR = "127.0.0.1: 9001"; // listen to the specified address if (sstream-> open (ADDR) = false) {STD: cout <"Ope N "<ADDR <" error! "<STD: Endl; sstream-> close (); // XXX: to ensure that the listening stream can be closed, check handle again. check (); getchar (); Return (1) ;}// creates a callback Class Object. When a new connection is established, io_accept_callback callback is automatically called; sstream-> add_accept_callback (& callback); STD: cout <"Listen:" <ADDR <"OK! "<STD: Endl; while (true) {// if false is returned, it indicates that the operation will not continue. Exit if (handle. check () = false) {STD: cout <"aio_server stop now... "<STD: Endl; break;} // close the listening stream and release the stream object sstream-> close (); // XXX: to ensure that the listening stream can be disabled, check handle again here. check (); Return (0 );}

The basic idea of the above Code is as follows:

A) create an asynchronous communication framework object aio_handle --> Create an asynchronous listening stream aio_listen_stream and register the callback Class Object io_accept_callback --> enter the event loop of the asynchronous communication framework;

B) After receiving the client connection, the asynchronous Framework calls back the accept_callback interface of the io_accept_callback Class Object and inputs the client asynchronous stream --> creates an asynchronous stream interface class object, and register the object to the client asynchronous Stream object;

C) when the client asynchronous stream receives data, it calls back the read_callback method in the asynchronous stream interface --> write back to receive data to the client; when the client stream connection is closed, it calls back close_callback In the asynchronous stream interface --> if this interface class object is dynamically created, you need to manually delete it; when the received client data times out, the time_callback In the asynchronous stream interface is called back. If this function returns true, it indicates that you want the asynchronous framework not to close the asynchronous stream of the client; otherwise, it is disabled.

Pure virtual function of the interface class for asynchronous stream listening: Virtual bool accept_callback (aio_socket_stream * client) must be implemented by a subclass. The subclass obtains the client-connected asynchronous Stream object in this function.

The asynchronous client stream interface class aio_callback has four virtual functions:

A) virtual bool read_callback (char * data, int Len) callback virtual function when the client asynchronously reads data;

B) virtual bool write_callback () callback virtual function after the client asynchronously writes data;

C) virtual void close_callback () callback virtual function when the asynchronous stream (client stream or listener stream) is disabled;

D) virtual bool timeout_callback () the callback function virtual function when the asynchronous stream (client stream reading and writing times out or the listening stream times out in the listener) times out.

2. asynchronous Client

# Include <iostream> # include <assert. h> # include "string. HPP "# include" util. HPP "# include" aio_handle.hpp "# include" acl_cpp_init.hpp "# include" handler "# ifdef Win32 # ifndef snprintf # define snprintf _ snprintf # endif # endifusing namespace ACL; typedef struct {char ADDR [64]; aio_handle * handle; int connect_timeout; int read_timeout; int nopen_limit; int nopen_total; int nwrite_limit; int nwrite_total; Int nread_total; int id_begin; bool debug;} io_ctx; static bool connect_server (io_ctx * CTX, int ID ); /*** client asynchronous connection stream callback function class */class client_io_callback: Public aio_open_callback {public: /*** constructor ** @ Param CTX {io_ctx *} * @ Param client {aio_socket_stream *} asynchronously connects the stream * @ Param ID {int} ID of the current stream */client_io_callback (io_ctx * CTX, aio_socket_stream * client, int ID): client _ (client), CTX _ (CTX), nwrite _ (0), ID _ (ID ){} ~ Client_io_callback () {STD: cout <"> ID:" <ID _ <", io_callback deleted now! "<STD: Endl;}/*** base class virtual function, when an asynchronous stream reads the required data, call this callback function * @ Param data {char *} to read the data address * @ Param Len {int} to read the data length * @ return {bool} returns true to the caller, indicating that the request continues, otherwise, the asynchronous stream */bool read_callback (char * data, int Len) {(void) data; (void) Len; CTX _-> nread_total ++; if (CTX _-> Debug) {If (nwrite _ <10) STD: cout <"gets (" <nwrite _ <"):" <data; else if (nwrite _ % 2000 = 0) STD: cout <"> ID:" <ID _ <", I:" <nwrite _ <<";" <Data ;}// if you receive an Exit message from the server, you should also exit if (ACL: strncasecmp _ (data, "quit", 4) = 0) {// send data client _-> Format ("Bye! \ R \ n "); // close the asynchronous stream Connection Client _-> close (); Return (true);} If (nwrite _> = CTX _-> nwrite_limit) {If (CTX _-> Debug) STD: cout <"ID:" <ID _ <", nwrite:" <nwrite _ <", nwrite_limit: "<CTX _-> nwrite_limit <", quiting... "<STD: Endl; // client _-> Format (" Quit \ r \ n "); client _-> close ();} else {char Buf [256]; snprintf (BUF, sizeof (BUF), "Hello World: % d \ n", nwrite _); client _-> write (BUF, (INT) strlen (BUF )); // Send data to the server // client _-> Format ("Hello World: % d \ n", nwrite _) ;}return (true );} /*** base-class virtual function. This callback function is called when asynchronous stream write is successful * @ return {bool} returns true to the caller to continue, otherwise, the asynchronous stream */bool write_callback () {CTX _-> nwrite_total ++; nwrite _ ++; // read a row of data from the server client _-> gets (CTX _-> read_timeout, false); Return (true) ;}/ *** basic class virtual functions, call this callback function when the asynchronous stream is closed */void close_callback () {If (client _-> is_opened () = false) {STD: cout <"ID: "<ID _ <" Connect "<CTX _-> ADDR <" error: "<ACL: last_serror (); // if the connection fails for the first time, exit if (CTX _-> nopen_total = 0) {STD: cout <", first connect error, quit";/* to obtain the asynchronous engine handle, and set it to exit */client _-> get_handle (). stop ();} STD: cout <STD: Endl; Delete this; return ;} /* obtain the number of monitored asynchronous streams in the asynchronous engine */INT nleft = client _-> get_handle (). length (); If (CTX _-> nopen_total = CTX _-> nopen_limit & nleft = 1) {STD: cout <"ID: "<ID _ <" Stop now! Nstream: "<nleft <STD: Endl;/* obtain the asynchronous engine handle and set it to exit */client _-> get_handle (). stop () ;}// the dynamically allocated callback class object must be deleted here to prevent memory leakage Delete this;}/*** basic class virtual functions, when an asynchronous stream times out, call this function * @ return {bool} and return it to the caller "true". Otherwise, the asynchronous stream */bool timeout_callback () {STD :: cout <"Connect" <CTX _-> ADDR <"timeout... "<STD: Endl; client _-> close (); Return (false);}/*** base class virtual function, after the asynchronous connection is successful, call this function * @ return {bool} and return it to the caller "true". Otherwise, the asynchronous stream needs to be closed */ Bool open_callback () {// connection successful, set the IO read/write callback function client _-> add_read_callback (this); client _-> add_write_callback (this ); CTX _-> nopen_total ++; ACL: assert _ (ID _> 0); If (CTX _-> nopen_total <CTX _-> nopen_limit) {// start the next connection process if (connect_server (CTX _, ID _ + 1) = false) STD: cout <"Connect error! "<STD: Endl;} // asynchronously sends data to the server // client _-> Format (" Hello World: % d \ n ", nwrite _); char Buf [256]; snprintf (BUF, sizeof (BUF), "Hello World: % d \ n", nwrite _); client _-> write (BUF, (INT) strlen (BUF); // asynchronously reads a row of data from the server client _-> gets (CTX _-> read_timeout, false ); // return (true);} protected: Private: aio_socket_stream * client _; io_ctx * CTX _; int nwrite _; int ID _;}; static bool connect_server (io_ctx * CTX, int ID) {// open Start asynchronous connection to remote server aio_socket_stream * stream = aio_socket_stream: open (CTX-> handle, CTX-> ADDR, CTX-> connect_timeout); If (Stream = NULL) {STD:: cout <"Connect" <CTX-> ADDR <"error! "<STD: Endl; STD: cout <" stoping... "<STD: Endl; If (ID = 0) CTX-> handle-> stop (); Return (false );} // client_io_callback * callback = new client_io_callback (CTX, stream, ID); // The callback function class stream> add_open_callback (callback) after the connection is created ); // stream-> add_close_callback (callback); // adds stream-> add_timeout_callback (callback); Return (true );} int main (INT argc, char * argv []) {bool use_kernel = false; int ch; io_ctx CTX; memset (& CTX, 0, sizeof (CTX); CTX. connect_timeout = 5; CTX. nopen_limit = 10; CTX. id_begin = 1; CTX. nwrite_limit = 10; CTX. DEBUG = false; snprintf (CTX. ADDR, sizeof (CTX. ADDR), "127.0.0.1: 9001"); acl_cpp_init (); aio_handle handle (engine_kernel); CTX. handle = & handle; If (connect_server (& CTX, CTX. id_begin) = false) {STD: cout <"enter any key to exit. "<STD: Endl; getchar (); Return (1);} STD: cout <" Connect "<CTX. ADDR <"... "<STD: Endl; while (true) {// if false is returned, it indicates that the operation will not continue. Exit if (handle. check () = false) break;} return (0 );}

The basic process of the asynchronous client is as follows:

A) create an asynchronous framework object aio_handle --> asynchronously connect to a remote server, create a connection success/failure/timeout asynchronous Interface Class Object and register it in the asynchronous connection stream --> asynchronous framework in the event loop;

B) after the connection is successful, open_callback In the asynchronous Interface Class Object is called to start the next asynchronous connection process (before the maximum number of connections is reached) --> Add callback interfaces for asynchronous reading and asynchronous writing --> write data asynchronously and start the asynchronous data reading process;

C) when the client asynchronous stream receives data, it calls back the read_callback method in the asynchronous stream interface --> write back to receive data to the client; when the client stream connection is closed, it calls back close_callback In the asynchronous stream interface --> if this interface class object is dynamically created, you need to manually delete it; when the received client data times out, the time_callback In the asynchronous stream interface is called back. If this function returns true, it indicates that you want the asynchronous framework not to close the asynchronous stream of the client; otherwise, it is disabled.

Virtual bool open_callback (), a pure virtual function of the client's asynchronous stream connection interface class aio_open_callback, must be implemented by a subclass. This function is called after the connection to the server is successful, allowing the subclass to perform further operations in this function, for example, register the asynchronous read callback Interface Class Object of the client stream and the asynchronous write callback class object. If the connection is closed due to a timeout or connection failure, the timeout_callback () in the basic Interface Class () or close_callback () will be called to notify the user of the application.

Iii. Summary

The preceding example demonstrates the basic process of non-blocking asynchronous stream listening, reading/writing, and connection. The class design also provides basic operation methods. In order to cope with the diversity and complexity in practice, the asynchronous stream of acl_cpp also designs more interfaces and methods, such as delayed read/write operations (which are useful for throttled servers) and timer operations. You can download a copy of the complete ACL Framework library from the address below: https://sourceforge.net/projects/acl/

Non-blocking client instance: lib_acl_cpp \ samples \ aio_client

Non-blocking server instance: lib_acl_cpp \ samples \ aio_server

Personal microblog: http://weibo.com/zsxxsz

ACL download: http://sourceforge.net/projects/acl/

QQ group: 242722074

 

An example of non-blocking network programming in the ACL communication library

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.