ACE_Reactor中的handle_output

來源:互聯網
上載者:User

一直對ACE reactor framework中的handle_output困惑不解,而且個人覺得select是個很噁心的函數。

直到前段時間工作上需要用到網路編程,又把C++網路編程卷2找出來看看,寫了幾個小程式做實驗才漸漸明白了reactor中都handle_output的觸發條件。回想以前抱著書看了很久就是懶得動手寫代碼,結果總是一知半解的,看來“實踐出真知”一點都不假。

 

關於handle_output的小結:

當ACE_WFMO_Reactor回調到handle_output時你可以認為一直可寫,直到寫操作返回EWOULDBLOCK為止。如果socket一直都可以寫,ACE_WFMO_Reactor只會調用一次handle_output。因為socket本身的狀態沒有發生改變,ACE_WFMO_Reactor不會將它放在待指派的事件來源中。那麼下一次調用handle_output會是什麼時候呢?答案是socket從不可寫狀態變為可寫。這就是所謂的“邊緣觸發方式”。

再來看看ACE_Select_Reactor。Select_Reactor基於BSD Socket的select系統函數,使用的是“水平觸發方式”。也就是說,如果socket可寫,ACE_Select_Reactor就會不停地調用handle_output,可以說它是比較勤快和公平的,呵呵。

 

下面是個簡單的測試程式:echo伺服器。你可以通過宏USE_SELECT_REACTOR來決定使用WFMO_Reactor還是Select_Reactor。

 

 // Reactive_Server.cpp : Defines the entry point for the console application.<br />//</p><p>#include "stdafx.h"<br />#include "ace/Event_Handler.h"<br />#include "ace/SOCK_Acceptor.h"<br />#include "ace/SOCK_Stream.h"<br />#include "ace/Reactor.h"<br />#include "ace/OS.h"</p><p>#define USE_SELECT_REACTOR</p><p>#ifdef USE_SELECT_REACTOR<br />#include "ace/Select_Reactor.h"<br />#endif</p><p>#include <iostream></p><p>class Acceptor : public ACE_Event_Handler<br />{<br />private:<br />~Acceptor() {}<br />public:<br />virtual int open(const ACE_INET_Addr & addr);</p><p>/// overrides from ACE_Event_Handler<br />virtual int handle_input(ACE_HANDLE handle = ACE_INVALID_HANDLE);<br />virtual int handle_close(ACE_HANDLE handle, ACE_Reactor_Mask close_mask);<br />virtual ACE_HANDLE get_handle() const;</p><p>private:<br />ACE_SOCK_Acceptor m_acceptor;<br />};</p><p>class Client_Handler : public ACE_Event_Handler<br />{<br />private:<br />~Client_Handler() {}<br />public:<br />Client_Handler();<br />virtual int open();</p><p>/// overrides from ACE_Event_Handler<br />virtual int handle_input(ACE_HANDLE handle = ACE_INVALID_HANDLE);<br />virtual int handle_output(ACE_HANDLE handle = ACE_INVALID_HANDLE);<br />virtual int handle_close(ACE_HANDLE handle, ACE_Reactor_Mask close_mask);<br />virtual ACE_HANDLE get_handle() const;</p><p>ACE_SOCK_Stream & peer ();</p><p>private:<br />ACE_SOCK_Stream m_stream;<br />char m_buffer[8];<br />};</p><p>int _tmain(int argc, _TCHAR* argv[])<br />{<br />ACE_INET_Addr addr("0.0.0.0:1080");</p><p>#ifdef USE_SELECT_REACTOR<br />ACE_Select_Reactor select_reactor;<br />ACE_Reactor reactor(&select_reactor);<br />ACE_Reactor::instance(&reactor, 0);<br />#endif</p><p>Acceptor * acceptor = new Acceptor();<br />int ret = acceptor->open(addr);<br />if (ret == -1)<br />return -1;</p><p>return ACE_Reactor::instance()->run_event_loop();<br />}</p><p>///<br />/// Implementation of class Acceptor<br />///<br />int Acceptor::open(const ACE_INET_Addr & addr)<br />{<br />int ret = m_acceptor.open(addr);<br />if (ret == -1)<br />return -1;</p><p>ret = ACE_Reactor::instance()->register_handler(this, ACCEPT_MASK);<br />return ret;<br />}</p><p>int Acceptor::handle_input(ACE_HANDLE handle)<br />{<br />ACE_INET_Addr remotePeer;<br />Client_Handler * client_handler = new Client_Handler();<br />int ret = m_acceptor.accept(client_handler->peer(), &remotePeer);<br />if (ret == -1)<br />{<br />client_handler->handle_close(ACE_INVALID_HANDLE, NULL_MASK);<br />return -1;<br />}</p><p>cout << "Received connection from " << remotePeer.get_host_name() << ":" << remotePeer.get_port_number() << endl;</p><p>return client_handler->open();<br />}</p><p>int Acceptor::handle_close(ACE_HANDLE handle, ACE_Reactor_Mask close_mask)<br />{<br />m_acceptor.close();<br />delete this;<br />return -1; // return value ignored by reactor.<br />}</p><p>ACE_HANDLE Acceptor::get_handle() const<br />{<br />return this->m_acceptor.get_handle();<br />}</p><p>///<br />/// Implementation of class Client_Handler<br />///<br />Client_Handler::Client_Handler()<br />{<br />ACE_OS::memset(m_buffer, 0, sizeof(m_buffer));<br />}</p><p>int Client_Handler::open()<br />{<br />assert (m_stream.get_handle() != ACE_INVALID_HANDLE);<br />ACE_Time_Value timeout(1);<br />const char welcome [] = "Welcome to echo server";<br />m_stream.enable(ACE_NONBLOCK);<br />size_t size = m_stream.send(welcome, sizeof(welcome), &timeout);<br />if (size == 0)<br />return -1;<br />else if (size == -1)<br />{<br />assert (errno == EWOULDBLOCK);<br />}</p><p>m_stream.disable(ACE_NONBLOCK);</p><p>return ACE_Reactor::instance()->register_handler(this, READ_MASK | WRITE_MASK);<br />}</p><p>int Client_Handler::handle_input(ACE_HANDLE handle)<br />{<br />ACE_OS::memset(m_buffer, 0, sizeof(m_buffer));<br />m_stream.enable(ACE_NONBLOCK);<br />size_t size = m_stream.recv(m_buffer, sizeof(m_buffer));<br />if (size == 0) // connection loss<br />return -1;<br />else if (size == -1) // block<br />{<br />if (errno == EWOULDBLOCK)<br />return 0;<br />else<br />return -1;<br />}</p><p>// give us chance to reply to client<br />ACE_Reactor::instance()->schedule_wakeup(this, WRITE_MASK);</p><p>if (size == sizeof(m_buffer)) // there may be more data available<br />return 1;</p><p>return 0;<br />}</p><p>int Client_Handler::handle_output(ACE_HANDLE handle)<br />{<br />// just echo<br />size_t size = sizeof(m_buffer[0]) * (ACE_OS::strlen(m_buffer) + 1);<br />if (size > 1)<br />{<br />size_t num_bytes_sent = m_stream.send(m_buffer, size);<br />if (num_bytes_sent == 0) // connection loss<br />return -1;<br />else if (num_bytes_sent == -1) // block<br />{<br />assert (errno == EWOULDBLOCK);<br />}</p><p>if (num_bytes_sent == size)<br />{<br />ACE_Reactor::instance()->cancel_wakeup(this, WRITE_MASK);<br />}<br />else<br />{<br />// only part of the buffer are sent, <br />char * temp = new char[size - num_bytes_sent];<br />assert (temp != 0);<br />ACE_OS::memcpy(temp, m_buffer + num_bytes_sent, size - num_bytes_sent);<br />ACE_OS::memset(m_buffer, 0, sizeof(m_buffer));<br />ACE_OS::memcpy(m_buffer, temp, size - num_bytes_sent);<br />delete [] temp;<br />}</p><p>return 0;<br />}<br />else<br />{<br />ACE_Reactor::instance()->cancel_wakeup(this, WRITE_MASK);<br />return 0;<br />}<br />}</p><p>int Client_Handler::handle_close(ACE_HANDLE handle, ACE_Reactor_Mask close_mask)<br />{<br />if (close_mask == WRITE_MASK)<br />{<br />return 0;<br />}<br />else<br />{<br />ACE_INET_Addr remotePeer;<br />m_stream.get_remote_addr(remotePeer);<br />cout << "Disconnected: " << remotePeer.get_host_name() << ":" << remotePeer.get_port_number() << endl;<br />m_stream.close();<br />delete this;<br />return -1; // return value ignored by reactor<br />}<br />}</p><p>ACE_HANDLE Client_Handler::get_handle() const<br />{<br />return m_stream.get_handle();<br />}</p><p>ACE_SOCK_Stream & Client_Handler::peer ()<br />{<br />return this->m_stream;<br />}<br />

 

 

Technorati Tags: C++,ACE,network programming,select,reactor,WaitForMultipleObjects

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

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.