{"id":304117,"date":"2020-05-23T15:00:57","date_gmt":"2020-05-23T15:00:57","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=304117"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=304117","title":{"rendered":"\u041a\u0440\u043e\u0441\u0441\u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435\u043d\u043d\u044b\u0439 \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u0442\u043e\u0447\u043d\u044b\u0439 TCP\/IP \u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0430 C++"},"content":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/post\/503432\/\">\n<p>\u041a\u0430\u043a-\u0442\u043e \u0440\u0430\u0437 \u0432\u0441\u0442\u0430\u043b\u0430 \u0437\u0430\u0434\u0430\u0447\u0430 \u043f\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u0438 \u0431\u044b\u0441\u0442\u0440\u043e\u0433\u043e \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u0442\u043e\u0447\u043d\u043e\u0433\u043e TCP\/IP \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043d\u0430 C++ \u0438 \u043f\u0440\u0438 \u044d\u0442\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u043b \u0438\u0437 \u043f\u043e\u0434 Windows \u0438 Linux \u0431\u0435\u0437 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u043a\u0430\u043a-\u043b\u0438\u0431\u043e \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u043a\u043e\u0434 \u0437\u0430 \u043f\u0440\u0435\u0434\u0435\u043b\u0430\u043c\u0438 \u043a\u043b\u0430\u0441\u0441\u0430 \u0441\u0430\u043c\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0435\u0440\u0430. \u0420\u0430\u043d\u0435\u0435, \u043d\u0430 \u0447\u0438\u0441\u0442\u043e\u043c C++ \u0431\u0435\u0437 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u0432\u0440\u043e\u0434\u0435 Qt, Tcp-\u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0435 \u043f\u0438\u0441\u0430\u043b, \u0438 \u043f\u0440\u0435\u0434\u0432\u0435\u0449\u0430\u043b \u0441\u0435\u0431\u0435 \u0434\u043e\u043b\u0433\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u043c\u0443\u0447\u0435\u043d\u0438\u0439 \u0441 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u043e-\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c\u044e. \u041d\u043e \u043a\u0430\u043a \u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u0432\u0441\u0451 \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u043f\u0440\u043e\u0449\u0435 \u0447\u0435\u043c \u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u043d\u0430 \u043f\u0435\u0440\u0432\u044b\u0439 \u0432\u0437\u0433\u043b\u044f\u0434, \u0432\u0435\u0434\u044c \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b \u0441\u043e\u043a\u0435\u0442\u043e\u0432 \u043e\u0431\u043e\u0438\u0445 \u0441\u0438\u0441\u0442\u0435\u043c \u043f\u043e\u0445\u043e\u0436\u0438 \u043a\u0430\u043a \u0434\u0432\u0435 \u043a\u0430\u043f\u043b\u0438 \u0432\u043e\u0434\u044b \u0438 \u0440\u0430\u0437\u043b\u0438\u0447\u0430\u044e\u0442\u0441\u044f \u043b\u0438\u0448\u044c \u0432 \u043c\u0435\u043b\u043a\u0438\u0445 \u0434\u0435\u0442\u0430\u043b\u044f\u0445.<\/p>\n<p><a name=\"habracut\"><\/a>  <\/p>\n<p>\u0418\u0442\u0430\u043a \u043a\u043b\u0430\u0441\u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<p>  <\/p>\n<p><strong>TcpServer.h<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"cpp\">#ifndef TCPSERVER_H #define TCPSERVER_H  #include &lt;cstdint&gt; #include &lt;functional&gt; #include &lt;thread&gt; #include &lt;list&gt;  #ifdef _WIN32 \/\/ Windows NT  #include &lt;WinSock2.h&gt;  #else \/\/ *nix  #include &lt;sys\/types.h&gt; #include &lt;sys\/socket.h&gt; #include &lt;netinet\/in.h&gt; #include &lt;unistd.h&gt; #include &lt;stdio.h&gt; #include &lt;stdlib.h&gt;  #endif  \/\/\u0411\u0443\u0444\u0444\u0435\u0440 \u0434\u043b\u044f \u043f\u0440\u0438\u0451\u043c\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u043e\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 static constexpr uint16_t buffer_size = 4096;  struct TcpServer {     class Client;      \/\/\u0422\u0438\u043f Callback-\u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0430     typedef std::function&lt;void(Client)&gt; handler_function_t;      \/\/\u0421\u0442\u0430\u0442\u0443\u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430     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; \/\/\u041f\u043e\u0440\u0442     status _status = status::close;     handler_function_t handler;      std::thread handler_thread;     std::list&lt;std::thread&gt; client_handler_threads;     std::list&lt;std::thread::id&gt; client_handling_end;  #ifdef _WIN32 \/\/ Windows NT     SOCKET serv_socket = INVALID_SOCKET;     WSAData w_data; #else \/\/ *nix     int serv_socket; #endif      void handlingLoop();  public:     TcpServer(const uint16_t port, handler_function_t handler);     ~TcpServer();      \/\/! Set client handler     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 \/\/ Windows NT     SOCKET socket;     SOCKADDR_IN address;     char buffer[buffer_size]; public:     Client(SOCKET socket, SOCKADDR_IN address); #else \/\/ *nix     int socket;     struct sockaddr_in address;     char buffer[buffer_size]; public:     Client(int socket, struct sockaddr_in address); #endif public:     Client(const Client&amp; 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 \/\/ TCPSERVER_H <\/code><\/pre>\n<p>  <\/p>\n<p>\u041a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043c\u0435\u0442\u0438\u0442\u044c \u0440\u0430\u0437\u043b\u0438\u0447\u0438\u044f \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b \u043f\u043e\u043c\u0438\u043c\u043e \u0440\u0430\u0437\u043d\u044b\u0445 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u043c\u044b\u0445 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u0447\u043d\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432 \u0440\u0430\u0437\u043b\u0438\u0447\u0430\u044e\u0442\u0441\u044f \u0440\u0430\u0437\u0432\u0435 \u0447\u0442\u043e \u0442\u0438\u043f \u0441\u043e\u043a\u0435\u0442\u0430 \u2014 <code>SOCKET<\/code> \u0434\u043b\u044f Windows \u0438 (\u043a\u0430\u043a \u0431\u044b \u0441\u0442\u0440\u0430\u043d\u043d\u043e \u044d\u0442\u043e \u043d\u0435 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b\u043e) <code>int<\/code> \u0434\u043b\u044f Linux. \u0420\u0430\u0437\u043d\u0438\u0446\u0430 \u0437\u0434\u0435\u0441\u044c \u043b\u0438\u0448\u044c \u0432 \u0442\u043e\u043c \u0447\u0442\u043e Linux \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 int \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u043e\u043a\u0435\u0442\u0430, \u0432 \u0442\u043e \u0432\u0440\u0435\u043c\u044f \u043a\u0430\u043a \u0432 Windows \u0437\u0430\u0434\u0435\u043a\u043b\u0430\u0440\u0438\u0440\u043e\u0432\u0430\u043d \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0442\u0438\u043f \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0440\u0430\u0437\u043d\u044b\u0439 \u0440\u0430\u0437\u043c\u0435\u0440 \u0438 \u0437\u043d\u0430\u0447\u043d\u043e\u0441\u0442\u044c \u0446\u0435\u043b\u043e\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u0442\u0438\u043f\u0430, \u0447\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u0432 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0445 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u0447\u043d\u044b\u0445 \u0444\u0430\u0439\u043b\u0430\u0445:<\/p>\n<p>  <\/p>\n<pre><code class=\"cpp\">\/\/file _socket_types.h \/\/... #if 1 typedef UINT_PTR    SOCKET; #else typedef INT_PTR     SOCKET; #endif \/\/...  \/\/file BaseTsd.h \/\/... #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 \/\/...<\/code><\/pre>\n<p>  <\/p>\n<p>\u0422\u0430\u043a \u0436\u0435 \u0432 Windows \u0447\u0430\u0441\u0442\u0438 TcpServer-\u0445\u0435\u0434\u0435\u0440\u0430 \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u043b\u044f \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 WinSocket \u2014 <code>WSAData w_data;<\/code>(\u0441\u043c. <a href=\"https:\/\/docs.microsoft.com\/en-us\/windows\/win32\/api\/winsock\/ns-winsock-wsadata\">WSAData<\/a>)<\/p>\n<p>  <\/p>\n<p>\u041f\u0435\u0440\u0435\u0439\u0434\u0451\u043c \u043a \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430:<\/p>\n<p>  <\/p>\n<p><strong>TcpServer.cpp<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"cpp\">#include &quot;..\/hdr\/TcpServer.h&quot; #include &lt;chrono&gt;  \/\/\u041a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442: \/\/port - \u043f\u043e\u0440\u0442 \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0431\u0443\u0434\u0435\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0441\u0435\u0440\u0432\u0435\u0440 \/\/handler - callback-\u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044f\u043c\u0430\u044f \u043f\u0440\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \/\/          \u043e\u0431\u044a\u0435\u043a\u0442 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u044e\u0442 \u043f\u0435\u0440\u0432\u044b\u043c \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u043c \u0432 callback \/\/          (\u043f\u0440\u0438\u043c\u0435\u0440 \u043b\u044f\u043c\u0431\u0434\u0430-\u0444\u0443\u043d\u043a\u0446\u0438\u0438: [](TcpServer::Client){...do something...}) TcpServer::TcpServer(const uint16_t port, handler_function_t handler) : port(port), handler(handler) {}  \/\/\u0414\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u0441\u0435\u0440\u0432\u0435\u0440 \u0435\u0441\u043b\u0438 \u043e\u043d \u0431\u044b\u043b \u0437\u0430\u043f\u0443\u0449\u0435\u043d \/\/\u0438 \u0432\u044b\u0447\u0438\u0449\u0430\u0435\u0442 \u0437\u0430\u0434\u0430\u043d\u043d\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e WinSocket TcpServer::~TcpServer() {   if(_status == status::up)     stop(); #ifdef _WIN32 \/\/ Windows NT     WSACleanup (); #endif }  \/\/\u0417\u0430\u0434\u0430\u0451\u0442 callback-\u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044f\u043c\u0443\u044e \u043f\u0440\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 void TcpServer::setHandler(TcpServer::handler_function_t handler) {this-&gt;handler = handler;}  \/\/Getter\/Setter \u043f\u043e\u0440\u0442\u0430 uint16_t TcpServer::getPort() const {return port;} uint16_t TcpServer::setPort( const uint16_t port) {     this-&gt;port = port;     restart(); \/\/\u041f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0435\u0441\u043b\u0438 \u0441\u0435\u0440\u0432\u0435\u0440 \u0431\u044b\u043b \u0437\u0430\u043f\u0443\u0449\u0435\u043d     return port; }  \/\/\u041f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0430 TcpServer::status TcpServer::restart() {     if(_status == status::up)       stop ();     return start(); }  \/\/ \u0412\u0445\u043e\u0434 \u0432 \u043f\u043e\u0442\u043e\u043a \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0439 void TcpServer::joinLoop() {handler_thread.join();}  \/\/\u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u0432 \u0431\u0443\u0444\u0435\u0440 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0438\u0445 \u0440\u0430\u0437\u043c\u0435\u0440 int TcpServer::Client::loadData() {return recv(socket, buffer, buffer_size, 0);} \/\/\u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c \u043d\u0430 \u0431\u0443\u0444\u0435\u0440 \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043e\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 char* TcpServer::Client::getData() {return buffer;} \/\/\u041e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u0443 bool TcpServer::Client::sendData(const char* buffer, const size_t size) const {   if(send(socket, buffer, size, 0) &lt; 0) return false;   return true; }  #ifdef _WIN32 \/\/ Windows NT \/\/\u0417\u0430\u043f\u0443\u0441\u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0430 TcpServer::status TcpServer::start() {     WSAStartup(MAKEWORD(2, 2), &amp;w_data); \/\/\u0417\u0430\u0434\u0430\u0451\u043c \u0432\u0435\u0440\u0441\u0438\u044e WinSocket      SOCKADDR_IN address; \/\/\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0445\u043e\u0441\u0442\/\u043f\u043e\u0440\u0442\/\u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b \u0434\u043b\u044f \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u043e\u043a\u0435\u0442\u0430     address.sin_addr.S_un.S_addr = INADDR_ANY; \/\/\u041b\u044e\u0431\u043e\u0439 IP \u0430\u0434\u0440\u0435\u0441\u0441     address.sin_port = htons(port); \/\/\u0417\u0430\u0434\u0430\u0451\u043c \u043f\u043e\u0440\u0442     address.sin_family = AF_INET; \/\/AF_INET - C\u0435\u043c\u0435\u0439\u0441\u0442\u0432\u043e \u0430\u0434\u0440\u0435\u0441\u043e\u0432 \u0434\u043b\u044f IPv4      \/\/\u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u043d\u0430\u0448 \u0441\u043e\u043a\u0435\u0442 \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u043b\u0438 \u043f\u0440\u043e\u0448\u043b\u0430 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f     \/\/\u0432 \u043f\u0440\u043e\u0442\u0438\u0432\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0441\u0442\u0430\u0442\u0443\u0441 \u0441 \u043e\u0448\u0438\u0431\u043a\u043e\u0439     if(static_cast&lt;int&gt;(serv_socket = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR) return _status = status::err_socket_init;     \/\/\u041f\u0440\u0438\u0441\u0432\u0430\u0438\u0432\u0430\u0435\u043c \u043a \u0441\u043e\u043a\u0435\u0442\u0443 \u0430\u0434\u0440\u0435\u0441\u0441 \u0438 \u043f\u043e\u0440\u0442 \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u043d\u0430 \u043a\u043e\u0440\u0435\u043a\u0442\u043d\u043e\u0441\u0442\u044c \u0441\u043e\u043a\u0435\u0442     \/\/\u0432 \u043f\u0440\u043e\u0442\u0438\u0432\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0441\u0442\u0430\u0442\u0443\u0441 \u0441 \u043e\u0448\u0438\u0431\u043a\u043e\u0439     if(bind(serv_socket, (struct sockaddr*)&amp;address, sizeof(address)) == SOCKET_ERROR) return _status = status::err_socket_bind;     \/\/\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u043f\u0440\u043e\u0441\u043b\u0443\u0448\u043a\u0443 \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043b\u0430\u0441\u044c \u043b\u0438 \u043e\u043d\u0430     \/\/\u0432 \u043f\u0440\u043e\u0442\u0438\u0432\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0441\u0442\u0430\u0442\u0443\u0441 \u0441 \u043e\u0448\u0438\u0431\u043a\u043e\u0439     if(listen(serv_socket, SOMAXCONN) == SOCKET_ERROR) return _status = status::err_socket_listening;      \/\/\u041c\u0435\u043d\u044f\u0435\u043c \u0441\u0442\u0430\u0442\u0443\u0441, \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0439 \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0441\u0442\u0430\u0442\u0443\u0441     _status = status::up;     handler_thread = std::thread([this]{handlingLoop();});     return _status; }  \/\/\u041e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 void TcpServer::stop() {     _status = status::close; \/\/\u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0441\u0442\u0430\u0442\u0443\u0441\u0430     closesocket (serv_socket); \/\/\u0417\u0430\u043a\u0440\u044b\u0442\u0438\u0435 \u0441\u043e\u043a\u0435\u0442\u0430     joinLoop(); \/\/\u041e\u0436\u0438\u0434\u0430\u043d\u0438\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f     for(std::thread&amp; cl_thr : client_handler_threads) \/\/\u041f\u0435\u0440\u0435\u0431\u043e\u0440 \u0432\u0441\u0435\u0445 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u0438\u0445 \u043f\u043e\u0442\u043e\u043a\u043e\u0432         cl_thr.join(); \/\/ \u041e\u0436\u0438\u0434\u0430\u043d\u0438\u0435 \u0438\u0445 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f     client_handler_threads.clear (); \/\/ \u041e\u0447\u0438\u0441\u0442\u043a\u0430 \u0441\u043f\u0438\u0441\u043a\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u0438\u0445 \u043f\u043e\u0442\u043e\u043a\u043e\u0432     client_handling_end.clear (); \/\/ \u041e\u0447\u0438\u0441\u0442\u043a\u0430 \u0441\u043f\u0438\u0441\u043a\u0430 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u0432 \u0437\u0430\u0432\u0435\u0440\u0448\u0451\u043d\u043d\u044b\u0445 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u0438\u0445 \u043f\u043e\u0442\u043e\u043a\u043e\u0432 }  \/\/ \u0424\u0443\u043d\u043a\u0438\u0446\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0439 void TcpServer::handlingLoop() {     while(_status == status::up) {         SOCKET client_socket; \/\/\u0421\u043e\u043a\u0435\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u0430         SOCKADDR_IN client_addr; \/\/\u0410\u0434\u0440\u0435\u0441\u0441 \u043a\u043b\u0438\u0435\u043d\u0442\u0430         int addrlen = sizeof(client_addr); \/\/\u0420\u0430\u0437\u043c\u0435\u0440 \u0430\u0434\u0440\u0435\u0441\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0430         \/\/\u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0441\u043e\u043a\u0435\u0442\u0430 \u0438 \u0430\u0434\u0440\u0435\u0441\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0430         \/\/(\u0435\u0441\u043b\u0438 \u0441\u043e\u043a\u0435\u0442 \u043a\u043e\u0440\u0435\u043a\u0442\u0435\u043d \u0438 \u0441\u0435\u0440\u0432\u0435\u0440 \u0437\u0430\u0440\u0443\u0449\u0435\u043d \u0437\u0430\u043f\u0443\u0441\u043a \u043f\u043e\u0442\u043e\u043a\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438)         if ((client_socket = accept(serv_socket, (struct sockaddr*)&amp;client_addr, &amp;addrlen)) != 0 &amp;&amp; _status == status::up){             client_handler_threads.push_back(std::thread([this, &amp;client_socket, &amp;client_addr] {                 handler(Client(client_socket, client_addr)); \/\/\u0417\u0430\u043f\u0443\u0441\u043a callback-\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430                 \/\/\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0430 \u0432 \u0441\u043f\u0438\u0441\u043e\u043a \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u0432 \u0437\u0430\u0432\u0435\u0440\u0448\u0451\u043d\u043d\u044b\u0445 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u0438\u0445 \u043f\u043e\u0442\u043e\u043a\u043e\u0432                 client_handling_end.push_back (std::this_thread::get_id());              }));         }         \/\/\u041e\u0447\u0438\u0441\u0442\u043a\u0430 \u043e\u0442\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u044b\u0445 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u0438\u0445 \u043f\u043e\u0442\u043e\u043a\u043e\u0432         if(!client_handling_end.empty())           for(std::list&lt;std::thread::id&gt;::iterator id_it = client_handling_end.begin (); !client_handling_end.empty() ; id_it = client_handling_end.begin())             for(std::list&lt;std::thread&gt;::iterator thr_it = client_handler_threads.begin (); thr_it != client_handler_threads.end () ; ++thr_it)               if(thr_it-&gt;get_id () == *id_it) {                 thr_it-&gt;join();                 client_handler_threads.erase(thr_it);                 client_handling_end.erase (id_it);                 break;               }          std::this_thread::sleep_for(std::chrono::milliseconds(50));     } }  \/\/ \u041a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u043f\u043e \u0441\u043e\u043a\u0435\u0442\u0443 \u0438 \u0430\u0434\u0440\u0435\u0441\u0443 TcpServer::Client::Client(SOCKET socket, SOCKADDR_IN address) : socket(socket), address(address) {} \/\/ \u041a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f TcpServer::Client::Client(const TcpServer::Client&amp; other) : socket(other.socket), address(other.address) {}  TcpServer::Client::~Client() {     shutdown(socket, 0); \/\/\u041e\u0431\u0440\u044b\u0432 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u043a\u0435\u0442\u0430     closesocket(socket); \/\/\u0417\u0430\u043a\u0440\u044b\u0442\u0438\u0435 \u0441\u043e\u043a\u0435\u0442\u0430 }  \/\/ \u0413\u0435\u0442\u0442\u0435\u0440\u044b \u0445\u043e\u0441\u0442\u0430 \u0438 \u043f\u043e\u0440\u0442\u0430 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 \/\/ *nix  \/\/\u0417\u0430\u043f\u0443\u0441\u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0430 (\u043f\u043e \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0438 \u0441 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u0434\u043b\u044f Windows) 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 *)&amp;server , sizeof(server)) &lt; 0) return _status = status::err_socket_bind;     if(listen(serv_socket, 3) &lt; 0)return _status = status::err_socket_listening;      _status = status::up;     handler_thread = std::thread([this]{handlingLoop();});     return _status; }  \/\/\u041e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 void TcpServer::stop() {     _status = status::close;     close(serv_socket);     joinLoop();     for(std::thread&amp; cl_thr : client_handler_threads)         cl_thr.join();     client_handler_threads.clear ();     client_handling_end.clear (); }  \/\/ \u0424\u0443\u043d\u043a\u0438\u0446\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0439 (\u043f\u043e \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0438 \u0441 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u0434\u043b\u044f Windows) 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*)&amp;client_addr, (socklen_t*)&amp;addrlen)) &gt;= 0 &amp;&amp; _status == status::up)             client_handler_threads.push_back(std::thread([this, &amp;client_socket, &amp;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&lt;std::thread::id&gt;::iterator id_it = client_handling_end.begin (); !client_handling_end.empty() ; id_it = client_handling_end.begin())             for(std::list&lt;std::thread&gt;::iterator thr_it = client_handler_threads.begin (); thr_it != client_handler_threads.end () ; ++thr_it)               if(thr_it-&gt;get_id () == *id_it) {                 thr_it-&gt;join();                 client_handler_threads.erase(thr_it);                 client_handling_end.erase (id_it);                 break;               }          std::this_thread::sleep_for(std::chrono::milliseconds(50));     } }  \/\/ \u041a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u043f\u043e \u0441\u043e\u043a\u0435\u0442\u0443 \u0438 \u0430\u0434\u0440\u0435\u0441\u0443 TcpServer::Client::Client(int socket, struct sockaddr_in address) : socket(socket), address(address) {} \/\/ \u041a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f TcpServer::Client::Client(const TcpServer::Client&amp; other) : socket(other.socket), address(other.address) {}  TcpServer::Client::~Client() {     shutdown(socket, 0); \/\/\u041e\u0431\u0440\u044b\u0432 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u043a\u0435\u0442\u0430     close(socket); \/\/\u0417\u0430\u043a\u0440\u044b\u0442\u0438\u0435 \u0441\u043e\u043a\u0435\u0442\u0430 }  \/\/ \u0413\u0435\u0442\u0442\u0435\u0440\u044b \u0445\u043e\u0441\u0442\u0430 \u0438 \u043f\u043e\u0440\u0442\u0430 uint32_t TcpServer::Client::getHost() {return address.sin_addr.s_addr;} uint16_t TcpServer::Client::getPort() {return address.sin_port;}  #endif<\/code><\/pre>\n<p>  <\/p>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0434\u043b\u044f Linux \u0438 Windows \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0438\u0434\u0435\u043d\u0442\u0438\u0447\u043d\u0430 \u0437\u0430 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c \u043d\u0435\u043a\u043e\u0442\u0440\u044b\u0445 \u043c\u0435\u0441\u0442, \u043e\u0431\u0443\u0441\u043b\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u0440\u0430\u0437\u0432\u0435 \u0447\u0442\u043e \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u043c\u0438 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430\u043c\u0438 \u0445\u0440\u0430\u043d\u044f\u0449\u0438\u043c \u0430\u0434\u0440\u0435\u0441\u0430(<code>struct sockaddr_in\/SOCKADDR_IN, struct sockaddr\/SOCKADDR<\/code>) \u0438 \u0441\u043e\u043a\u0435\u0442\u044b(<code>int\/SOCKET<\/code>), \u0430 \u0442\u0430\u043a \u0436\u0435 \u043d\u0430\u043b\u0438\u0447\u0438\u0435\u043c \u0443 Windows \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0432\u0435\u0440\u0441\u0438\u0438 WinSocket(<code>WSAData<\/code>).<\/p>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f:<\/p>\n<p>  <\/p>\n<p><strong>main.cpp<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"cpp\">#include &quot;server\/hdr\/TcpServer.h&quot;  #include &lt;iostream&gt;  \/\/\u041f\u0430\u0440\u0441\u0435\u0440 ip \u0432 std::string std::string getHostStr(const TcpServer::Client&amp; client) {   uint32_t ip = client.getHost ();   return std::string() + std::to_string(int(reinterpret_cast&lt;char*&gt;(&amp;ip)[0])) + '.' +          std::to_string(int(reinterpret_cast&lt;char*&gt;(&amp;ip)[1])) + '.' +          std::to_string(int(reinterpret_cast&lt;char*&gt;(&amp;ip)[2])) + '.' +          std::to_string(int(reinterpret_cast&lt;char*&gt;(&amp;ip)[3])) + ':' +          std::to_string( client.getPort ()); }  int main() {   \/\/\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 TcpServer \u0441 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0435\u0439 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430\u043c\u0438 \u043f\u043e\u0440\u0442\u0430 \u0438 \u043b\u044f\u0431\u0434\u0430-\u0444\u0443\u043d\u0446\u0438\u0438 \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a \u043a\u043b\u0438\u0435\u043d\u0442\u0430   TcpServer server( 8080,        [](TcpServer::Client client){            \/\/\u0412\u044b\u0432\u043e\u0434 \u0430\u0434\u0440\u0435\u0441\u0430 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0432\u0448\u0435\u0433\u043e \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u044c           std::cout&lt;&lt;&quot;Connected host:&quot;&lt;&lt;getHostStr(client)&lt;&lt;std::endl;            \/\/\u041e\u0436\u0438\u0434\u0430\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u043e\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u0430           int size = 0;           while (size == 0) size = client.loadData ();            \/\/\u0412\u044b\u0432\u043e\u0434 \u0440\u0430\u0437\u043c\u0435\u0440\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0441\u0430\u043c\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u044c           std::cout               &lt;&lt;&quot;size: &quot;&lt;&lt;size&lt;&lt;&quot; bytes&quot;&lt;&lt;std::endl               &lt;&lt; client.getData() &lt;&lt; std::endl;            \/\/\u041e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 \u043e\u0442\u0432\u0435\u0442\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0443           const char answer[] = &quot;Hello World from Server&quot;;           client.sendData(answer, sizeof (answer));       }    );    \/\/\u0417\u0430\u043f\u0443\u0441\u043a \u0441\u0435\u0440\u0435\u0432\u0435\u0440\u0430   if(server.start() == TcpServer::status::up) {     \/\/\u0415\u0441\u043b\u0438 \u0441\u0435\u0440\u0432\u0435\u0440 \u0437\u0430\u043f\u0443\u0449\u0435\u043d \u0432\u044b\u0432\u0435\u0441\u0442\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0438 \u0432\u043e\u0439\u0442\u0438 \u0432 \u043f\u043e\u0442\u043e\u043a \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u0439 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432       std::cout&lt;&lt;&quot;Server is up!&quot;&lt;&lt;std::endl;       server.joinLoop();   } else {     \/\/\u0415\u0441\u043b\u0438 \u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0435 \u0437\u0430\u043f\u0443\u0449\u0435\u043d \u0432\u044b\u0432\u043e\u0434 \u043a\u043e\u0434\u0430 \u043e\u0448\u0438\u0431\u043a\u0438 \u0438 \u0437\u0430\u0432\u0435\u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b       std::cout&lt;&lt;&quot;Server start error! Error code:&quot;&lt;&lt; int(server.getStatus()) &lt;&lt;std::endl;       return -1;   }  }<\/code><\/pre>\n<p>  <\/p>\n<p><a href=\"https:\/\/github.com\/sh13max\/TcpServer\">\u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 GitHub<\/a><\/p>\n<p>  <\/p>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0432\u0430\u0448\u0438\u0435\u0441\u044f \u0441\u0442\u0430\u0442\u044c\u0438:<\/p>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/www.rsdn.org\/article\/unix\/sockets.xml\">\u041f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u043e\u043a\u0435\u0442\u043e\u0432 \u0432 Linux<\/a><\/li>\n<li><a href=\"https:\/\/habr.com\/ru\/post\/327574\/\">\u041f\u0440\u043e\u0441\u0442\u043e\u0439 \u0438 \u0431\u044b\u0441\u0442\u0440\u044b\u0439 \u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0430 C\/C++&#8230;<\/a><\/li>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/windows\/win32\/winsock\/winsock-server-application\">Winsock Server Application<\/a><\/li>\n<\/ul>\n<\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/503432\/\"> https:\/\/habr.com\/ru\/post\/503432\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/post\/503432\/\">\n<p>\u041a\u0430\u043a-\u0442\u043e \u0440\u0430\u0437 \u0432\u0441\u0442\u0430\u043b\u0430 \u0437\u0430\u0434\u0430\u0447\u0430 \u043f\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u0438 \u0431\u044b\u0441\u0442\u0440\u043e\u0433\u043e \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u0442\u043e\u0447\u043d\u043e\u0433\u043e TCP\/IP \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043d\u0430 C++ \u0438 \u043f\u0440\u0438 \u044d\u0442\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u043b \u0438\u0437 \u043f\u043e\u0434 Windows \u0438 Linux \u0431\u0435\u0437 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u043a\u0430\u043a-\u043b\u0438\u0431\u043e \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u043a\u043e\u0434 \u0437\u0430 \u043f\u0440\u0435\u0434\u0435\u043b\u0430\u043c\u0438 \u043a\u043b\u0430\u0441\u0441\u0430 \u0441\u0430\u043c\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0435\u0440\u0430. \u0420\u0430\u043d\u0435\u0435, \u043d\u0430 \u0447\u0438\u0441\u0442\u043e\u043c C++ \u0431\u0435\u0437 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u0432\u0440\u043e\u0434\u0435 Qt, Tcp-\u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0435 \u043f\u0438\u0441\u0430\u043b, \u0438 \u043f\u0440\u0435\u0434\u0432\u0435\u0449\u0430\u043b \u0441\u0435\u0431\u0435 \u0434\u043e\u043b\u0433\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u043c\u0443\u0447\u0435\u043d\u0438\u0439 \u0441 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u043e-\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c\u044e. \u041d\u043e \u043a\u0430\u043a \u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u0432\u0441\u0451 \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u043f\u0440\u043e\u0449\u0435 \u0447\u0435\u043c \u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u043d\u0430 \u043f\u0435\u0440\u0432\u044b\u0439 \u0432\u0437\u0433\u043b\u044f\u0434, \u0432\u0435\u0434\u044c \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b \u0441\u043e\u043a\u0435\u0442\u043e\u0432 \u043e\u0431\u043e\u0438\u0445 \u0441\u0438\u0441\u0442\u0435\u043c \u043f\u043e\u0445\u043e\u0436\u0438 \u043a\u0430\u043a \u0434\u0432\u0435 \u043a\u0430\u043f\u043b\u0438 \u0432\u043e\u0434\u044b \u0438 \u0440\u0430\u0437\u043b\u0438\u0447\u0430\u044e\u0442\u0441\u044f \u043b\u0438\u0448\u044c \u0432 \u043c\u0435\u043b\u043a\u0438\u0445 \u0434\u0435\u0442\u0430\u043b\u044f\u0445.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-304117","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/304117","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=304117"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/304117\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=304117"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=304117"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=304117"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}