簡體   English   中英

Boost ASIO - 無法通過 TCP 發送消息

[英]Boost ASIO - Unable to send message over TCP

我正在使用 Boost ASIO 進行 TCP 網絡通信。 這是我的代碼:

Server.h

#ifndef VIBRANIUM_CORE_SERVER_H
#define VIBRANIUM_CORE_SERVER_H
#include <cstdlib>
#include <iostream>
#include <memory>
#include <utility>
#include <boost/asio.hpp>
#include <deque>
#include "Logger.h"
#include "Client.h"
#include "Protocol/ServerOpcode.h"

using boost::asio::ip::tcp;
namespace Vibranium {
    class Server {
    public:
        Server(boost::asio::io_service &io_service, short port)
                : acceptor_(io_service, tcp::endpoint(tcp::v4(), port)),
                  socket_(io_service) {
            do_accept();
            Logger::Log("Server Started! Listening on Port("+std::to_string(port)+")", Logger::Success, true);
        }
        static std::deque<std::shared_ptr<Client>> Clients;

    private:
        void do_accept();
        int incrementor;
        tcp::acceptor acceptor_;
        tcp::socket socket_;
    };

}


#endif //VIBRANIUM_CORE_SERVER_H

Server.cpp

#include "Server.h"
#include "Client.h"

using namespace Vibranium;
std::deque<std::shared_ptr<Client>> Server::Clients;
void Server::do_accept()
{
    acceptor_.async_accept(socket_,
   [this](boost::system::error_code ec)
   {
       if (!ec)
       {
           incrementor++;
           Logger::Log("New Connection (ID: " + std::to_string(incrementor) + ")",Logger::Success);
           std::shared_ptr<Client> c = std::make_shared<Client>(std::move(socket_));
           c->start();
           c->connectionId = incrementor;
           Server::Clients.push_back(c);
       }

       do_accept();
   });
}

Client.h

#ifndef VIBRANIUM_CORE_CLIENT_H
#define VIBRANIUM_CORE_CLIENT_H

#include <cstdlib>
#include <iostream>
#include <memory>
#include <utility>
#include <boost/asio.hpp>
#include "Protocol/ServerOpcode.h"

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

namespace Vibranium{
    class Client: public std::enable_shared_from_this<Client>
    {
    public:
        Client(tcp::socket socket)
        : socket(std::move(socket))
        {
        }
        void start();
        int connectionId;
        tcp::socket socket;
        void Send(ServerOpcode serverOpcode, const std::string& message);

    private:
        void do_read();
        void do_write(std::size_t length);
        enum { max_length = 1024 };
        char data_[max_length];
    };
}
#endif //VIBRANIUM_CORE_CLIENT_H

Client.cpp

#include "Client.h"
#include "Server.h"

void Vibranium::Client::start() {
    do_read();
}

void Vibranium::Client::do_read() {
    auto self(shared_from_this());
    socket.async_read_some(boost::asio::buffer(data_, max_length),
    [this, self](boost::system::error_code ec, std::size_t length)
    {
        if ((boost::asio::error::eof == ec) || (boost::asio::error::connection_reset == ec))
        {
            Logger::Log("Disconnected ID: " + std::to_string(connectionId),Logger::Error, true);
            for (int i = 0; i < Server::Clients.size(); ++i) {
                if(Server::Clients[i]->connectionId == connectionId)
                    Server::Clients.erase(Server::Clients.begin()+i);
            }
        }
        else
        {
            std::cout.write(data_, length);
            std::cout << "\n";
            //do_write(length);
            Send(ServerOpcode::SMSG_AUTH_CONNECTION_RESPONSE,"How are you, mate?");
        }
    });
}

void Vibranium::Client::do_write(std::size_t length) {
    auto self(shared_from_this());
    boost::asio::async_write(socket, boost::asio::buffer(data_, length),
     [this, self](boost::system::error_code ec, std::size_t /*length*/)
     {
         if (!ec)
         {
             do_read();
         }
     });
}

void Vibranium::Client::Send(ServerOpcode serverOpcode, const std::string& message) {
        auto self(shared_from_this());
        std::cout << "HERE!" << std::endl;
        size_t request_length = std::strlen(message.c_str());
        boost::asio::async_write(socket, boost::asio::buffer(message.c_str(), request_length),
         [this, self](boost::system::error_code ec, std::size_t /*length*/)
         {
             if (!ec)
                 do_read();
             else
                 Logger::Log("Message sent failed to " + std::to_string(connectionId),Logger::Error);
         });
}

這是我模擬到服務器的多個連接的方法:

Config config("AuthServer");
std::string defaultIP   = "127.0.0.1";
std::string defaultPort = "8080";
int connectionsNumber   = CommandQuestion<int>::AskQuestion("How many connections do you want established?");
std::cout << "Initializing " << std::to_string(connectionsNumber) << " connection/s." << std::endl;

std::cout << "Trying to connect to  " <<  defaultIP << " on port: " << config.GetConfigValue("AuthServerPort", defaultPort)  << std::endl;
boost::asio::io_context io_context;
std::vector<tcp::socket> sockets;
for (int i = 0; i < connectionsNumber; ++i) {
    try
    {
        sockets.emplace_back(io_context);
        tcp::socket& s{sockets.back()};
        tcp::resolver resolver(io_context);
        boost::asio::connect(s, resolver.resolve( defaultIP,config.GetConfigValue("AuthServerPort", defaultPort)));

        std::string message = "I am testing here!!!";
        size_t request_length = std::strlen(message.c_str());
        boost::asio::write(s, boost::asio::buffer(message, request_length));

        char reply[max_length];
        size_t reply_length = boost::asio::read(s,boost::asio::buffer(reply, request_length));
        Logger::Log(std::to_string(i) + " Connected!",Logger::Success);
                std::cout << "Reply is: ";
                std::cout.write(reply, reply_length);
                std::cout << "\n";
    }
    catch (std::exception& e)
    {
        std::cerr << "Exception: " << e.what() << "\n";
    }

}

所以基本上我正在建立連接,然后客戶端向服務器發送一條消息,說I am testing here!!! 比我想使用我的功能Send發送回客戶端另一條消息How are you, mate? .

但是它不起作用。 似乎無法從客戶端看到該消息。 在服務器端,我看到HERE!的輸出HERE! 它位於Send功能中。 這意味着我達到了那個點。

另一方面,如果我取消注釋//do_write(length); 從函數do_read()並評論回send()似乎返回了I am testing here!!!的消息I am testing here!!! . 所以根據我的理解,溝通是這樣工作的。

我的問題是我的Send功能錯誤在哪里? 為什么我不能讓它發送另一條消息,而不僅僅是回復客戶端首先發送的消息。

我發現自己的錯誤在哪里,這是我解決它的方法:

void Vibranium::Client::Send(ServerOpcode serverOpcode, const std::string& message) {
    auto self(shared_from_this());
    std::cout << "HERE!" << std::endl;
    strcpy(data_, message.c_str());
    size_t request_length = sizeof(data_)/sizeof(*data_);
    boost::asio::async_write(socket, boost::asio::buffer(data_, request_length),
     [this, self](boost::system::error_code ec, std::size_t /*length*/)
     {
         if (ec)
             Logger::Log("Message sent failed to " + std::to_string(connectionId),Logger::Error);
     });
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM