简体   繁体   English

Boost ASIO - 无法通过 TCP 发送消息

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

I am using Boost ASIO for my TCP network communication.我正在使用 Boost ASIO 进行 TCP 网络通信。 Here is my code:这是我的代码:

Server.h : 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 : 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 : 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 : 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);
         });
}

Here is how I simulate several connections to the server:这是我模拟到服务器的多个连接的方法:

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

} }

So basically I am establishing connection and then the clients sends a message to the server saying I am testing here!!!所以基本上我正在建立连接,然后客户端向服务器发送一条消息,说I am testing here!!! than I would like to use my function Send to send back to the client another message How are you, mate?比我想使用我的功能Send发送回客户端另一条消息How are you, mate? . .

However it does not work.但是它不起作用。 It seems the message can't be seen back from the client.似乎无法从客户端看到该消息。 On server side I see the output of HERE!在服务器端,我看到HERE!的输出HERE! which is located in Send function.它位于Send功能中。 That means I reach that point.这意味着我达到了那个点。

On another hand if I uncomment //do_write(length);另一方面,如果我取消注释//do_write(length); from function do_read() and comment back send() it seems to return back the message I am testing here!!!从函数do_read()并评论回send()似乎返回了I am testing here!!!的消息I am testing here!!! . . So by my understanding communication works that way.所以根据我的理解,沟通是这样工作的。

My question is where is my mistake with Send function?我的问题是我的Send功能错误在哪里? Why I can't make it send another message instead of just replying back with what the client sent in first place.为什么我不能让它发送另一条消息,而不仅仅是回复客户端首先发送的消息。

I found myself where the error was, here is how I solved it:我发现自己的错误在哪里,这是我解决它的方法:

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