Boost :: Asio :: Ip :: Tcp :: Iostream вопросы

Привет всем, я новичок в asio и boost, я пытался реализовать TCP-сервер и клиент, чтобы я мог передавать std :: vector, но пока у меня ничего не вышло. Я считаю, что документация по расширению Asio отсутствует (мягко говоря) и трудна для понимания (английский не является моим основным языком).

В любом случае, я смотрел примеры iostreams и пытался реализовать объектно-ориентированное решение, но у меня ничего не вышло.

Сервер, который я пытаюсь реализовать, должен иметь возможность принимать соединения от нескольких клиентов (как мне это сделать?)

Сервер должен получить std :: vector, / * Сделать что-нибудь * /, а затем вернуть его клиенту, чтобы клиент мог сказать, что сервер получил данные без изменений.

файл * .h

class TCP_Server : private boost::noncopyable
        {
            typedef boost::shared_ptr<TCP_Connection> tcp_conn_pointer;

            public :
                TCP_Server(ba::io_service &io_service, int port);
                virtual ~TCP_Server() {}
                virtual void Start_Accept();
            private:
                virtual void Handle_Accept(const boost::system::error_code& e);
            private :
                int                 m_port;
                ba::io_service&     m_io_service;               // IO Service
                bi::tcp::acceptor   m_acceptor;         // TCP Connections acceptor
                tcp_conn_pointer    m_new_tcp_connection;   // New connection pointer
        };

* .cpp файл

TCP_Server::TCP_Server(boost::asio::io_service &io_service, int port) : 
            m_io_service(io_service), 
            m_acceptor(io_service, bi::tcp::endpoint(bi::tcp::v4(), port)), 
            m_new_tcp_connection(TCP_Connection::Create(io_service))
        {
            m_port = port;
            Start_Accept();
        }

        void TCP_Server::Start_Accept()
        {
            std::cout << "[TCP_Server][Start_Accept] => Listening on port : " << m_port << std::endl;
            //m_acceptor.async_accept(m_new_tcp_connection->Socket(),
            //                        boost::bind(&TCP_Server::Handle_Accept, this,
            //                                    ba::placeholders::error));


                m_acceptor.async_accept(*m_stream.rdbuf(),
                boost::bind(&TCP_Server::Handle_Accept, 
                this,
                ba::placeholders::error));
        }

        void TCP_Server::Handle_Accept(const boost::system::error_code &e)
        {
            if(!e)
            {

                /*boost::thread T(boost::bind(&TCP_Connection::Run, m_new_tcp_connection));
                std::cout << "[TCP_Server][Handle_Accept] => Accepting incoming connection. Launching Thread " << std::endl;
                m_new_tcp_connection = TCP_Connection::Create(m_io_service);
                m_acceptor.async_accept(m_new_tcp_connection->Socket(), 
                                        boost::bind(&TCP_Server::Handle_Accept, 
                                                    this, 
                                                    ba::placeholders::error));*/
                m_stream << "Server Response..." << std::endl;
            }
        }

Как должен выглядеть клиент? Как сохранить соединение, пока оба приложения «разговаривают»?


person Community    schedule 16.06.2009    source источник


Ответы (3)


Iostreams AFAIK ASIO предназначены только для синхронного ввода-вывода. Но ваш пример подсказывает мне, что вы хотите использовать асинхронный ввод-вывод. Вот небольшой пример сервера, который использует асинхронный ввод-вывод для чтения запроса, состоящего из массива целых чисел, которому предшествует 4-байтовый счетчик целых чисел в запросе. Таким образом, фактически я сериализую вектор целых чисел как count (4 байта) int int ... и т.д., если чтение вектора целых чисел прошло успешно, сервер напишет 4-байтовый код ответа (= 1), а затем выполнит чтение для новый запрос от клиента. Достаточно сказать, Код следует.

#include <iostream>
#include <vector>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <boost/asio.hpp>

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

class Connection
{
public:
    Connection(tcp::acceptor& acceptor)
        : acceptor_(acceptor), socket_(acceptor.get_io_service(), tcp::v4())
    {
    }
    void start()
    {
        acceptor_.get_io_service().post(boost::bind(&Connection::start_accept, this));
    }
private:
    void start_accept()
    {
        acceptor_.async_accept(socket_,boost::bind(&Connection::handle_accept, this, 
            placeholders::error));
    }
    void handle_accept(const boost::system::error_code& err)
    {
        if (err)
        {
            //Failed to accept the incoming connection.
            disconnect();
        }
        else
        {
            count_ = 0;
            async_read(socket_, buffer(&count_, sizeof(count_)),
                boost::bind(&Connection::handle_read_count,
                this, placeholders::error, placeholders::bytes_transferred));
        }
    }
    void handle_read_count(const boost::system::error_code& err, std::size_t bytes_transferred)
    {
        if (err || (bytes_transferred != sizeof(count_))
        {
            //Failed to read the element count.
            disconnect();
        }
        else
        {
            elements_.assign(count_, 0);
            async_read(socket_, buffer(elements_), 
                boost::bind(&Connection::handle_read_elements, this,
                placeholders::error, placeholders::bytes_transferred));
        }
    }

    void handle_read_elements(const boost::system::error_code& err, std::size_t bytes_transferred)
    {
        if (err || (bytes_transferred != count_ * sizeof(int)))
        {
            //Failed to read the request elements.
            disconnect();
        }
        else
        {
            response_ = 1;
            async_write(socket_, buffer(&response_, sizeof(response_)),
                boost::bind(&Connection::handle_write_response, this,
                placeholders::error, placeholders::bytes_transferred));
        }
    }
    void handle_write_response(const boost::system::error_code& err, std::size_t bytes_transferred)
    {
        if (err)
            disconnect();
        else
        {
            //Start a fresh read 
            count_ = 0;
            async_read(socket_, buffer(&count_, sizeof(count_)),
                boost::bind(&Connection::handle_read_count,
                this, placeholders::error, placeholders::bytes_transferred));
        }
    }
    void disconnect()
    {
        socket_.shutdown(tcp::socket::shutdown_both);
        socket_.close();
        socket_.open(tcp::v4());
        start_accept();
    }
    tcp::acceptor& acceptor_;
    tcp::socket socket_;
    std::vector<int> elements_;
    long count_;
    long response_;
};

class Server : private boost::noncopyable
{
public:
    Server(unsigned short port, unsigned short thread_pool_size, unsigned short conn_pool_size)
        : acceptor_(io_service_, tcp::endpoint(tcp::v4(), port), true)
    {
        unsigned short i = 0;
        for (i = 0; i < conn_pool_size; ++i)
        {
            ConnectionPtr conn(new Connection(acceptor_));
            conn->start();
            conn_pool_.push_back(conn);
        }

        // Start the pool of threads to run all of the io_services.
        for (i = 0; i < thread_pool_size; ++i)
        {
            thread_pool_.create_thread(boost::bind(&io_service::run, &io_service_));
        }
    }   
    ~Server()
    {
        io_service_.stop();
        thread_pool_.join_all();
    }

private:
    io_service io_service_;
    tcp::acceptor acceptor_;
    typedef boost::shared_ptr<Connection> ConnectionPtr;
    std::vector<ConnectionPtr> conn_pool_;
    boost::thread_group thread_pool_;
};

boost::function0<void> console_ctrl_function;

BOOL WINAPI console_ctrl_handler(DWORD ctrl_type)
{
  switch (ctrl_type)
  {
  case CTRL_C_EVENT:
  case CTRL_BREAK_EVENT:
  case CTRL_CLOSE_EVENT:
  case CTRL_SHUTDOWN_EVENT:
    console_ctrl_function();
    return TRUE;
  default:
    return FALSE;
  }
}

void stop_server(Server* pServer)
{
    delete pServer;
    pServer = NULL;
}

int main()
{
    Server *pServer = new Server(10255, 4, 20);
    console_ctrl_function = boost::bind(stop_server, pServer);
    SetConsoleCtrlHandler(console_ctrl_handler, TRUE);
    while(true)
    {
        Sleep(10000);
    }
}
person Modicom    schedule 13.07.2009
comment
Этот образец кода (с исправлением отсутствующего символа ')') скомпилирован, но при запуске выдает исключение. Кажется, что handle_accept вызывается с ошибкой сразу при запуске. В чем проблема? - person Marius; 04.06.2010
comment
Ах, чтобы исправить этот пример, socket_ необходимо инициализировать следующим образом: socket_(acceptor.get_io_service()). Таким образом, просто удалите tcp::v4(). - person Marius; 04.06.2010

Я считаю, что опубликованный вами код немного неполон / неверен. Тем не менее, вот некоторые рекомендации.

1) Ваш вызов async_accept () кажется неправильным. Должно получиться что-то вроде,

m_acceptor.async_accept(m_new_tcp_connection->socket(),...)

2) Обратите внимание, что функция Handle_Accept () будет вызываться после принятия сокета. Другими словами, когда управление достигает Handle_Accept (), вам просто нужно писать в сокет. Что-то типа

void TCP_Server::Handle_Accept(const system::error_code& error)
{
  if(!error)
  {
    //send data to the client
    string message = "hello there!\n";

    //Write data to the socket and then call the handler AFTER that
    //Note, you will need to define a Handle_Write() function in your TCP_Connection class.
async_write(m_new_tcp_connection->socket(),buffer(message),bind(&TCP_Connection::Handle_Write, this,placeholders::error,placeholders::bytes_transferred)); 

    //accept the next connection
    Start_Accept();
  }
}

3) Что касается клиента, вы должны посмотреть здесь: http://www.boost.org/doc/libs/1_39_0/doc/html/boost_asio/tutorial/tutdaytime1.html

person Imran.Fanaswala    schedule 29.06.2009

Если ваше взаимодействие на обоих концах реализовано на C ++, вы можете использовать библиотеку Boost Serialization, чтобы разделить вектор на байты и передать их на другой компьютер. На противоположном конце вы будете использовать библиотеку ускоренной сериализации для десириализации объекта. Я видел по крайней мере два подхода к этому.

Преимущество Boost Serialization: этот подход работает также при передаче объектов между 32-битной и 64-битной системами.

Ниже приведены ссылки:
статья проекта кода < br> расширить идеи списков рассылки

С уважением,
Ованес

person ovanes    schedule 11.07.2009