Ace reactor mode (2)

Source: Internet
Author: User

In socket programming, common events are "Read-ready" and "Write-ready". asynchronous operations in the socket can be implemented by capturing and distributing these two events.

Event processor in socket programming

As we have mentioned earlier, in the ace reactor framework, everything must be derived from the ace_event_handler class, and the corresponding event processing function will be called by reloading it to implement corresponding callback processing. In socket programming, we usually need to reload the functions

  1. Handle_input ()
    When input on an I/O handle (such as a file descriptor in UNIX) is available, the reactor automatically calls back this method.
  2. Handle_output ()
    When the output queue of the I/O device has available space, the reactor automatically calls back this method.
  3. Handle_close ()
    Called when an event in the event processor is removed from the reactor.

In addition, to enable the reactor to find the corresponding event processor through the I/O handle, it must also reload its get_handle () method to enable the reactor to establish an association between the I/O handle and event processor.

Use the reactor framework.

Next we will take a client program as an example to introduce how to use the reactor framework in socket programming.

1. Create a client object (event processor ).

The client object is an event processor and its declaration is as follows:

Class client: Public ace_event_handler
{
Public:
Ace_handle get_handle (void) const;
Int handle_input (ace_handle FD );
Int handle_close (ace_handle handle,
Ace_reactor_mask close_mask );
Ace_sock_stream & peer ();
PRIVATE:
Ace_sock_stream peer;
};

On the client side, I only care about the "Read-ready" event, so I only need to overload the handle_input function (in most applications, I only need to overload the handle_input function ). In addition, the client also saves a peer object named ace_sock_stream for socket communication, and encapsulates a peer () function to return its reference.

2. Reload the corresponding callback Handler

Ace_sock_stream & client: Peer ()
{
Return peer;
}

Ace_handle client: get_handle (void) const
{
Return peer. get_handle ();
}

Int client: handle_input (ace_handle FD)
{
Int REV = 0;
If (REV = peer. Recv (buffer, 1000)> 0)
{
Buffer [rev] = '\ 0 ';
Cout <Endl <"Rev: \ t" <buffer <Endl;
Return 0;
}
Else // socket connection error.-1 is returned. log off the event in the reactor and trigger the handle_close function.
{
Return-1;
}
}

Int client: handle_close (ace_handle handle,
Ace_reactor_mask close_mask)
{
Cout <Endl <"connecetd closed ";
Return ace_event_handler: handle_close (handle, close_mask );
}

The functions of several functions are very simple. I will not introduce them here.

3. register events in Reactor

First, let's take a look at the code of the corresponding main function:

Int main (INT argc, char * argv [])
{
Client client;
Ace_sock_connector conne;
Ace_inet_addr ADDR (3000, "127.0.0.1 ");
Ace_time_value timeout (5, 0 );
If (connector. Connect (client. Peer (), ADDR, & timeout )! = 0)
{
Cout <Endl <"connecetd fail ";
Return 0;
}

Ace_reactor: instance ()-> register_handler (& client, ace_event_handler: read_mask );

While (true)
{
Ace_reactor: instance ()-> handle_events ();
}

Return 0;
}

We can see that after using the reactor framework, we still use the connect function of ace_sock_connector to establish a connection. After the connection is established, you can use the ace_reactor: instance ()-> register_handler function to register the reactor, and associate the I/O event with the handle_input method of the client object, the first parameter is the address of the event processor, and the second parameter is the event type. Because only the read-ready event is concerned, the registered event type is ace_event_handler: read_mask.

4. Start reactor event Loop

After the preceding settings, we can use ace_reactor: instance ()-> handle_events () to start the reactor loop. In this way, whenever the server sends data to the client, when the client data is ready, the handle_input function of the client object is triggered to print the received data.

Generally, the reactor event loop is processed as a separate thread, so that the main function is not blocked.

5. log out of the reactor event

There are two methods for canceling a reactor event: explicit and implicit. The following describes how to cancel a reactor event.

  1. Implicit logout.
    After a reactor captures an event, the corresponding "handle _" processing function is triggered. If the return value of the "handle _" processing function is greater than or equal to 0, the event is successfully processed, when the return value is less than 0, the event processing fails. At this time, the reactor will automatically cancel all events registered with the handle and trigger the handle_close function to clear the corresponding resources.
    In this example, when the Recv function in the handle_input function receives 0, it indicates that the socket has an error (most of which are socket connection interruptions), and-1 is returned, the system automatically logs out the corresponding event.
  2. Display logout.
    Call the remove_handler method of the reactor object to remove it. It has two parameters: the first is the registered event reactor object, and the second is the event to be deregistered.

In this example, the connector has only one socket connection, and the reactor's advantages are not shown, but in some network management systems, the connection provider needs to connect multiple devices (servers) to be managed. In this case, the reactor mode is used, you only need to open one reactor event loop thread to achieve multi-channel event distribution and reuse without blocking. It is very convenient to use through object-oriented callback management.

Another common feature of the reactor framework is the server. Generally, a server corresponds to multiple clients. In this way, the reactor mode can greatly improve the concurrency, this programming method will be introduced in the next chapter.

In socket programming, common events are "Read-ready" and "Write-ready". asynchronous operations in the socket can be implemented by capturing and distributing these two events.

Event processor in socket programming

As we have mentioned earlier, in the ace reactor framework, everything must be derived from the ace_event_handler class, and the corresponding event processing function will be called by reloading it to implement corresponding callback processing. In socket programming, we usually need to reload the functions

  1. Handle_input ()
    When input on an I/O handle (such as a file descriptor in UNIX) is available, the reactor automatically calls back this method.
  2. Handle_output ()
    When the output queue of the I/O device has available space, the reactor automatically calls back this method.
  3. Handle_close ()
    Called when an event in the event processor is removed from the reactor.

In addition, to enable the reactor to find the corresponding event processor through the I/O handle, it must also reload its get_handle () method to enable the reactor to establish an association between the I/O handle and event processor.

Use the reactor framework.

Next we will take a client program as an example to introduce how to use the reactor framework in socket programming.

1. Create a client object (event processor ).

The client object is an event processor and its declaration is as follows:

Class client: Public ace_event_handler
{
Public:
Ace_handle get_handle (void) const;
Int handle_input (ace_handle FD );
Int handle_close (ace_handle handle,
Ace_reactor_mask close_mask );
Ace_sock_stream & peer ();
PRIVATE:
Ace_sock_stream peer;
};

On the client side, I only care about the "Read-ready" event, so I only need to overload the handle_input function (in most applications, I only need to overload the handle_input function ). In addition, the client also saves a peer object named ace_sock_stream for socket communication, and encapsulates a peer () function to return its reference.

2. Reload the corresponding callback Handler

Ace_sock_stream & client: Peer ()
{
Return peer;
}

Ace_handle client: get_handle (void) const
{
Return peer. get_handle ();
}

Int client: handle_input (ace_handle FD)
{
Int REV = 0;
If (REV = peer. Recv (buffer, 1000)> 0)
{
Buffer [rev] = '\ 0 ';
Cout <Endl <"Rev: \ t" <buffer <Endl;
Return 0;
}
Else // socket connection error.-1 is returned. log off the event in the reactor and trigger the handle_close function.
{
Return-1;
}
}

Int client: handle_close (ace_handle handle,
Ace_reactor_mask close_mask)
{
Cout <Endl <"connecetd closed ";
Return ace_event_handler: handle_close (handle, close_mask );
}

The functions of several functions are very simple. I will not introduce them here.

3. register events in Reactor

First, let's take a look at the code of the corresponding main function:

Int main (INT argc, char * argv [])
{
Client client;
Ace_sock_connector conne;
Ace_inet_addr ADDR (3000, "127.0.0.1 ");
Ace_time_value timeout (5, 0 );
If (connector. Connect (client. Peer (), ADDR, & timeout )! = 0)
{
Cout <Endl <"connecetd fail ";
Return 0;
}

Ace_reactor: instance ()-> register_handler (& client, ace_event_handler: read_mask );

While (true)
{
Ace_reactor: instance ()-> handle_events ();
}

Return 0;
}

We can see that after using the reactor framework, we still use the connect function of ace_sock_connector to establish a connection. After the connection is established, you can use the ace_reactor: instance ()-> register_handler function to register the reactor, and associate the I/O event with the handle_input method of the client object, the first parameter is the address of the event processor, and the second parameter is the event type. Because only the read-ready event is concerned, the registered event type is ace_event_handler: read_mask.

4. Start reactor event Loop

After the preceding settings, we can use ace_reactor: instance ()-> handle_events () to start the reactor loop. In this way, whenever the server sends data to the client, when the client data is ready, the handle_input function of the client object is triggered to print the received data.

Generally, the reactor event loop is processed as a separate thread, so that the main function is not blocked.

5. log out of the reactor event

There are two methods for canceling a reactor event: explicit and implicit. The following describes how to cancel a reactor event.

  1. Implicit logout.
    After a reactor captures an event, the corresponding "handle _" processing function is triggered. If the return value of the "handle _" processing function is greater than or equal to 0, the event is successfully processed, when the return value is less than 0, the event processing fails. At this time, the reactor will automatically cancel all events registered with the handle and trigger the handle_close function to clear the corresponding resources.
    In this example, when the Recv function in the handle_input function receives 0, it indicates that the socket has an error (most of which are socket connection interruptions), and-1 is returned, the system automatically logs out the corresponding event.
  2. Display logout.
    Call the remove_handler method of the reactor object to remove it. It has two parameters: the first is the registered event reactor object, and the second is the event to be deregistered.

In this example, the connector has only one socket connection, and the reactor's advantages are not shown, but in some network management systems, the connection provider needs to connect multiple devices (servers) to be managed. In this case, the reactor mode is used, you only need to open one reactor event loop thread to achieve multi-channel event distribution and reuse without blocking. It is very convenient to use through object-oriented callback management.

Another common feature of the reactor framework is the server. Generally, a server corresponds to multiple clients. In this way, the reactor mode can greatly improve the concurrency, this programming method will be introduced in the next chapter.

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.