2009-06-16 2 views
3

Hey alle, ich bin neu zu Asio und Boost, ich habe versucht, einen TCP-Server & Client zu implementieren, so dass ich eine STD übertragen könnte :: Vektor - aber ich bin bisher gescheitert. Ich finde die Boost-Dokumentation von Asio fehlt (um es milde auszudrücken) und schwer zu verstehen (Englisch ist nicht meine primäre Sprache).Boost :: Asio :: Ip :: Tcp :: Iostream Fragen

In jedem Fall habe ich mir die Iostreams-Beispiele angeschaut und versucht, eine objektorientierte Lösung zu implementieren - aber ich bin gescheitert.

Der Server, der ich in der Lage zu implementieren bin versucht, sollten Verbindungen von mehreren Clients zu akzeptieren (Wie kann ich das tun?)

Der Server hat die std :: vector erhalten sollte,/* etwas tun */und dann an den Client zurückgeben, damit der Client feststellen kann, dass der Server die Daten intakt empfangen hat.

* .h-Datei

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-Datei

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; 
      } 
     } 

Wie sollte der Kunde aussehen? Wie halte ich die Verbindung aufrecht, während beide Apps "sprechen"?

Antwort

1

Ich glaube, dass der Code, den Sie gepostet haben, ein wenig unvollständig/falsch ist. Nichtsdestoweniger, hier ist einige Anleitung.

1) Ihr async_accept() Aufruf scheint falsch. Es sollte so etwas wie,

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

2) Beachten Sie, dass die Handle_Accept() Funktion nach die Fassung angenommen wird aufgerufen wird sein. Mit anderen Worten, wenn die Steuerung Handle_Accept() erreicht, müssen Sie einfach in den Socket schreiben. So etwas wie

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) Wie für den Kunden, sollten Sie einen Blick hier: http://www.boost.org/doc/libs/1_39_0/doc/html/boost_asio/tutorial/tutdaytime1.html

1

Wenn Ihre Kommunikation an beiden Enden in C realisiert wird ++ Sie Boost-Serialisierung Bibliothek verwenden können, um den Vektor sezilize in Bytes und übertrage diese auf die andere Maschine. Auf der anderen Seite verwenden Sie die Boost-Serialisierungsbibliothek, um das Objekt zu desiralisieren. Ich sah mindestens zwei Ansätze dabei.

Vorteil der Boost-Serialisierung: Dieser Ansatz funktioniert auch bei der Übertragung von Objekten zwischen 32-Bit- und 64-Bit-Systemen.

Im Folgenden sind die Verbindungen:
code project article
boost mailing list ideas

Grüße,
Ovanes

3

AFAIK ASIO iostreams sind nur für synchrone I/O. Aber Ihr Beispiel gibt mir einen Hinweis, dass Sie asynchrone E/A verwenden möchten. Hier ist ein kleines Beispiel für einen Server, der Async-E/A verwendet, um eine Anforderung zu lesen, die aus einem Array von ganzen Zahlen besteht, denen 4 Bytes der ganzen Zahlen in der Anfrage vorausgehen. Also in der Tat bin Serialisierung ich einen Vektor von integerss als Zahl (4 Byte) int int ... etc wenn das Lesen der Vektor der ints erfolgreich ist, wird der Server ein 4-Byte-Antwortcode schreiben (= 1) und dann einen Lesevorgang für eine neue Anfrage vom Client durchführen. Genug gesagt, Code folgt.

#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); 
    } 
} 
+0

Dieses Codebeispiel (mit der Behebung eines fehlenden ')') kompiliert, aber beim Ausführen eine Ausnahme ausgelöst. Es scheint, dass handle_accept sofort beim Start mit einem Fehler aufgerufen wird. Was ist das Problem? – Marius

+0

Ah, um dieses Beispiel zu beheben, muss 'socket_' wie folgt initialisiert werden: 'socket_ (acceptor.get_io_service())'. Entfernen Sie einfach die 'tcp :: v4()'. – Marius