C++ udp客户端服务器从拉模式更改为推模式

C++ udp客户端服务器从拉模式更改为推模式,c++,c++11,boost,client-server,boost-asio,C++,C++11,Boost,Client Server,Boost Asio,我已经实现了udp_客户端和“udp_服务器”,其中服务器和客户端遵循拉模式。服务器仅在客户端请求数据时才推送数据。我想将此更改为推送模式,即当数据可用时,服务器将数据向下推送到客户端 下面给出了我的源文件、头文件和make udp_服务器.cpp #include "udp_server.hpp" #include <iostream> #include <exception> #include <boost/array.hpp> #include <

我已经实现了
udp_客户端
和“udp_服务器”,其中服务器和客户端遵循拉模式。服务器仅在客户端请求数据时才推送数据。我想将此更改为推送模式,即当数据可用时,服务器将数据向下推送到客户端

下面给出了我的源文件、头文件和make

udp_服务器.cpp

#include "udp_server.hpp"
#include <iostream>
#include <exception>
#include <boost/array.hpp>
#include <boost/asio.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <algorithm>
#include <sstream>
#include <iomanip>
const int ARG_COUNT = 2;
const int LOWEST_PORT = 1024;
const int HIGHEST_PORT = 65000;

static char message_array[8192];

void gen_random_string(char *s, const int len) 
{
    static const char alphanum[] =
        "0123456789"
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "abcdefghijklmnopqrstuvwxyz";

    for (int i = 0; i < len; ++i) {
        s[i] = alphanum[rand() % (sizeof(alphanum) - 1)];
    }
    s[len] = 0;
}


class udp_server
{
public:
    udp_server(boost::asio::io_service& io_service,int port_number)
        : socket_(io_service, boost::asio::ip::udp::udp::endpoint(boost::asio::ip::udp::udp::v4(), port_number))
    {
        std::cout << "UDP server listening on " << port_number << std::endl;
        start_receive();
    }

private:
    void start_receive()
    {
        socket_.async_receive_from(
            boost::asio::buffer(recv_buffer_), remote_endpoint_,
            boost::bind(&udp_server::handle_receive, this,
                        boost::asio::placeholders::error,
                        boost::asio::placeholders::bytes_transferred));
    }

    void handle_receive(const boost::system::error_code& error,
                        std::size_t /*bytes_transferred*/)
    {
        if (!error || error == boost::asio::error::message_size)
        {
            gen_random_string(message_array, 8192);
            boost::shared_ptr<std::string> message(new std::string(message_array));

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

            start_receive();
        }
    }

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

    boost::asio::ip::udp::udp::socket socket_;
    boost::asio::ip::udp::udp::endpoint remote_endpoint_;
    boost::array<char, 1> recv_buffer_;
};


void runUDPServer( CmdLineOpts input )
{
    try
    {
        boost::asio::io_service io_service;
        udp_server server(io_service,input.port);
        io_service.run();
    }
    catch (std::exception& e)
    {
        std::cerr << e.what() << std::endl;
    }

}



class udp_client
{
public:
    udp_client(
        boost::asio::io_service& io_service,
        const std::string& host,
        const std::string& port
    ) : io_service_(io_service), socket_(io_service, boost::asio::ip::udp::udp::endpoint(boost::asio::ip::udp::udp::v4(), 0)) {
        boost::asio::ip::udp::udp::resolver resolver(io_service_);
        boost::asio::ip::udp::udp::resolver::query query(boost::asio::ip::udp::udp::v4(), host, port);
        boost::asio::ip::udp::udp::resolver::iterator iter = resolver.resolve(query);
        endpoint_ = *iter;
    }

    ~udp_client()
    {
        std::cout << "Calling UDP client destructor" << std::endl;
        socket_.close();
    }

    void send() {
        socket_.send_to(boost::asio::buffer(send_buf), endpoint_);
    }

    void recieve_from() {
        /*Initialize our endpoint*/
        boost::array<unsigned char, 8192> temp; 
       // boost::asio::buffer boost_buf(temp);
        size_t len = socket_.receive_from(
                         boost::asio::buffer(temp), sender_endpoint);

        std::ostringstream ss;
        ss << std::hex << std::uppercase << std::setfill( '0' );
        std::for_each( temp.cbegin(), temp.cend(), [&]( int c ) { ss << std::setw( 2 ) << c; } );
        std::string result = ss.str();
        std::cout << "Length of recieved message " << len << std::endl;
        std::cout << result << std::endl;

    }

private:
    boost::asio::io_service& io_service_;
    boost::asio::ip::udp::udp::socket socket_;
    boost::asio::ip::udp::udp::endpoint endpoint_;
    //boost::array<char, 2048> recv_buf;
    std::vector<unsigned char> recv_buf;
    boost::array<char, 1> send_buf  = {{ 0 }};
    boost::asio::ip::udp::endpoint sender_endpoint;

};

void runUDPClient(std::string portStr)
{
    try
    {
        boost::asio::io_service io_service;
        udp_client client(io_service, "localhost", portStr);
        client.send();
        client.recieve_from();
    }
    catch (std::exception& e)
    {
        std::cerr << e.what() << std::endl;
    }
}

void runClient( CmdLineOpts input )
{
    runUDPClient(input.portStr);
}

void runServer( CmdLineOpts input )
{
    runUDPServer(input);
}

/**
* Usage: client_server <protocol> <port> <num of packets>
*/
bool clarg_parse ( int argc, char *argv[], CmdLineOpts *input )
{
    bool result = true;
    if (argc - 1 == ARG_COUNT)
    {
        // arg 1: server or client
        int arg1 = std::stoi(argv[1]);
        if (arg1 == 0 || arg1 == 1)
        {
            input->servOrClient = arg1;
        }
        else
        {
            std::cout << "Invalid client server choice.\nUsage: client_server <client (0) or server(1)> <port>" << std::endl;
            result = false;
        }
        // arg 2: port
        int arg2 = std::stoi(argv[3]);
        if (arg2 > LOWEST_PORT && arg2 < HIGHEST_PORT )
        {
            input->port = arg2;
            input->portStr = argv[3];
        }
        else
        {
            std::cout << "Invalid port, must be between " << LOWEST_PORT << " and " << HIGHEST_PORT << std::endl;
            std::cout << "Usage: client_server <client (0) or server(1)> <port>" << std::endl;
            result = false;
        }

    }
    else
    {
        std::cout << "Usage: client_server <client (0) or server(1)> <port>" << std::endl;
        result = false;
    }

    return result;
}



int main ( int argc, char *argv[] )
{
    CmdLineOpts input;
    if (clarg_parse(argc, argv, &input))
    {
        if(input.servOrClient == 1)
        {
            runServer(input);
        }
        else if(input.servOrClient == 0)
        {
            runClient(input);
        }
    }
    else
    {
        return 1;
    }

    return 0;
}
但是上面的改变给了我以下的错误

g++ -std=c++11 -g -Wall -pedantic -c udp_server.cpp -o udp_server.o
udp_server.cpp: In member function ‘void udp_server::start_receive()’:
udp_server.cpp:22:46: error: expected primary-expression before ‘&’ token
     handle_recieve(boost::system::error_code &error, std::size_t bytes_transferred);
                                              ^
udp_server.cpp:22:47: error: ‘error’ was not declared in this scope
     handle_recieve(boost::system::error_code &error, std::size_t bytes_transferred);
我想知道我做错了什么,以及如何将udp服务器/客户端的模式更改为push from pull。

更改客户端:

  • 使其在接收端循环(以演示多次推送)
  • 更改服务器:

  • 不要马上回应
  • 在收到虚拟数据包时存储客户端的远程端点(地址)
  • 每当您决定将数据推送到客户机时,只需浏览存储的端点列表并在此时发送信息即可

  • 我是否应该更新远程端点集,比如说,如果我没有从客户端收到一个虚拟数据包,比如说5分钟?这是一个好主意吗?是的,应该有一些超时。我是否也需要存储类似(boost::asio)tcp服务器的远程连接端点?我认为您还必须存储相关的套接字,以保持持久连接。不,只需像
    std::vector订阅者这样的向量
    或者,如果您查看一下,在客户机使用
    tcp\u连接的地方
    holder类,您可以存储
    std::vector订阅者
    
    TARGET = udp_server
    LIBS = -lboost_system -lpthread
    CXX = g++
    CXXFLAGS = -std=c++11 -g -Wall -pedantic
    
    .PHONY: default all clean
    
    default: $(TARGET)
    all: default
    
    OBJECTS = $(patsubst %.cpp, %.o, $(wildcard *.cpp))
    HEADERS = $(wildcard *.hpp)
    
    %.o: %.cpp $(HEADERS)
        $(CXX) $(CXXFLAGS) -c $< -o $@
    
    .PRECIOUS: $(TARGET) $(OBJECTS)
    
    $(TARGET): $(OBJECTS)
        $(CXX) $(OBJECTS) $(LIBS) -o $@
    
    clean:
        -rm -f *.o
        -rm -f $(TARGET)
    
    void udp_server::start_receive()
    {
        /*m_socket.async_receive_from(
            boost::asio::buffer(m_recv_buffer), m_remote_endpoint,
            boost::bind(&udp_server::handle_receive, this,
                        boost::asio::placeholders::error,
                        boost::asio::placeholders::bytes_transferred));*/
        handle_recieve(boost::system::error_code &error, std::size_t bytes_transferred);
    }
    
    g++ -std=c++11 -g -Wall -pedantic -c udp_server.cpp -o udp_server.o
    udp_server.cpp: In member function ‘void udp_server::start_receive()’:
    udp_server.cpp:22:46: error: expected primary-expression before ‘&’ token
         handle_recieve(boost::system::error_code &error, std::size_t bytes_transferred);
                                                  ^
    udp_server.cpp:22:47: error: ‘error’ was not declared in this scope
         handle_recieve(boost::system::error_code &error, std::size_t bytes_transferred);