Boost.Asio c++ 網路編程翻譯(20),boost.asio網路編程

來源:互聯網
上載者:User

Boost.Asio c++ 網路編程翻譯(20),boost.asio網路編程
非同步服務端這個圖表是相當複雜的;從Boost.Asio出來你可以看到4個箭頭指向on_accept,on_read,on_write和on_check_ping。著也就意味著你永遠不知道哪個非同步呼叫是下一個完成的調用,但是你可以確定的是它是這4個操作中的一個。現在,我們是非同步了;我們可以繼續保持單線程。接受用戶端串連是最簡單的部分,如下所示:

ip::tcp::acceptor acceptor(service, ip::tcp::endpoint(ip::tcp::v4(),   8001));   void handle_accept(talk_to_client::ptr client, const error_code & err)   {
       client->start();       talk_to_client::ptr new_client = talk_to_client::new_();       acceptor.async_accept(new_client->sock(),
                             boost::bind(handle_accept,new_client,_1));
   }   int main(int argc, char* argv[]) {
       talk_to_client::ptr client = talk_to_client::new_();       acceptor.async_accept(client->sock(),boost::bind(handle_accept,client,_1));
    service.run();}
上述代碼會一直非同步地等待一個新的用戶端串連(每個新的用戶端串連會觸發另外一個非同步等待操作)。我們需要監控client list changed事件(一個新用戶端串連或者一個用戶端中斷連線),然後當事件發生時通知所有的用戶端。因此,我們需要儲存一個用戶端串連的數組,否則,除非你不需要在某一時刻知道所有串連的用戶端,你才不需要這樣一個數組。
class talk_to_client; typedef boost::shared_ptr<talk_to_client>   client_ptr;   typedef std::vector<client_ptr> array;   array clients;
connection類的架構如下:

class talk_to_client : public boost::enable_shared_from_this<talk_to_

client>

                        , boost::noncopyable {       talk_to_client() { ... }
   public:       typedef boost::system::error_code error_code;       typedef boost::shared_ptr<talk_to_client> ptr;       void start() {
           started_ = true;           clients.push_back( shared_from_this());           last_ping = boost::posix_time::microsec_clock::local_time();           do_read(); //首先,我們等待用戶端串連
       }       static ptr new_() { ptr new_(new talk_to_client); return new_; }       void stop() {
           if ( !started_) return;           started_ = false;           sock_.close();           ptr self = shared_from_this();           array::iterator it = std::find(clients.begin(), clients.end(),
   self);           clients.erase(it);
           update_clients_changed();       }
       bool started() const { return started_; }       ip::tcp::socket & sock() { return sock_;}       std::string username() const { return username_; }       void set_clients_changed() { clients_changed_ = true; }       … 
private:
       ip::tcp::socket sock_;       enum { max_msg = 1024 };       char read_buffer_[max_msg];       char write_buffer_[max_msg];       bool started_;       std::string username_;       deadline_timer timer_;       boost::posix_time::ptime last_ping;       bool clients_changed_;

};

我會用talk_to_client或者talk_to_server來調用connection類,從而使你更明白我所說的內容。
現在你需要用到之前的代碼了;它和我們在用戶端應用中所用到的是一樣的。但是我們還有另外一個stop()方法,這個方法用來從用戶端數組中移除一個用戶端串連。服務端持續不斷地等待非同步read操作:
void on_read(const error_code & err, size_t bytes) {       if ( err) stop();       if ( !started() ) return;       std::string msg(read_buffer_, bytes);
       if ( msg.find("login ") == 0) on_login(msg);       else if ( msg.find("ping") == 0) on_ping();       else if ( msg.find("ask_clients") == 0) on_clients();
   }   void on_login(const std::string & msg) {
       std::istringstream in(msg);       in >> username_ >> username_;       do_write("login ok\n");       update_clients_changed();
   }   void on_ping() {
       do_write(clients_changed_ ? "ping client_list_changed\n" : "ping   ok\n");
       clients_changed_ = false;   }
void on_clients() {
    std::string msg;
for(array::const_iterator b =clients.begin(),e =clients.end(); b   != e; ++b)
           msg += (*b)->username() + " ";       do_write("clients " + msg + "\n");

這段代碼是簡單易懂的;需要注意的一點是:當一個新用戶端登入,我們調用update_clients_changed(),這個方法為所有用戶端將clients_changed_標誌為true。服務端每收到一個請求就用正確的方式進行回複,如下所示:
void do_ping() { do_write("ping\n"); }   void do_ask_clients() { do_write("ask_clients\n"); }   void on_write(const error_code & err, size_t bytes) { do_read(); }   void do_read() {
       async_read(sock_, buffer(read_buffer_),                   MEM_FN2(read_complete,_1,_2), MEM_FN2(on_read,_1,_2));
       post_check_ping();   }
   void do_write(const std::string & msg) {       if ( !started() ) return;       std::copy(msg.begin(), msg.end(), write_buffer_);       sock_.async_write_some( buffer(write_buffer_, msg.size()),
                               MEM_FN2(on_write,_1,_2));
   }   size_t read_complete(const boost::system::error_code & err, size_t   bytes) {
       // ... as before   }
在每個write操作的末尾,on_write()方法被調用,這個方法會觸發另外一個非同步讀操作,這樣的話“等待請求-回複請求”這個迴圈酒會一直執行,直到用戶端中斷連線或者逾時。在每次讀操作開始之前,我們非同步等待5秒鐘來觀察用戶端是否逾時。如果逾時,我們關閉它的串連:
void on_check_ping() {       ptime now = microsec_clock::local_time();       if ( (now - last_ping).total_milliseconds() > 5000)
           stop();       last_ping = boost::posix_time::microsec_clock::local_time();
   }   void post_check_ping() {
       timer_.expires_from_now(boost::posix_time::millisec(5000));
       timer_.async_wait( MEM_FN(on_check_ping));   }
這就是整個服務端的實現。你可以運行並讓它工作起來!在代碼中,我向你們展示了這一章我們學到的東西,為了更容易理解,我把代碼稍微精簡了下;比如,大部分的控制台輸出我都沒有展示,儘管在這本書附贈的代碼中它們是存在的。我建議你自己運行這些例子,因為從頭到尾讀一次代碼能加強你對本章展示應用的理解。總結我們已經學到了怎麼寫一些基礎的用戶端/服務端應用。我們已經避免了一些諸如記憶體流失和死結的低級錯誤。所有的編碼都是架構式的,這樣你就可以根據你自己的需求對它們進行擴充。在接下來的章節中,我們會更加深入地瞭解使用Boost.Asio進行同步編程和非同步編程的不同點,同時你會也學會如何嵌入你自己的非同步作業。





解答初一英語:將“-20°C”翻譯成英文

以下幾句均可:

twenty degrees below zero centigrade.
攝氏度

minus twenty degrees Celsius。

minus twenty degrees centigrade。
 
翻譯this type of precipitator can be designed for more than –20 inches wc

英寸水柱(inch water column)
是個壓力單位

這句話應該是說,這類機器設計為可以在-20 英寸水柱這麼大的壓力下工作。
 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.