2016-03-26 4 views
0

3ウェイハンドシェイクを使用して非同期接続を確立しようとしています。コードの一番下には、引数がクライアントまたはサーバーとして動作しているかどうかを判断する主要な方法があります。boost :: asio、どうして私のソケットはすぐにasync_receive_fromを呼び出した後にコールバック関数を実行するのですか?

サーバーとして動作している場合、ソケットを作成し、データを受信するまで待機してから、コールバック関数multiplexを呼び出して、受け取ったデータをどのように処理するかを判断します。

クライアントとして動作している場合は、データの受信を非同期で待機するソケットを作成しますが、create_connectionメソッドを使用してudp経由でsynパケットをサーバーに送信します。

ソケットのコンストラクタでは、start_receiveメソッドを実行します。これは、udpソケット上でasync_receive_fromを呼び出す必要があります。問題は、すぐにデータを受信するのではなく、0.0.0.0:0のエンドポイントを使用してコールバック関数multiplexをすぐに呼び出したことです。

#include <iostream> 
#include <string> 
#include <boost/asio.hpp> 
#include <boost/shared_ptr.hpp> 
#include <boost/cstdint.hpp> 
#include <boost/function.hpp> 
#include <boost/bind.hpp> 
#include <unordered_map> 
#include "packed_message.h" 
#include "segment.pb.h" 
#include "rtp.hpp" 

#define DEBUG true 
#define BUFFER_SIZE 10000 

using boost::asio::ip::udp; 
typedef boost::shared_ptr<rtp::Segment> SegmentPtr; 
typedef std::vector<uint8_t> data_buffer; 

// constructor for socket 
rtp::Socket::Socket(boost::asio::io_service& io_service_, std::string source_ip, std::string source_port): 
    io_service_(io_service_), 
    socket_(io_service_, udp::endpoint(boost::asio::ip::address::from_string(source_ip), std::stoi(source_port))), 
    source_port(source_port), 
    source_ip(source_ip) 
{ 
    // accept incoming rtp segments 
    std::cout << rtp::get_endpoint_str(socket_.local_endpoint()) << std::endl; 
    start_receive(); 
} 

/** 
* Accept incoming rtp segments 
*/ 
void rtp::Socket::start_receive() 
{ 
    data_buffer tmp_buf; 
    socket_.async_receive_from(boost::asio::buffer(tmp_buf), remote_endpoint_, 
     boost::bind(&rtp::Socket::multiplex, this, 
      tmp_buf, 
      boost::asio::placeholders::error, 
      boost::asio::placeholders::bytes_transferred)); 

} 

void rtp::Socket::multiplex(data_buffer& tmp_buf, 
    const boost::system::error_code& error, 
    std::size_t /*bytes_transferred*/) 
{ 
    std::string identifier = rtp::get_endpoint_str(remote_endpoint_); 

    if (connections.count(identifier) == 0) 
    { 
     boost::shared_ptr<Connection> connection(new Connection(remote_endpoint_)); 
     connections.insert({rtp::get_endpoint_str(remote_endpoint_), connection}); 
     std::cout << rtp::get_endpoint_str(remote_endpoint_) << std::endl; 
     connection_establishment(tmp_buf, connections.at(identifier)); 


    } 
    else if(!(connections.at(identifier)->is_valid())) // connection not in list of connections 
    { 
     connection_establishment(tmp_buf, connections.at(identifier)); 


} 

boost::shared_ptr<rtp::Connection> rtp::Socket::create_connection(std::string ip, std::string port) 
{ 
    udp::resolver resolver_(io_service_); 
    udp::resolver::query query_(ip, port); 
    udp::endpoint remote_endpoint_ = *resolver_.resolve(query_); 
    boost::shared_ptr<Connection> connection(new Connection(remote_endpoint_)); 

    connections.insert({rtp::get_endpoint_str(remote_endpoint_), connection}); 

    PackedMessage<rtp::Segment> m_packed_segment(SegmentPtr(new rtp::Segment())); 
    boost::shared_ptr<data_buffer> message(new data_buffer); 
    SegmentPtr ackseg(new rtp::Segment()); 
    ackseg->set_ack(true); 
    PackedMessage<rtp::Segment> initialack(ackseg); 
    initialack.pack(*message); 



    socket_.async_send_to(boost::asio::buffer(*message), remote_endpoint_, 
     boost::bind(&rtp::Socket::handle_send, this, message, 
     boost::asio::placeholders::error, 
     boost::asio::placeholders::bytes_transferred)); 

    return connection; 

} 

void rtp::Socket::connection_establishment(data_buffer& m_readbuf, boost::shared_ptr<Connection> connection) 
{ 
    int buffer_position(0); 
    PackedMessage<rtp::Segment> m_packed_segment(boost::shared_ptr<rtp::Segment>(new rtp::Segment())); 
    boost::shared_ptr<data_buffer> message(new data_buffer); 

    unsigned msg_len = m_packed_segment.decode_header(m_readbuf, buffer_position); 
    buffer_position += HEADER_SIZE; 
    m_packed_segment.unpack(m_readbuf, msg_len, buffer_position); 
    buffer_position += msg_len; 

    SegmentPtr synackseg = m_packed_segment.get_msg(); 
    if (synackseg->syn() && synackseg->ack()) 
    { 
     SegmentPtr ackseg(new rtp::Segment()); 
     ackseg->set_ack(true); 
     PackedMessage<rtp::Segment> finalack(ackseg); 
     finalack.pack(*message); 

     connection->set_valid(true); 

     socket_.async_send_to(boost::asio::buffer(*message), remote_endpoint_, 
      boost::bind(&rtp::Socket::handle_send, this, 
       message, 
       boost::asio::placeholders::error, 
       boost::asio::placeholders::bytes_transferred)); 

    } 
    else if (synackseg->syn()) 
    { 
     SegmentPtr synackseg(new rtp::Segment()); 
     synackseg->set_ack(true); 
     synackseg->set_syn(true); 
     PackedMessage<rtp::Segment> synack(synackseg); 
     synack.pack(*message); 

     socket_.async_send_to(boost::asio::buffer(*message), remote_endpoint_, 
      boost::bind(&rtp::Socket::handle_send, this, 
       message, 
       boost::asio::placeholders::error, 
       boost::asio::placeholders::bytes_transferred)); 


    } 
    else if (synackseg->ack()) 
    { 
     connection->set_valid(true); 
    } 

    start_receive(); 
} 

void rtp::Socket::handle_send(boost::shared_ptr<data_buffer> /*message*/, 
      const boost::system::error_code& /*error*/, 
      std::size_t /*bytes_transferred*/) 
{ 
} 

/** 
* Get remote peer ip and port in string "<ip>:<port>" 
*/ 
std::string rtp::get_endpoint_str(udp::endpoint remote_endpoint_) 
{ 
    std::string ip = remote_endpoint_.address().to_string(); 
    std::string port = std::to_string(remote_endpoint_.port()); 
    return ip + ":" + port; 
} 


rtp::Connection::Connection(udp::endpoint remote_endpoint_): 
    remote_endpoint_(remote_endpoint_), 
    dest_ip(remote_endpoint_.address().to_string()), 
    dest_port(std::to_string(remote_endpoint_.port())), 
    valid(false) 
{ 
} 

bool rtp::Connection::is_valid() 
{ 
    return valid; 
} 

void rtp::Connection::set_valid(bool val) 
{ 
    if(DEBUG) std::cerr << "Connection Created" << std::endl; 
    valid = val; 
} 


int main(int argc, char* argv[]) 
{ 
    if (argc == 1) 
    { 
     std::cerr << "Not enough args" << std::endl; 
     return 1; 
    } 
    boost::asio::io_service io_service_; 

    if (std::string(argv[1]) == u8"server") 
    { 
     rtp::Socket socket(io_service_, u8"127.0.0.1", u8"4545"); 
    } 
    else if (std::string(argv[1]) == u8"client") 
    { 
     rtp::Socket socket(io_service_, u8"127.0.0.1", u8"4546"); 
     socket.create_connection(u8"127.0.0.1", u8"4545"); 

    } 
    io_service_.run(); 
    return 0; 

} 

答えて

3

問題が最も可能性が高いこれらの行である:ここでは、変数socketを宣言し、それが唯一のif文の本体の範囲内で局所的であるifステートメント体の各

if (std::string(argv[1]) == u8"server") 
{ 
    rtp::Socket socket(io_service_, u8"127.0.0.1", u8"4545"); 
} 
else if (std::string(argv[1]) == u8"client") 
{ 
    rtp::Socket socket(io_service_, u8"127.0.0.1", u8"4546"); 
    socket.create_connection(u8"127.0.0.1", u8"4545"); 

} 

。スコープが終了すると、変数は破壊され、もう存在しなくなります。

このようなスコープで作成したオブジェクトが破壊される可能性があります。

有効期間がすべてのスコープよりも長いソケットを作成する必要があります.が返されるまで持続します。

+0

ありがとうございました。これが問題の原因となっています。 – vicg

関連する問題