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 ++ 대상 실행 파일에서 서버에 대한 연결을 초기화하고 있습니다. 그래서 서버 실행 파일을 실행하고 여러 연결을 만들고 한 번에 유지하려는 다른 실행 파일을 가지고 있습니다.
연결이 생성 된 후 바로 삭제되지 않고 유지되도록하려면 어떻게해야합니까? 내 실수는 어디에 있으며 어떻게 고칠 수 있습니까?
은 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] 삭제
몇 마디 만하겠습니다