2010-11-03 2 views
2
поднимать торг

прежде всего, the codeЛучшее понимание в

// 
// chat_client.cpp 
// ~~~~~~~~~~~~~~~ 
// 
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) 
// 
// Distributed under the Boost Software License, Version 1.0. (See accompanying 
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 
// 

#include <cstdlib> 
#include <deque> 
#include <iostream> 
#include <boost/bind.hpp> 
#include <boost/asio.hpp> 
#include <boost/thread.hpp> 
#include "chat_message.hpp" 

using boost::asio::ip::tcp; 

typedef std::deque<chat_message> chat_message_queue; 

class chat_client 
{ 
public: 
    chat_client(boost::asio::io_service& io_service, 
     tcp::resolver::iterator endpoint_iterator) 
    : io_service_(io_service), 
     socket_(io_service) 
    { 
    tcp::endpoint endpoint = *endpoint_iterator; 
    socket_.async_connect(endpoint, 
     boost::bind(&chat_client::handle_connect, this, 
      boost::asio::placeholders::error, ++endpoint_iterator)); 
    } 

    void write(const chat_message& msg) 
    { 
    io_service_.post(boost::bind(&chat_client::do_write, this, msg)); 
    } 

    void close() 
    { 
    io_service_.post(boost::bind(&chat_client::do_close, this)); 
    } 

private: 

    void handle_connect(const boost::system::error_code& error, 
     tcp::resolver::iterator endpoint_iterator) 
    { 
    if (!error) 
    { 
     boost::asio::async_read(socket_, 
      boost::asio::buffer(read_msg_.data(), chat_message::header_length), 
      boost::bind(&chat_client::handle_read_header, this, 
      boost::asio::placeholders::error)); 
    } 
    else if (endpoint_iterator != tcp::resolver::iterator()) 
    { 
     socket_.close(); 
     tcp::endpoint endpoint = *endpoint_iterator; 
     socket_.async_connect(endpoint, 
      boost::bind(&chat_client::handle_connect, this, 
      boost::asio::placeholders::error, ++endpoint_iterator)); 
    } 
    } 

    void handle_read_header(const boost::system::error_code& error) 
    { 
    if (!error && read_msg_.decode_header()) 
    { 
     boost::asio::async_read(socket_, 
      boost::asio::buffer(read_msg_.body(), read_msg_.body_length()), 
      boost::bind(&chat_client::handle_read_body, this, 
      boost::asio::placeholders::error)); 
    } 
    else 
    { 
     do_close(); 
    } 
    } 

    void handle_read_body(const boost::system::error_code& error) 
    { 
    if (!error) 
    { 
     std::cout.write(read_msg_.body(), read_msg_.body_length()); 
     std::cout << "\n"; 
     boost::asio::async_read(socket_, 
      boost::asio::buffer(read_msg_.data(), chat_message::header_length), 
      boost::bind(&chat_client::handle_read_header, this, 
      boost::asio::placeholders::error)); 
    } 
    else 
    { 
     do_close(); 
    } 
    } 

    void do_write(chat_message msg) 
    { 
    bool write_in_progress = !write_msgs_.empty(); 
    write_msgs_.push_back(msg); 
    if (!write_in_progress) 
    { 
     boost::asio::async_write(socket_, 
      boost::asio::buffer(write_msgs_.front().data(), 
      write_msgs_.front().length()), 
      boost::bind(&chat_client::handle_write, this, 
      boost::asio::placeholders::error)); 
    } 
    } 

    void handle_write(const boost::system::error_code& error) 
    { 
    if (!error) 
    { 
     write_msgs_.pop_front(); 
     if (!write_msgs_.empty()) 
     { 
     boost::asio::async_write(socket_, 
      boost::asio::buffer(write_msgs_.front().data(), 
       write_msgs_.front().length()), 
      boost::bind(&chat_client::handle_write, this, 
       boost::asio::placeholders::error)); 
     } 
    } 
    else 
    { 
     do_close(); 
    } 
    } 

    void do_close() 
    { 
    socket_.close(); 
    } 

private: 
    boost::asio::io_service& io_service_; 
    tcp::socket socket_; 
    chat_message read_msg_; 
    chat_message_queue write_msgs_; 
}; 

int main(int argc, char* argv[]) 
{ 
    try 
    { 
    if (argc != 3) 
    { 
     std::cerr << "Usage: chat_client <host> <port>\n"; 
     return 1; 
    } 

    boost::asio::io_service io_service; 

    tcp::resolver resolver(io_service); 
    tcp::resolver::query query(argv[1], argv[2]); 
    tcp::resolver::iterator iterator = resolver.resolve(query); 

    chat_client c(io_service, iterator); 

    boost::thread t(boost::bind(&boost::asio::io_service::run, &io_service)); 

    char line[chat_message::max_body_length + 1]; 
    while (std::cin.getline(line, chat_message::max_body_length + 1)) 
    { 
     using namespace std; // For strlen and memcpy. 
     chat_message msg; 
     msg.body_length(strlen(line)); 
     memcpy(msg.body(), line, msg.body_length()); 
     msg.encode_header(); 
     c.write(msg); 
    } 

    c.close(); 
    t.join(); 
    } 
    catch (std::exception& e) 
    { 
    std::cerr << "Exception: " << e.what() << "\n"; 
    } 

    return 0; 
} 

теперь я не понимаю, почему они делают write функцию, чтобы отправить вызов в io_service? поэтому он будет потокобезопасным, и no1 будет использовать сокет одновременно? делает ли это, что 2X async_write никогда не произойдет? и что никакие async_write и async_read никогда не будут использоваться вместе? Должен ли я быть уверенным, что asynch_write и async_read не произойдет одновременно? или безопасно ли это делать одновременно? Кстати, если я хочу, чтобы код работал быстрее, я понял, что могу сделать 2 (или более) потока для выполнения io_service::run(), так что в этом случае мне нужно использовать мьютексы, чтобы убедиться, что вещи, которые я написал выше, не будут случаться?

ответ

1

io_service::post используется от открытого метода chat_client::write, потому что async_write является composed operation и приложения должны гарантировать, что никакие другие операции не выполняются на потоке до тех пор, пока не будет завершена.

Эта операция выполняется в терминах из нуля или более вызовов на функции async_write_some ручья, и известен как составная операция. Программа должна гарантировать, что поток выполняет никаких других операций записи (например, async_write, функции async_write_some ручья, или каких-либо другие составленных операций, которые не выполняют запись) до этой операции завершается.

Настоящая работа выполняется в chat_client::do_write, где используется очередь исходящих сообщений.

редактировать:

в примере клиента чата, есть только один поток вызова io_service::run поэтому нет никаких проблем безопасности потока в обработчиках. Если у вас несколько потоков, вызывающих io_service::run, вам следует исследовать пряди, а не мьютексы, как я описал в your previous question.

+0

tnx много для этого !! но все равно не получил ответа на все мои вопросы :) – grich

+0

@grich ответ был обновлен –

+0

tnx еще 1 вещь: безопасно ли иметь как 'async_recive', так и' async_send' в 'io_service', когда используются 2 или более потока 'io_service :: run'? а не 2Xasync_recives (или 2 async_send) только один из них, но оба в одно и то же время (если u хочет получить другой принятый ответ, напишите его здесь: http://stackoverflow.com/questions/4098455/is-it-thread- безопасный и позвони Асинхрам-отправить-и-асинхронному приемно-на-на-же время) – grich

Смежные вопросы