рдПрдХ рдмрд╛рд░, рдХрд╛рд░реНрдп C ++ рдореЗрдВ рдПрдХ рд╕рд░рд▓ рдФрд░ рддреЗрдЬрд╝ рдорд▓реНрдЯреА-рдереНрд░реЗрдбреЗрдб рдЯреАрд╕реАрдкреА / рдЖрдИрдкреА рд╕рд░реНрд╡рд░ рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдЙрддреНрдкрдиреНрди рд╣реБрдЖ рдФрд░ рдЙрд╕реА рд╕рдордп рд╡рд┐рдВрдбреЛрдЬ рдФрд░ рд▓рд┐рдирдХреНрд╕ рдХреЗ рддрд╣рдд рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рд╕реА рднреА рддрд░рд╣ рд╕рд░реНрд╡рд░ рдХреЗ рд╡рд░реНрдЧ рдХреЗ рдмрд╛рд╣рд░ рдХреЛрдб рдХреЛ рдмрджрд▓рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреЗ рдмрд┐рдирд╛ред рдЗрд╕рд╕реЗ рдкрд╣рд▓реЗ, Qt рдЬреИрд╕реА рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдХреЗ рдмрд┐рдирд╛ рд╢реБрджреНрдз C ++ рдореЗрдВ, Tcp рд╕рд░реНрд╡рд░ рдиреЗ рд▓рд┐рдЦрд╛ рдирд╣реАрдВ рдерд╛, рдФрд░ рдордВрдЪ-рдЖрд╢реНрд░рд┐рдд рдХреЗ рд╕рд╛рде рдЦреБрдж рдХреЛ рдмрд╣реБрдд рд▓рдВрдмреЗ рд╕рдордп рддрдХ рдкреАрдбрд╝рд╛ рджреА рдереАред рд▓реЗрдХрд┐рди рдЬреИрд╕рд╛ рдХрд┐ рдпрд╣ рдкрддрд╛ рдЪрд▓рд╛ рд╣реИ, рдкрд╣рд▓реА рдирдЬрд╝рд░ рдореЗрдВ рд▓рдЧрдиреЗ рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рд╕рдм рдХреБрдЫ рдмрд╣реБрдд рд╕рд░рд▓ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдореВрд▓ рд░реВрдк рд╕реЗ рджреЛрдиреЛрдВ рдкреНрд░рдгрд╛рд▓рд┐рдпреЛрдВ рдХреЗ рд╕реЙрдХреЗрдЯ рдЗрдВрдЯрд░рдлреЗрд╕ рдкрд╛рдиреА рдХреА рджреЛ рдмреВрдВрджреЛрдВ рдХреЗ рд╕рдорд╛рди рд╣реИрдВ рдФрд░ рдХреЗрд╡рд▓ рдЫреЛрдЯреЗ рд╡рд┐рд╡рд░рдгреЛрдВ рдореЗрдВ рднрд┐рдиреНрди рд╣реИрдВред
рдЗрд╕рд▓рд┐рдП рд╕рд░реНрд╡рд░ рдФрд░ рдХреНрд▓рд╛рдЗрдВрдЯ рдХреНрд▓рд╛рд╕ рдЗрд╕ рдкреНрд░рдХрд╛рд░ рд╣реИ:
TcpServer.h
#ifndef TCPSERVER_H
#define TCPSERVER_H
#include <cstdint>
#include <functional>
#include <thread>
#include <list>
#ifdef _WIN32
#include <WinSock2.h>
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#endif
static constexpr uint16_t buffer_size = 4096;
struct TcpServer {
class Client;
typedef std::function<void(Client)> handler_function_t;
enum class status : uint8_t {
up = 0,
err_socket_init = 1,
err_socket_bind = 2,
err_socket_listening = 3,
close = 4
};
private:
uint16_t port;
status _status = status::close;
handler_function_t handler;
std::thread handler_thread;
std::list<std::thread> client_handler_threads;
std::list<std::thread::id> client_handling_end;
#ifdef _WIN32
SOCKET serv_socket = INVALID_SOCKET;
WSAData w_data;
#else
int serv_socket;
#endif
void handlingLoop();
public:
TcpServer(const uint16_t port, handler_function_t handler);
~TcpServer();
void setHandler(handler_function_t handler);
uint16_t getPort() const;
uint16_t setPort(const uint16_t port);
status getStatus() const {return _status;}
status restart();
status start();
void stop();
void joinLoop();
};
class TcpServer::Client {
#ifdef _WIN32
SOCKET socket;
SOCKADDR_IN address;
char buffer[buffer_size];
public:
Client(SOCKET socket, SOCKADDR_IN address);
#else
int socket;
struct sockaddr_in address;
char buffer[buffer_size];
public:
Client(int socket, struct sockaddr_in address);
#endif
public:
Client(const Client& other);
~Client();
uint32_t getHost() const;
uint16_t getPort() const;
int loadData();
char* getData();
bool sendData(const char* buffer, const size_t size) const;
};
#endif
тАФ SOCKET
Windows ( ) int
Linux. Linux int , Windows , :
#if 1
typedef UINT_PTR SOCKET;
#else
typedef INT_PTR SOCKET;
#endif
#if defined(_WIN64)
typedef unsigned __int64 UINT_PTR;
#else
typedef unsigned int UINT_PTR;
#endif
#if defined(_WIN64)
typedef __int64 INT_PTR;
#else
typedef int INT_PTR;
#endif
Windows TcpServer- WinSocket тАФ WSAData w_data;
(. WSAData)
:
TcpServer.cpp
#include "../hdr/TcpServer.h"
#include <chrono>
TcpServer::TcpServer(const uint16_t port, handler_function_t handler) : port(port), handler(handler) {}
TcpServer::~TcpServer() {
if(_status == status::up)
stop();
#ifdef _WIN32
WSACleanup ();
#endif
}
void TcpServer::setHandler(TcpServer::handler_function_t handler) {this->handler = handler;}
uint16_t TcpServer::getPort() const {return port;}
uint16_t TcpServer::setPort( const uint16_t port) {
this->port = port;
restart();
return port;
}
TcpServer::status TcpServer::restart() {
if(_status == status::up)
stop ();
return start();
}
void TcpServer::joinLoop() {handler_thread.join();}
int TcpServer::Client::loadData() {return recv(socket, buffer, buffer_size, 0);}
char* TcpServer::Client::getData() {return buffer;}
bool TcpServer::Client::sendData(const char* buffer, const size_t size) const {
if(send(socket, buffer, size, 0) < 0) return false;
return true;
}
#ifdef _WIN32
TcpServer::status TcpServer::start() {
WSAStartup(MAKEWORD(2, 2), &w_data);
SOCKADDR_IN address;
address.sin_addr.S_un.S_addr = INADDR_ANY;
address.sin_port = htons(port);
address.sin_family = AF_INET;
if(static_cast<int>(serv_socket = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR) return _status = status::err_socket_init;
if(bind(serv_socket, (struct sockaddr*)&address, sizeof(address)) == SOCKET_ERROR) return _status = status::err_socket_bind;
if(listen(serv_socket, SOMAXCONN) == SOCKET_ERROR) return _status = status::err_socket_listening;
_status = status::up;
handler_thread = std::thread([this]{handlingLoop();});
return _status;
}
void TcpServer::stop() {
_status = status::close;
closesocket (serv_socket);
joinLoop();
for(std::thread& cl_thr : client_handler_threads)
cl_thr.join();
client_handler_threads.clear ();
client_handling_end.clear ();
}
void TcpServer::handlingLoop() {
while(_status == status::up) {
SOCKET client_socket;
SOCKADDR_IN client_addr;
int addrlen = sizeof(client_addr);
if ((client_socket = accept(serv_socket, (struct sockaddr*)&client_addr, &addrlen)) != 0 && _status == status::up){
client_handler_threads.push_back(std::thread([this, &client_socket, &client_addr] {
handler(Client(client_socket, client_addr));
client_handling_end.push_back (std::this_thread::get_id());
}));
}
if(!client_handling_end.empty())
for(std::list<std::thread::id>::iterator id_it = client_handling_end.begin (); !client_handling_end.empty() ; id_it = client_handling_end.begin())
for(std::list<std::thread>::iterator thr_it = client_handler_threads.begin (); thr_it != client_handler_threads.end () ; ++thr_it)
if(thr_it->get_id () == *id_it) {
thr_it->join();
client_handler_threads.erase(thr_it);
client_handling_end.erase (id_it);
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
}
TcpServer::Client::Client(SOCKET socket, SOCKADDR_IN address) : socket(socket), address(address) {}
TcpServer::Client::Client(const TcpServer::Client& other) : socket(other.socket), address(other.address) {}
TcpServer::Client::~Client() {
shutdown(socket, 0);
closesocket(socket);
}
uint32_t TcpServer::Client::getHost() const {return address.sin_addr.S_un.S_addr;}
uint16_t TcpServer::Client::getPort() const {return address.sin_port;}
#else
TcpServer::status TcpServer::start() {
struct sockaddr_in server;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( port );
server.sin_family = AF_INET;
serv_socket = socket(AF_INET, SOCK_STREAM, 0);
if(serv_socket == -1) return _status = status::err_socket_init;
if(bind(serv_socket,(struct sockaddr *)&server , sizeof(server)) < 0) return _status = status::err_socket_bind;
if(listen(serv_socket, 3) < 0)return _status = status::err_socket_listening;
_status = status::up;
handler_thread = std::thread([this]{handlingLoop();});
return _status;
}
void TcpServer::stop() {
_status = status::close;
close(serv_socket);
joinLoop();
for(std::thread& cl_thr : client_handler_threads)
cl_thr.join();
client_handler_threads.clear ();
client_handling_end.clear ();
}
void TcpServer::handlingLoop() {
while (_status == status::up) {
int client_socket;
struct sockaddr_in client_addr;
int addrlen = sizeof (struct sockaddr_in);
if((client_socket = accept(serv_socket, (struct sockaddr*)&client_addr, (socklen_t*)&addrlen)) >= 0 && _status == status::up)
client_handler_threads.push_back(std::thread([this, &client_socket, &client_addr] {
handler(Client(client_socket, client_addr));
client_handling_end.push_back (std::this_thread::get_id());
}));
if(!client_handling_end.empty())
for(std::list<std::thread::id>::iterator id_it = client_handling_end.begin (); !client_handling_end.empty() ; id_it = client_handling_end.begin())
for(std::list<std::thread>::iterator thr_it = client_handler_threads.begin (); thr_it != client_handler_threads.end () ; ++thr_it)
if(thr_it->get_id () == *id_it) {
thr_it->join();
client_handler_threads.erase(thr_it);
client_handling_end.erase (id_it);
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
}
TcpServer::Client::Client(int socket, struct sockaddr_in address) : socket(socket), address(address) {}
TcpServer::Client::Client(const TcpServer::Client& other) : socket(other.socket), address(other.address) {}
TcpServer::Client::~Client() {
shutdown(socket, 0);
close(socket);
}
uint32_t TcpServer::Client::getHost() {return address.sin_addr.s_addr;}
uint16_t TcpServer::Client::getPort() {return address.sin_port;}
#endif
рд▓рд┐рдирдХреНрд╕ рдФрд░ рд╡рд┐рдВрдбреЛрдЬ рдХреЗ рд▓рд┐рдП рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреБрдЫ рд╕реНрдерд╛рдиреЛрдВ рдХреЗ рдЕрдкрд╡рд╛рдж рдХреЗ рд╕рд╛рде рд▓рдЧрднрдЧ рд╕рдорд╛рди рд╣реИ, рдЬреЛ рдХреЗрд╡рд▓ рдкрддреЗ ( struct sockaddr_in/SOCKADDR_IN, struct sockaddr/SOCKADDR
) рдФрд░ рд╕реЙрдХреЗрдЯ ( int/SOCKET
), рд╕рд╛рде рд╣реА рд╡рд┐рдВрдбреЛрдЬ рдореЗрдВ рдПрдХ WinSocket ( WSAData
) рд╕рдВрд╕реНрдХрд░рдг рдХреА рдЙрдкрд╕реНрдерд┐рддрд┐ рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рд╡рд┐рднрд┐рдиреНрди рд╕рдВрд░рдЪрдирд╛рдУрдВ рдХреЗ рдХрд╛рд░рдг рд╣реЛрддрд╛ рд╣реИ ред
рдЙрдкрдпреЛрдЧ рдЙрджрд╛рд╣рд░рдг:
main.cpp
#include "server/hdr/TcpServer.h"
#include <iostream>
std::string getHostStr(const TcpServer::Client& client) {
uint32_t ip = client.getHost ();
return std::string() + std::to_string(int(reinterpret_cast<char*>(&ip)[0])) + '.' +
std::to_string(int(reinterpret_cast<char*>(&ip)[1])) + '.' +
std::to_string(int(reinterpret_cast<char*>(&ip)[2])) + '.' +
std::to_string(int(reinterpret_cast<char*>(&ip)[3])) + ':' +
std::to_string( client.getPort ());
}
int main() {
TcpServer server( 8080,
[](TcpServer::Client client){
std::cout<<"Connected host:"<<getHostStr(client)<<std::endl;
int size = 0;
while (size == 0) size = client.loadData ();
std::cout
<<"size: "<<size<<" bytes"<<std::endl
<< client.getData() << std::endl;
const char answer[] = "Hello World from Server";
client.sendData(answer, sizeof (answer));
}
);
if(server.start() == TcpServer::status::up) {
std::cout<<"Server is up!"<<std::endl;
server.joinLoop();
} else {
std::cout<<"Server start error! Error code:"<< int(server.getStatus()) <<std::endl;
return -1;
}
}
рдЧрд┐рдЯрд╣рдм рд▓рд┐рдВрдХ
рдкреНрд░рдпреБрдХреНрдд рд▓реЗрдЦ: