Boost.Asio c++ 網路編程翻譯(18)

來源:互聯網
上載者:User

標籤:else   stream   資料   asi   creat   拷貝構造   ptime   管理   track   

同步服務端同步服務端也相當簡單。它須要兩個線程,一個負責接收新的client。另外一個負責處理已經存在的client。

它不能使用單線程;等帶一個新的client是一個堵塞操作,所以我們須要另外一個線程來處理已經存在的client。正常來說服務端都比client要難實現。一方面,它要管理全部已經串連的client。由於我們是同步的,所以我們須要至少兩個線程。一個接受新的client串連(由於accept()是堵塞的)而還有一個負責回複已經存在的client。

   void accept_thread() {       ip::tcp::acceptor acceptor(service,
                                  ip::tcp::endpoint(ip::tcp::v4(),
   8001));       while ( true) {
           client_ptr new_( new talk_to_client);           acceptor.accept(new_->sock());           boost::recursive_mutex::scoped_lock lk(cs);           clients.push_back(new_);

} }

   void handle_clients_thread() {       while ( true) {
           boost::this_thread::sleep( millisec(1));           boost::recursive_mutex::scoped_lock lk(cs);           for(array::iterator b = clients.begin(),e = clients.end(); b

!= e; ++b)

               (*b)->answer_to_client();           // 刪除已經逾時的用戶端           clients.erase(std::remove_if(clients.begin(), clients.end(),
                      boost::bind(&talk_to_client::timed_out,_1)),
   clients.end());       }
   }   int main(int argc, char* argv[]) {
       boost::thread_group threads;       threads.create_thread(accept_thread);       threads.create_thread(handle_clients_thread);       threads.join_all();

為了分別處理client發送過來的請求我們須要儲存一個client的列表。每一個talk_to_client執行個體都擁有一個socket,socket類是不支援拷貝構造的,所以假設你想要把它們儲存在一個std::vector方法中,你須要一個指向它的智能指標。這裡有兩種實現的方式:在talk_to_client內部儲存一個指向socket的智能指標然後建立一個talk_to_client執行個體的數組,或者讓talk_to_client執行個體用變數的方式儲存socket,然後建立一個指向talk_to_client智能指標的數組。我選擇後者。可是你也能夠選前面的方式:
typedef boost::shared_ptr<talk_to_client> client_ptr;   typedef std::vector<client_ptr> array;   array clients;   boost::recursive_mutex cs; // 用安全執行緒的方式訪問用戶端數組
talk_to_client的主要代碼例如以下:
struct talk_to_client : boost::enable_shared_from_this<talk_to_client>   {
       talk_to_client() { ... }       std::string username() const { return username_; }       void answer_to_client() {
           try {               read_request();
               process_request();           } catch ( boost::system::system_error&) {

stop(); }

           if ( timed_out())               stop();
       }       void set_clients_changed() { clients_changed_ = true; }       ip::tcp::socket & sock() { return sock_; }       bool timed_out() const {
           ptime now = microsec_clock::local_time();           long long ms = (now - last_ping).total_milliseconds();           return ms > 5000 ;
       }       void stop() {
           boost::system::error_code err; sock_.close(err);       }
void read_request() {
           if ( sock_.available())

read_)); }

... private:

already_read_ += sock_.read_some(    buffer(buff_ + already_read_, max_msg - already_
       // ...  same as in Synchronous Client       bool clients_changed_;       ptime last_ping;

}; 

上述代碼擁有很好的自釋。最重要的方法是read_request()。

它僅僅有在存在有效資料的情況才讀取,這種話,服務端永遠不會堵塞:

void process_request() {       bool found_enter = std::find(buff_, buff_ + already_read_, ‘\n‘)
                           < buff_ + already_read_;
       if ( !found_enter)           return; // message is not full
       // process the msg       last_ping = microsec_clock::local_time();       size_t pos = std::find(buff_, buff_ + already_read_, ‘\n‘) -
   buff_;       std::string msg(buff_, pos);       std::copy(buff_ + already_read_, buff_ + max_msg, buff_);       already_read_ -= pos + 1;
       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();       else std::cerr << "invalid msg " << msg << std::endl;
   }   void on_login(const std::string & msg) {
       std::istringstream in(msg);       in >> username_ >> username_;       write("login ok\n");       update_clients_changed();

void on_ping() {

       write(clients_changed_ ? "ping client_list_changed\n" : "ping
   ok\n");       clients_changed_ = false;
   }   void on_clients() {
       std::string msg;       { boost::recursive_mutex::scoped_lock lk(cs);
           for( array::const_iterator b = clients.begin(), e = clients.   end() ;
                b != e; ++b)           msg += (*b)->username() + " ";

}

       write("clients " + msg + "\n");   }
   void write(const std::string & msg) { sock_.write_some(buffer(msg)); }
觀察process_request()。當我們讀取到足夠多有效資料時,我們須要知道我們是否已經讀取到整個訊息(假設found_enter為真)。這樣做的話。我們能夠使我們避免一次讀多個訊息的可能(’\n’之後的訊息被儲存到緩衝區中)。然後我們解析讀取到的整個訊息。剩下的代碼都是易懂的。







Boost.Asio c++ 網路編程翻譯(18)

聯繫我們

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