udp client sever changing from pull model to push model [closed]

◇◆丶佛笑我妖孽 提交于 2020-01-24 12:58:50

问题


I have implemented udp_client and 'udp_server` where server and client follows a pull model. The server pushes the data only when the client requests it. I want to change this to push model where server pushes the data down to the client when data is available.

My source files, header files and make is given below.

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

udp_server.hpp

#ifndef UDP_SERVER_H_INCLUDED 
#define UDP_SERVER_H_INCLUDED

#include <string>

struct CmdLineOpts
{
    std::string portStr;
    int port;
    int servOrClient;
};

void runUDPServer ( CmdLineOpts input );

bool clarg_parse ( int argc, char *argv[], CmdLineOpts input );
#endif

makefile

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)

I have tried modifying udp_server.cpp (given above) to change udp_server::start_recieve() function to explictly call handle_recieve()' instead of havinghandle_recieve()registered as a callback toasync_recieve_from()`. The modified function is given below

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

But the above change is giving me the following error.

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

I would like to know what I am doing wrong and how to change the model of udp server/client to push from pull.


回答1:


Change the client:

  1. so that it loops on the receive (to demonstrate multiple pushes)

Change the server:

  1. Do not respond right away
  2. Store the remote endpoint (the address) of the client upon receipt of the dummy packet
  3. Whenever you decide you do have data to push to the client, simply go through the list of stored endpoints and send the information at that time


来源:https://stackoverflow.com/questions/35544258/udp-client-sever-changing-from-pull-model-to-push-model

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!