Boost ASIO를 사용하여 서버에 대한 여러 연결을 만드는 방법

Venelin

TCP 네트워킹 솔루션으로 Boost Asio를 사용하고 있습니다.

내 서버 코드는 다음과 같습니다.

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"

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>

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;
    private:
        void do_read();
        void do_write(std::size_t length);
        tcp::socket socket_;
        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);
        }
    });
}

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

서버를 시작하는 방법은 다음과 같습니다.

#include "Config.h"
#include "Database/MySQLConnection.h"
#include "Implementation/LoginDatabase.h"
#include "Banner.h"
#include "Server/Server.h"
#include <boost/asio.hpp>

using boost::asio::ip::tcp;
using namespace std;
using namespace Vibranium;

int main() {
    //Don't mind Logger::FatalError it's just for coloring!
    Banner::Show(Logger::Error,"AuthServer");
    Config config("AuthServer");
    std::string defaultPort = "8080";
    MySQLConnectionInfo mySqlConnectionInfo(config, "LoginDatabaseInfo");
    LoginDatabaseConnection loginDatabaseConnection(mySqlConnectionInfo);
    loginDatabaseConnection.LoadDatabase();

    try
    {
        boost::asio::io_service io_service;
        Server s(io_service, std::stoi(config.GetConfigValue("AuthServerPort", defaultPort)));
        io_service.run();
    }
    catch (std::exception& e)
    {
        std::cerr << "Exception: " << e.what() << "\n";
    }

    return 0;
}

한 번에 여러 연결을 만들고 유지하는 방법은 다음과 같습니다.

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;
for (int i = 0; i < connectionsNumber; ++i) {
   try
    {
        boost::asio::io_context io_context;
        tcp::socket s(io_context);
        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";
    }

}

성공적인 연결을 만들 수 있지만 예제 에코 메시지를 만들고 전송 한 직후에 연결이 끊어졌습니다.

예를 들어 3 연결을 초기화하려고하면 서버에 다음 출력이 표시됩니다.

Server Started! Listening on Port(8085)
New Connection (ID: 1)
I am testing here!!!
Disconnected ID: 1
New Connection (ID: 2)
I am testing here!!!
Disconnected ID: 2
New Connection (ID: 3)
I am testing here!!!
Disconnected ID: 3

동일한 PC에서 다른 C ++ 대상 실행 파일에서 서버에 대한 연결을 초기화하고 있습니다. 그래서 서버 실행 파일을 실행하고 여러 연결을 만들고 한 번에 유지하려는 다른 실행 파일을 가지고 있습니다.

연결이 생성 된 후 바로 삭제되지 않고 유지되도록하려면 어떻게해야합니까? 내 실수는 어디에 있으며 어떻게 고칠 수 있습니까?

f9c69e9781fa194211448473495534

tcp::socket그 범위 (벗어날 때 그 연결을 종료한다 참조 ). 연결을 열린 상태로 유지하려면 개체를 활성 상태로 유지해야합니다.

io_context클라이언트 예제에서 루프 밖으로 이동 하고 소켓을 보유하기위한 일부 목록을 유지하여 이를 수행 할 수 있습니다 .

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

      // initialize socket as before ...

그러면 클라이언트 루프가 완료된 후 서버 출력에 연결 해제 메시지가 표시됩니다.

New Connection (ID: 2)
Hello, world!
New Connection (ID: 3)
Hello, world!
New Connection (ID: 4)
Hello, world!
Disconnected ID: 2
Disconnected ID: 3
Disconnected ID: 4

추가 참고 사항 :의 내용을 표시하지 않았지만 do_write이 함수의 구현이 어떤 식 으로든 do_read다시 호출한다고 가정하여 최종 EOF 또는 연결 재설정을 처리 할 수 ​​있습니다.

이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.

침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

분류에서Dev

boost :: asio를 사용하여 HTTPS 서버에 연결

분류에서Dev

d3를 사용하여 산점도의 여러 점에 대한 도구 설명을 만드는 방법

분류에서Dev

PHP를 사용하여 동일한 호스트에 대한 여러 영구 소켓 연결 TCP / IP를 만드는 방법

분류에서Dev

C ++ 및 Boost Asio를 사용하여 HTTP 게시 요청에서 키 값을 가져 오는 방법

분류에서Dev

Qt에서 연결을 사용하여 "X"(종료) 버튼을 클릭 한시기를 확인하는 방법

분류에서Dev

Liferay 및 JavaScript를 사용하여 여러 파일에 대한 다운로드 버튼을 만드는 방법은 무엇입니까?

분류에서Dev

VB6.0을 사용하여 CR 8.5에 대한 연결 문자열을 만드는 방법

분류에서Dev

numpy를 사용하여 행렬의 여러 행에 대한 연산을 벡터화하는 방법

분류에서Dev

Pandas를 사용하여 여러 Excel 열에서 동일한 조건을 사용하는 방법 (대체)?

분류에서Dev

filepicker.io를 사용하여 동일한 페이지에 여러 드롭 창을 만드는 방법

분류에서Dev

여러 클래스에서 네트워크에 대한 단일 연결을 사용하는 방법

분류에서Dev

db-resolver를 사용하여 gorm v2의 여러 인스턴스에 대한 SQL 연결을 구성하는 방법

분류에서Dev

jQuery extend 메서드를 사용하여 요소 또는 클래스 선택기에 대한 사용자 지정 플러그인을 만드는 방법

분류에서Dev

boost :: spirit을 사용하여 문자열에서 여러 구조를 추출하는 방법

분류에서Dev

연결 종료 : Mongoose를 사용하여 동일한 MongoDB 서버에 연결하는 여러 노드 앱

분류에서Dev

Apache HttpClient 4.3.4를 사용하여 프록시를 통해 서버 SSL 포트에 대한 연결을 테스트하는 방법은 무엇입니까?

분류에서Dev

python 3.6을 사용하여 루프에 대한 결정 프롬프트를 만드는 방법

분류에서Dev

Kafka를 사용하여 Azure Eventhub에 대한 pyspark 연결 문자열을 포맷하는 방법

분류에서Dev

Toplevel () Tkinter에서 캔버스를 사용하여 버튼을 만드는 방법

분류에서Dev

파이썬에서 여러 인덱스를 사용하여 데이터 프레임에 대한 누적 플롯을 만드는 방법은 무엇입니까?

분류에서Dev

OpenVPN을 통해 NordVPN 서버를 사용하여 VPN 서버에 연결 한 후 SSH를 터미널에 허용하는 방법은 무엇입니까?

분류에서Dev

이름에 대한 변수를 사용하여 런타임에 여러 DataGridView를 만드는 방법

분류에서Dev

RxDatasource를 사용하여 여러 헤더가있는 UICollectionView에서 여러 섹션을 만드는 방법

분류에서Dev

cypher를 사용하여 여러 관계 중 하나에 대한 동작을 제한하는 방법

분류에서Dev

VsVim을 사용하여 여러 파일에 대한 키워드를 찾는 방법

분류에서Dev

R에서 ggplot을 사용하여 여러 종에 대한 평균 CPUE를 그리는 방법

분류에서Dev

Erlang을 사용하여 웹 서버를 만드는 방법

분류에서Dev

lftp를 사용하여 ftps 파일 서버에 연결하고 파일을 서버로 푸시하는 방법

분류에서Dev

PowerQuery를 사용하여 Excel을 Oracle에 연결하는 방법

Related 관련 기사

  1. 1

    boost :: asio를 사용하여 HTTPS 서버에 연결

  2. 2

    d3를 사용하여 산점도의 여러 점에 대한 도구 설명을 만드는 방법

  3. 3

    PHP를 사용하여 동일한 호스트에 대한 여러 영구 소켓 연결 TCP / IP를 만드는 방법

  4. 4

    C ++ 및 Boost Asio를 사용하여 HTTP 게시 요청에서 키 값을 가져 오는 방법

  5. 5

    Qt에서 연결을 사용하여 "X"(종료) 버튼을 클릭 한시기를 확인하는 방법

  6. 6

    Liferay 및 JavaScript를 사용하여 여러 파일에 대한 다운로드 버튼을 만드는 방법은 무엇입니까?

  7. 7

    VB6.0을 사용하여 CR 8.5에 대한 연결 문자열을 만드는 방법

  8. 8

    numpy를 사용하여 행렬의 여러 행에 대한 연산을 벡터화하는 방법

  9. 9

    Pandas를 사용하여 여러 Excel 열에서 동일한 조건을 사용하는 방법 (대체)?

  10. 10

    filepicker.io를 사용하여 동일한 페이지에 여러 드롭 창을 만드는 방법

  11. 11

    여러 클래스에서 네트워크에 대한 단일 연결을 사용하는 방법

  12. 12

    db-resolver를 사용하여 gorm v2의 여러 인스턴스에 대한 SQL 연결을 구성하는 방법

  13. 13

    jQuery extend 메서드를 사용하여 요소 또는 클래스 선택기에 대한 사용자 지정 플러그인을 만드는 방법

  14. 14

    boost :: spirit을 사용하여 문자열에서 여러 구조를 추출하는 방법

  15. 15

    연결 종료 : Mongoose를 사용하여 동일한 MongoDB 서버에 연결하는 여러 노드 앱

  16. 16

    Apache HttpClient 4.3.4를 사용하여 프록시를 통해 서버 SSL 포트에 대한 연결을 테스트하는 방법은 무엇입니까?

  17. 17

    python 3.6을 사용하여 루프에 대한 결정 프롬프트를 만드는 방법

  18. 18

    Kafka를 사용하여 Azure Eventhub에 대한 pyspark 연결 문자열을 포맷하는 방법

  19. 19

    Toplevel () Tkinter에서 캔버스를 사용하여 버튼을 만드는 방법

  20. 20

    파이썬에서 여러 인덱스를 사용하여 데이터 프레임에 대한 누적 플롯을 만드는 방법은 무엇입니까?

  21. 21

    OpenVPN을 통해 NordVPN 서버를 사용하여 VPN 서버에 연결 한 후 SSH를 터미널에 허용하는 방법은 무엇입니까?

  22. 22

    이름에 대한 변수를 사용하여 런타임에 여러 DataGridView를 만드는 방법

  23. 23

    RxDatasource를 사용하여 여러 헤더가있는 UICollectionView에서 여러 섹션을 만드는 방법

  24. 24

    cypher를 사용하여 여러 관계 중 하나에 대한 동작을 제한하는 방법

  25. 25

    VsVim을 사용하여 여러 파일에 대한 키워드를 찾는 방법

  26. 26

    R에서 ggplot을 사용하여 여러 종에 대한 평균 CPUE를 그리는 방법

  27. 27

    Erlang을 사용하여 웹 서버를 만드는 방법

  28. 28

    lftp를 사용하여 ftps 파일 서버에 연결하고 파일을 서버로 푸시하는 방법

  29. 29

    PowerQuery를 사용하여 Excel을 Oracle에 연결하는 방법

뜨겁다태그

보관