SSH рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдПрдХ рджреВрд░рд╕реНрде рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдХреЗ рд╕рд╛рде рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдбреЗрдЯрд╛ рд╡рд┐рдирд┐рдордп

рдЕрдЪреНрдЫреЗ рджрд┐рди, рджреЛрд╕реНрддреЛрдВ рдФрд░ рд╕рд╣рдХрд░реНрдорд┐рдпреЛрдВред рдореЗрд░рд╛ рдирд╛рдо рдЕрднреА рднреА рджрд┐рдорд┐рддреНрд░реА рд╕реНрдорд┐рд░рдиреЛрд╡ рд╣реИ, рдФрд░ рдореИрдВ рдЕрднреА рднреА рдЕрдкрдиреЗ рдмрд╣реБрдд рдЦреБрд╢реА рдХреЗ рд▓рд┐рдП рдЖрдИрдПрд╕рдкреАрд╕рд┐рд╕реНрдЯрдо рдХреЗ рдбреЗрд╡рд▓рдкрд░ рд╣реВрдВред рдХреБрдЫ рд╕рдордп рдкрд╣рд▓реЗ, рдореИрдВрдиреЗ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдПрдХ рдирдИ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдкрд░ рдХрд╛рдо рд╢реБрд░реВ рдХрд┐рдпрд╛, рдЬрд┐рд╕рдиреЗ рдореБрдЭреЗ рдмрд╣реБрдд рдкреНрд░реЗрд░рд┐рдд рдХрд┐рдпрд╛, рдХреНрдпреЛрдВрдХрд┐ рдирдпрд╛ рд╣рдорд╛рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ рд╡рд┐рд░рд╛рд╕рдд рдХреЛрдб рдХреА рдХрдореА рдФрд░ рдкреБрд░рд╛рдиреЗ рд╕рдВрдХрд▓рдХ рдХреЗ рд▓рд┐рдП рд╕рдорд░реНрдерди рд╣реИред рдирдорд╕реНрдХрд╛рд░, рдмреВрд╕реНрдЯ, рд╕реА ++ 17 рдФрд░ рдЖрдзреБрдирд┐рдХ рд╡рд┐рдХрд╛рд╕ рдХреЗ рдЕрдиреНрдп рд╕рднреА рдЦреБрд╢рд┐рдпрд╛рдБред

рдРрд╕рд╛ рд╣реБрдЖ рдХрд┐ рдореЗрд░реА рд╕рднреА рдкрд┐рдЫрд▓реА рдкрд░рд┐рдпреЛрдЬрдирд╛рдПрдВ рдХреНрд░рдорд╢рдГ рдмрд╣реБ-рдереНрд░реЗрдбреЗрдб рдереАрдВ, рдореБрдЭреЗ рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рд╕рдорд╛рдзрд╛рдиреЛрдВ рдХреЗ рд╕рд╛рде рдмрд╣реБрдд рдХрдо рдЕрдиреБрднрд╡ рдерд╛ред рдЖрдзреБрдирд┐рдХ рд╢рдХреНрддрд┐рд╢рд╛рд▓реА рд╕рд╛рдзрдиреЛрдВ рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдЗрд╕ рд╡рд┐рдХрд╛рд╕ рдореЗрдВ рдпрд╣реА рдореЗрд░реЗ рд▓рд┐рдП рд╕рдмрд╕реЗ рд╕реБрдЦрдж рдмрди рдЧрдпрд╛ред

рдЕрдВрддрд┐рдо рд╕рдВрдмрдВрдзрд┐рдд рдХрд╛рд░реНрдпреЛрдВ рдореЗрдВ рд╕реЗ рдПрдХ Boost.Asio рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП рдПрдХ рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдЖрд╡реЗрджрди рдХреА рд╡рд╛рд╕реНрддрд╡рд┐рдХрддрд╛рдУрдВ рдореЗрдВ libssh2 рдкреБрд╕реНрддрдХрд╛рд▓рдп рдкрд░ рдПрдХ рдЖрд╡рд░рдг рд▓рд┐рдЦрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдереА, рдФрд░ рджреЛ рд╕реЗ рдЕрдзрд┐рдХ рдереНрд░реЗрдбреНрд╕ рдХреЛ рдкреИрджрд╛ рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рдирд╣реАрдВ рдерд╛ред рдореИрдВ рдЗрд╕ рдмрд╛рд░реЗ рдореЗрдВ рдмрддрд╛рдКрдВрдЧрд╛



рдиреЛрдЯ: рд▓реЗрдЦрдХ рдорд╛рдирддрд╛ рд╣реИ рдХрд┐ рдкрд╛рдардХ рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рд╡рд┐рдХрд╛рд╕ рдФрд░ рдмрдврд╝рд╛рд╡рд╛ рдХреЗ рдореВрд▓ рд╕рд┐рджреНрдзрд╛рдВрддреЛрдВ рд╕реЗ рдкрд░рд┐рдЪрд┐рдд рд╣реИ :: asioред

рдХрд╛рд░реНрдп


рд╕рд╛рдорд╛рдиреНрдп рд╢рдмреНрджреЛрдВ рдореЗрдВ, рдХрд╛рд░реНрдп рдирд┐рдореНрдирд╛рдиреБрд╕рд╛рд░ рдерд╛: rsa рдХреБрдВрдЬреА рдпрд╛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдирд╛рдо рдФрд░ рдкрд╛рд╕рд╡рд░реНрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рдПрдХ рджреВрд░рд╕реНрде рд╕рд░реНрд╡рд░ рд╕реЗ рдХрдиреЗрдХреНрдЯ; рд░рд┐рдореЛрдЯ рдорд╢реАрди рдкрд░ рдПрдХ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдЕрдкрд▓реЛрдб рдХрд░реЗрдВ рдФрд░ рдЗрд╕реЗ рдЪрд▓рд╛рдПрдВ; рдЙрд╕рдХреЗ рдЬрд╡рд╛рдм рдкрдврд╝реЗрдВ рдФрд░ рдЙрд╕реЗ рдЙрд╕реА рдХрдиреЗрдХреНрд╢рди рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдХрдорд╛рдВрдб рднреЗрдЬреЗрдВред рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, рдЬрд╝рд╛рд╣рд┐рд░ рд╣реИ, рдкреНрд░рд╡рд╛рд╣ рдХреЛ рдЕрд╡рд░реБрджреНрдз рдХрд┐рдП рдмрд┐рдирд╛ (рдЬреЛ рдХреБрд▓ рдкреВрд▓ рдХрд╛ рдЖрдзрд╛ рд╕рдВрднрд╡ рд╣реИ)ред

рдбрд┐рд╕реНрдХреНрд▓реЗрдорд░ : рдореБрдЭреЗ рдкрддрд╛ рд╣реИ рдХрд┐ рдкреЛрдХреЛ рдПрд╕рдПрд╕рдПрдЪ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдореБрдЭреЗ рдЕрд╕рд┐рдпреЛ рдХреЗ рд╕рд╛рде рдЙрд╕рд╕реЗ рд╢рд╛рджреА рдХрд░рдиреЗ рдХрд╛ рдХреЛрдИ рддрд░реАрдХрд╛ рдирд╣реАрдВ рдорд┐рд▓рд╛, рдФрд░ рдореЗрд░реЗ рдЦреБрдж рдХреЗ рдХреБрдЫ :-) рд▓рд┐рдЦрдирд╛ рдЕрдзрд┐рдХ рджрд┐рд▓рдЪрд╕реНрдк рдерд╛ред

рдкреНрд░рд╛рд░рдВрдн


рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХреЛ рдЖрд░рдВрдн рдФрд░ рдХрдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рд╕рд╛рдорд╛рдиреНрдп рд╕рд┐рдВрдЧрд▓рдЯрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рдирд┐рд░реНрдгрдп рд▓рд┐рдпрд╛:

Init ()
class LibSSH2 { public: static void Init() { static LibSSH2 instance; } private: explicit LibSSH2() { if (libssh2_init(0) != 0) { throw std::runtime_error("libssh2 initialization failed"); } } ~LibSSH2() { std::cout << "shutdown libssh2" << std::endl; libssh2_exit(); } }; 



рдореЗрд░реА рдкрд╕рдВрджреАрджрд╛ рд╣реИрдВрдбрдмреБрдХ, "рдП рдерд╛рдЙрдЬреЗрдВрдб рдПрдВрдб рд╡рди рд╡реЗрдЬ рдЯреВ рд╢реВрдЯ рдпреВ рд▓реЗрдЧ рдЗрди рд╕реА ++" рдХреЗ рдЕрдиреБрд╕рд╛рд░, рдЗрд╕ рдирд┐рд░реНрдгрдп рдореЗрдВ рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рдиреБрдХрд╕рд╛рди рд╣реИред рдпрджрд┐ рдХреЛрдИ рдРрд╕реА рдзрд╛рд░рд╛ рдЙрддреНрдкрдиреНрди рдХрд░рддрд╛ рд╣реИ рдЬрд┐рд╕реЗ рд╡реЗ рдкреНрд░рд╣рд╛рд░ рдХрд░рдирд╛ рднреВрд▓ рдЬрд╛рддреЗ рд╣реИрдВ, рдФрд░ рдореБрдЦреНрдп рдПрдХ рдкрд╣рд▓реЗ рд╕рдорд╛рдкреНрдд рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рджрд┐рд▓рдЪрд╕реНрдк рд╡рд┐рд╢реЗрд╖ рдкреНрд░рднрд╛рд╡ рдЙрддреНрдкрдиреНрди рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВред рд▓реЗрдХрд┐рди рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, рдореИрдВ рдЗрд╕ рд╕рдВрднрд╛рд╡рдирд╛ рдХреЛ рдзреНрдпрд╛рди рдореЗрдВ рдирд╣реАрдВ рд░рдЦреВрдВрдЧрд╛ред

рдореБрдЦреНрдп рд╕рдВрд╕реНрдерд╛рдПрдБ


рдЙрджрд╛рд╣рд░рдг рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж, рдпрд╣ рд╕реНрдкрд╖реНрдЯ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ рдХрд┐ рд╣рдорд╛рд░реЗ рдЫреЛрдЯреЗ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХреЗ рд▓рд┐рдП рд╣рдореЗрдВ рддреАрди рд╕рд░рд▓ рд╕рдВрд╕реНрдерд╛рдУрдВ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ: рд╕реЙрдХреЗрдЯ, рд╕рддреНрд░ рдФрд░ рдЪреИрдирд▓ред рдЪреВрдВрдХрд┐ рд╕рд┐рдВрдХреНрд░реЛрдирд╕ рдЯреВрд▓ рдХреЗ рд▓рд┐рдП рдпрд╣ рдЕрдЪреНрдЫрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╣рдо рдЕрд╕рд┐рдпреЛ рдХреЛ рдПрдХ рддрд░рдл рдЫреЛрдбрд╝ рджреЗрдВрдЧреЗред

рдЪрд▓реЛ рдПрдХ рд╕рд╛рдзрд╛рд░рдг рд╕реЙрдХреЗрдЯ рд╕реЗ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВ:

рд╕реЙрдХреЗрдЯ
 class Socket { public: explicit Socket() : m_sock(socket(AF_INET, SOCK_STREAM, 0)) { if (m_sock == -1) { throw std::runtime_error("failed to create socket"); } } ~Socket() { close(m_sock); } private: int m_sock = -1; } 


рдЕрдм рд╕рддреНрд░:

рд╕рддреНрд░
 class Session { public: explicit Session(const bool enable_compression) : m_session(libssh2_session_init()) { if (m_session == nullptr) { throw std::runtime_error("failed to create libssh2 session"); } libssh2_session_set_blocking(m_session, 0); if (enable_compression) { libssh2_session_flag(m_session, LIBSSH2_FLAG_COMPRESS, 1); } } ~Session() { const std::string desc = "Shutting down libssh2 session"; libssh2_session_disconnect(m_session, desc.c_str()); libssh2_session_free(m_session); } private: LIBSSH2_SESSION *m_session; } 


рдЪреВрдВрдХрд┐ рдЕрдм рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдХ рд╕реЙрдХреЗрдЯ рдФрд░ рдПрдХ рд╕рддреНрд░ рд╣реИ, рдЗрд╕рд▓рд┐рдП libssh2 рдХреА рд╡рд╛рд╕реНрддрд╡рд┐рдХрддрд╛рдУрдВ рдореЗрдВ рдПрдХ рд╕реЙрдХреЗрдЯ рдХреЗ рд▓рд┐рдП рдкреНрд░рддреАрдХреНрд╖рд╛ рдлрд╝рдВрдХреНрд╢рди рд▓рд┐рдЦрдирд╛ рдЕрдЪреНрдЫрд╛ рд╣реЛрдЧрд╛:

рдкреНрд░рддреАрдХреНрд╖рд╛рд░рдд рдЧрд░реНрддрд┐рдХрд╛
 int WaitSocket() const { pollfd fds{}; fds.fd = sock; fds.events = 0; if ((libssh2_session_block_directions(session) & LIBSSH2_SESSION_BLOCK_INBOUND) != 0) { fds.events |= POLLIN; } if ((libssh2_session_block_directions(session) & LIBSSH2_SESSION_BLOCK_OUTBOUND) != 0) { fds.events |= POLLOUT; } return poll(&fds, 1, 10); } 


рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдпрд╣ рдЙрдкрд░реНрдпреБрдХреНрдд рдЙрджрд╛рд╣рд░рдг рд╕реЗ рд╡реНрдпрд╛рд╡рд╣рд╛рд░рд┐рдХ рд░реВрдк рд╕реЗ рдЕрд▓рдЧ рдирд╣реАрдВ рд╣реИ, рд╕рд┐рд╡рд╛рдп рдЗрд╕рдХреЗ рдХрд┐ рдпрд╣ рдорддрджрд╛рди рдХреЗ рдмрдЬрд╛рдп рдЪреБрдирд┐рдВрджрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИред

рдЪреИрдирд▓ рдмрдирд╛ рд╣реБрдЖ рд╣реИред Libssh2 рдореЗрдВ рдХрдИ рдкреНрд░рдХрд╛рд░ рдХреЗ рдЪреИрдирд▓ рд╣реИрдВ: рд╕рд░рд▓, рдПрд╕рд╕реАрдкреА, рдбрд╛рдпрд░реЗрдХреНрдЯ рдЯреАрд╕реАрдкреАред рд╣рдо рд╕рдмрд╕реЗ рд╕рд░рд▓, рдмреБрдирд┐рдпрд╛рджреА рдЪреИрдирд▓ рдореЗрдВ рд░реБрдЪрд┐ рд░рдЦрддреЗ рд╣реИрдВ:

рдЪреИрдирд▓
 class SimpleChannel { public: explicit SimpleChannel(session) { while ((m_channel = libssh2_channel_open_session(session) == nullptr && GetSessionLastError() == LIBSSH2_ERROR_EAGAIN) { WaitSocket(); } if (m_channel == nullptr) { throw std::runtime_error("Critical error while opening simple channel"); } } void SendEof() { while (libssh2_channel_send_eof(m_channel) == LIBSSH2_ERROR_EAGAIN) { WaitSocket(); } while (libssh2_channel_wait_eof(m_channel) == LIBSSH2_ERROR_EAGAIN) { WaitSocket(); } } ~SimpleChannel() { CloseChannel(); } private: void CloseChannel() { int rc; while ((rc = libssh2_channel_close(m_channel)) == LIBSSH2_ERROR_EAGAIN) { WaitSocket(); } libssh2_channel_free(m_channel); } LIBSSH2_CHANNEL *m_channel; }; 


рдЕрдм рдЬрдм рд╕рднреА рдмреБрдирд┐рдпрд╛рджреА рдЙрдкрдХрд░рдг рддреИрдпрд╛рд░ рд╣реИрдВ, рддреЛ рдпрд╣ рдореЗрдЬрдмрд╛рди рдХреЗ рд╕рд╛рде рд╕рдВрдмрдВрдз рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдиреЗ рдФрд░ рдЖрд╡рд╢реНрдпрдХ рдЬреЛрдбрд╝рддреЛрдбрд╝ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрдирд╛ рд╣реБрдЖ рд╣реИред рдЪреИрдирд▓ рдХреЗ рд▓рд┐рдП рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рд░рд┐рдХреЙрд░реНрдбрд┐рдВрдЧ рдФрд░ рддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ, рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рдмрд╣реБрдд рдЕрд▓рдЧ рд╣реЛрдВрдЧреЗ, рд▓реЗрдХрд┐рди рдХрдиреЗрдХреНрд╢рди рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдиреЗ рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдирд╣реАрдВ рд╣реИред

рдЗрд╕рд▓рд┐рдП, рд╣рдо рдЖрдзрд╛рд░ рд╡рд░реНрдЧ рд▓рд┐рдЦрддреЗ рд╣реИрдВ:

рдореВрд▓ рд╕рдВрдмрдВрдз
 class BaseConnectionImpl { protected: explicit BaseConnectionImpl(const SshConnectData &connect_data) ///<    ,     : m_session(connect_data.enable_compression) , m_connect_data(connect_data) { LibSSH2::Init(); ConnectSocket(); HandShake(); ProcessKnownHosts(); Auth(); } ///       bool CheckSocket(int type) const { pollfd fds{}; fds.fd = m_sock; fds.events = type; return poll(&fds, 1, 0) == 1; } bool WantRead() const { return CheckSocket(POLLIN); } bool WantWrite() const { return CheckSocket(POLLOUT); } /*   ,   ,       *  - . */ void ConnectSocket() {...} void HandShake() {...} void Auth() {...} class Socket m_sock; class Session m_session; class SimpleChannel; SshConnectData m_connect_data; }; 


рдЕрдм рд╣рдо рджреВрд░рд╕реНрде рд╣реЛрд╕реНрдЯ рд╕реЗ рдЬреБрдбрд╝рдиреЗ рдФрд░ рдЙрд╕ рдкрд░ рдХрд┐рд╕реА рднреА рдХрдорд╛рдВрдб рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рдмрд╕реЗ рд╕рд░рд▓ рд╡рд░реНрдЧ рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рддреИрдпрд╛рд░ рд╣реИрдВ:

рд╕рдордХрд╛рд▓рд┐рдХ рд╕рдВрдмрдВрдз
 class Connection::Impl : public BaseConnectionImpl { public: explicit Impl(const SshConnectData &connect_data) : BaseConnectionImpl(connect_data) {} template <typename Begin> void WriteToChannel(LIBSSH2_CHANNEL *channel, Begin ptr, size_t size) { do { int rc; while ((rc = libssh2_channel_write(channel, ptr, size)) == LIBSSH2_ERROR_EAGAIN) { WaitSocket(); } if (rc < 0) { break; } size -= rc; ptr += rc; } while (size != 0); } void ExecuteCommand(const std::string &command, const std::string &in = "") { SimpleChannel channel(*this); int return_code = libssh2_channel_exec(channel, command.c_str()); if (return_code != 0 && return_code != LIBSSH2_ERROR_EAGAIN) { throw std::runtime_error("Critical error while executing ssh command"); } if (!in.empty()) { WriteToChannel(channel, in.c_str(), in.size()); channel.SendEof(); } std::string response; for (;;) { int rc; do { std::array<char, 4096> buffer{}; rc = libssh2_channel_read(channel, buffer.data(), buffer.size()); if (rc > 0) { boost::range::copy(boost::adaptors::slice(buffer, 0, rc), std::back_inserter(response)); } else if (rc < 0 && rc != LIBSSH2_ERROR_EAGAIN) { throw std::runtime_error("libssh2_channel_read error (" + std::to_string(rc) + ")"); } } while (rc > 0); if (rc == LIBSSH2_ERROR_EAGAIN) { WaitSocket(); } else { break; } } } }; 


рдЕрдм рддрдХ, рд╣рдордиреЗ рдЬреЛ рдХреБрдЫ рднреА рд▓рд┐рдЦрд╛ рд╣реИ, рд╡рд╣ рдЕрдзрд┐рдХ рд╕рднреНрдп рд░реВрдк рдореЗрдВ libssh2 рдЙрджрд╛рд╣рд░рдгреЛрдВ рдХреА рдПрдХ рд╕рд░рд▓ рдХрдореА рд╣реИред рд▓реЗрдХрд┐рди рдЕрдм, рдЪреИрдирд▓ рдХреЗ рд▓рд┐рдП рдбреЗрдЯрд╛ рдХреЛ рддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рд░реВрдк рд╕реЗ рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рд╕рднреА рд╕рд░рд▓ рдЙрдкрдХрд░рдг рд╣реЛрдиреЗ рд╕реЗ, рд╣рдо рдЕрд╕рд┐рдпреЛ рдкрд░ рдЖрдЧреЗ рдмрдврд╝ рд╕рдХрддреЗ рд╣реИрдВред

рдорд╛рдирдХ рд╕реЙрдХреЗрдЯ рд╣реЛрдирд╛ рдЕрдЪреНрдЫрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдмрд╣реБрдд рд╡реНрдпрд╛рд╡рд╣рд╛рд░рд┐рдХ рдирд╣реАрдВ рд╣реИ рдпрджрд┐ рдЖрдкрдХреЛ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдореЗрдВ рдЕрдкрдирд╛ рд╡реНрдпрд╡рд╕рд╛рдп рдХрд░рддреЗ рд╕рдордп рдкрдврд╝рдиреЗ / рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рд░реВрдк рд╕реЗ рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдпрд╣рд╛рдБ рдмрдврд╝рд╛рд╡рд╛ :: asio :: ip :: tcp :: рд╕реЙрдХреЗрдЯ рдмрдЪрд╛рд╡ рдХреЗ рд▓рд┐рдП рдЖрддрд╛ рд╣реИ, рдПрдХ рдЕрджреНрднреБрдд рд╡рд┐рдзрд┐ рд╣реИ:

 async_wait(wait_type, WaitHandler) 

рдпрд╣ рдПрдХ рдирд┐рдпрдорд┐рдд рд╕реЙрдХреЗрдЯ рд╕реЗ рд╢рд╛рдирджрд╛рд░ рддрд░реАрдХреЗ рд╕реЗ рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдЬрд┐рд╕рдХреЗ рд▓рд┐рдП рд╣рдо рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдХрдиреЗрдХреНрд╢рди рдХреЛ рдЕрдЧреНрд░рд┐рдо рдФрд░ рдмрдврд╝рд╛рд╡рд╛ рджреЗрддреЗ рд╣реИрдВ :: asio :: io_context - рд╣рдорд╛рд░реЗ рдЖрд╡реЗрджрди рдХрд╛ рдирд┐рд╖реНрдкрд╛рджрди рд╕рдВрджрд░реНрднред

рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдХрдиреЗрдХреНрд╢рди рдирд┐рд░реНрдорд╛рддрд╛
 class AsyncConnection::Impl : public BaseConnectionImpl, public std::enable_shared_from_this<AsyncConnection::Impl> { public: Impl(boost::asio::io_context &context, const SshConnectData &connect_data) : BaseConnectionImpl(connect_data) , m_tcp_socket(context, tcp::v4(), m_sock.GetSocket()) { m_tcp_socket.non_blocking(true); } }; 



рдЕрдм рд╣рдореЗрдВ рд░рд┐рдореЛрдЯ рд╣реЛрд╕реНрдЯ рдкрд░ рдХреБрдЫ рдХрдорд╛рдВрдб рдХрд╛ рдирд┐рд╖реНрдкрд╛рджрди рд╢реБрд░реВ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдФрд░ рдЬреИрд╕реЗ рд╣реА рдЗрд╕рдХрд╛ рдбреЗрдЯрд╛ рдЖрддрд╛ рд╣реИ, рдЗрд╕реЗ рдХреБрдЫ рдХреЙрд▓рдмреИрдХ рдкрд░ рднреЗрдЬреЗрдВред

 void AsyncRun(const std::string &command, CallbackType &&callback) { m_read_callback = std::move(callback); auto ec = libssh2_channel_exec(*m_channel, command.c_str()); TryRead(); } 

рдЗрд╕ рдкреНрд░рдХрд╛рд░, рдХрдорд╛рдВрдб рдЪрд▓рд╛рдХрд░, рд╣рдо рдХрдВрдЯреНрд░реЛрд▓рд░рд╛рдЗрдб () рд╡рд┐рдзрд┐ рдореЗрдВ рдирд┐рдпрдВрддреНрд░рдг рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рддреЗ рд╣реИрдВред

 void TryRead() { if (m_read_in_progress) { return; } m_tcp_socket.async_wait(tcp::socket::wait_read, [this, self = shared_from_this()](auto ec) { if (WantRead()) { ReadHandler(ec); } if (m_complete) { return; } TryRead(); }); } 

рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд╣рдо рдЬрд╛рдВрдЪрддреЗ рд╣реИрдВ рдХрд┐ рд░реАрдбрд┐рдВрдЧ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдХреБрдЫ рдкрд┐рдЫрд▓реЗ рдХреЙрд▓ рд╕реЗ рдЪрд▓ рд░рд╣реА рд╣реИ рдпрд╛ рдирд╣реАрдВред рдпрджрд┐ рдирд╣реАрдВ, рддреЛ рд╣рдо рдкрдврд╝рдиреЗ рдХреЗ рд▓рд┐рдП рд╕реЙрдХреЗрдЯ рдХреА рддрддреНрдкрд░рддрд╛ рдХреА рдЕрдкреЗрдХреНрд╖рд╛ рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВред Share_from_this () рдХреЗ рдХреИрдкреНрдЪрд░ рдХреЗ рд╕рд╛рде рдПрдХ рдирд┐рдпрдорд┐рдд рд▓рдВрдмреЛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдкреНрд░рддреАрдХреНрд╖рд╛ рд╣реИрдВрдбрд▓рд░ рдХреЗ рд░реВрдк рдореЗрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред

WantRead () рдХреЛ рдХреЙрд▓ рдкрд░ рдзреНрдпрд╛рди рджреЗрдВред Async_wait, рдЬреИрд╕рд╛ рдХрд┐ рдпрд╣ рдирд┐рдХрд▓рд╛, рдЗрд╕рдХреА рдЦрд╛рдорд┐рдпрд╛рдВ рднреА рд╣реИрдВ, рдФрд░ рдмрд╕ рдЯрд╛рдЗрдордЖрдЙрдЯ рдХрд░рдХреЗ рд╡рд╛рдкрд╕ рдЖ рд╕рдХрддреЗ рд╣реИрдВред рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ рдЕрдирд╛рд╡рд╢реНрдпрдХ рдХрд╛рд░реНрд░рд╡рд╛рдЗрдпреЛрдВ рд╕реЗ рдмрдЪрдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рд╕рдордп-рд╕реАрдорд╛ рдХреЗ рдмрд┐рдирд╛ рдкреЛрд▓ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╕реЙрдХреЗрдЯ рдХреА рдЬрд╛рдВрдЪ рдХрд░рдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ - рдХреНрдпрд╛ рд╕реЙрдХреЗрдЯ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЕрдм рдкрдврд╝рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реИред рдпрджрд┐ рдирд╣реАрдВ, рддреЛ рд╣рдо рд╕рд┐рд░реНрдл TryRead () рдлрд┐рд░ рд╕реЗ рдЪрд▓рд╛рддреЗ рд╣реИрдВ рдФрд░ рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рддреЗ рд╣реИрдВред рдЕрдиреНрдпрдерд╛, рд╣рдо рддреБрд░рдВрдд рдХреЙрд▓рдмреИрдХ рдкрд░ рдбреЗрдЯрд╛ рдкрдврд╝рдирд╛ рдФрд░ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВред

 void ReadHandler(const boost::system::error_code &error) { if (error != boost::system::errc::success) { return; } m_read_in_progress = true; int ec = LIBSSH2_ERROR_EAGAIN; std::array<char, 4096> buffer {}; while ((ec = libssh2_channel_read(*m_channel, buffer.data(), buffer.size())) > 0) { std::string tmp; boost::range::copy(boost::adaptors::slice(buffer, 0, ec), std::back_inserter(tmp)); if (m_read_callback != nullptr) { m_read_callback(tmp); } } m_read_in_progress = false; } 

рдЗрд╕ рдкреНрд░рдХрд╛рд░, рд░рдирд┐рдВрдЧ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд╕реЗ рдПрдХ рдЕрдВрддрд╣реАрди рдПрд╕рд┐рдВрдХреНрд░реЛрдирд╕ рд░реАрдб рд╕рд╛рдЗрдХрд┐рд▓ рд╢реБрд░реВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рд╣рдорд╛рд░реЗ рд▓рд┐рдП рдЕрдЧрд▓рд╛ рдХрджрдо рдЖрд╡реЗрджрди рдХреЗ рд▓рд┐рдП рдирд┐рд░реНрджреЗрд╢ рднреЗрдЬрдирд╛ рд╣реЛрдЧрд╛:

 void AsyncWrite(const std::string &data, WriteCallbackType &&callback) { m_input += data; m_write_callback = std::move(callback); TryWrite(); } 

рдХрдиреЗрдХреНрд╢рди рдХреЗ рдЕрдВрджрд░ рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рд░рд┐рдХреЙрд░реНрдбрд┐рдВрдЧ рдореЗрдВ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдбреЗрдЯрд╛ рдФрд░ рдХреЙрд▓рдмреИрдХ рдХреЛ рд╕рд╣реЗрдЬрд╛ рдЬрд╛рдПрдЧрд╛ред рдФрд░ рдЕрдЧрд▓рд╛ рдЪрдХреНрд░ рдЪрд▓рд╛рдПрдВ, рдХреЗрд╡рд▓ рдЗрд╕ рдмрд╛рд░ рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐рдпрд╛рдБ:

рд░рд┐рдХреЙрд░реНрдбрд┐рдВрдЧ рдЪрдХреНрд░
 void TryWrite() { if (m_input.empty() || m_write_in_progress) { return; } m_tcp_socket.async_wait(tcp::socket::wait_write, [this, self = shared_from_this()](auto ec) { if (WantWrite()) { WriteHandler(ec); } if (m_complete) { return; } TryWrite(); }); } void WriteHandler(const boost::system::error_code &error) { if (error != boost::system::errc::success) { return; } m_write_in_progress = true; int ec = LIBSSH2_ERROR_EAGAIN; while (!m_input.empty()) { auto ptr = m_input.c_str(); auto read_size = m_input.size(); while ((ec = libssh2_channel_write(*m_channel, ptr, read_size)) > 0) { read_size -= ec; ptr += ec; } AssertResult(ec); m_input.erase(0, m_input.size() - read_size); if (ec == LIBSSH2_ERROR_EAGAIN) { break; } } if (m_input.empty() && m_write_callback != nullptr) { m_write_callback(); } m_write_in_progress = false; } 


рдЗрд╕ рдкреНрд░рдХрд╛рд░, рд╣рдо рдЪреИрдирд▓ рдХреЛ рдбреЗрдЯрд╛ рддрдм рддрдХ рд▓рд┐рдЦреЗрдВрдЧреЗ рдЬрдм рддрдХ рдХрд┐ рд╡реЗ рд╕рднреА рд╕рдлрд▓рддрд╛рдкреВрд░реНрд╡рдХ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдирд╣реАрдВ рд╣реЛ рдЬрд╛рддреЗред рдлрд┐рд░ рд╣рдо рдХреЙрд▓рд░ рдХреЛ рдирд┐рдпрдВрддреНрд░рдг рд╡рд╛рдкрд╕ рдХрд░ рджреЗрдВрдЧреЗ рддрд╛рдХрд┐ рдбреЗрдЯрд╛ рдХрд╛ рдПрдХ рдирдпрд╛ рдЯреБрдХрдбрд╝рд╛ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХреЗред рдЗрд╕ рддрд░рд╣ рдЖрдк рди рдХреЗрд╡рд▓ рд╣реЛрд╕реНрдЯ рдкрд░ рдХреБрдЫ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рдирд┐рд░реНрджреЗрд╢ рднреЗрдЬ рд╕рдХрддреЗ рд╣реИрдВ, рдмрд▓реНрдХрд┐, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЫреЛрдЯреЗ рднрд╛рдЧреЛрдВ рдореЗрдВ рдХрд┐рд╕реА рднреА рдЖрдХрд╛рд░ рдХреА рдлрд╛рдЗрд▓реЗрдВ рдЕрдкрд▓реЛрдб рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдмрд┐рдирд╛ рдереНрд░реЗрдб рдХреЛ рдмреНрд▓реЙрдХ рдХрд┐рдП, рдЬреЛ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИред

рдЗрд╕ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ, рдореИрдВ рдПрдХ рджреВрд░рд╕реНрде рд╕рд░реНрд╡рд░ рдкрд░ рдПрдХ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЛ рд╕рдлрд▓рддрд╛рдкреВрд░реНрд╡рдХ рдЪрд▓рд╛рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рдерд╛ рдЬреЛ рдлрд╝рд╛рдЗрд▓ рд╕рд┐рд╕реНрдЯрдо рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреЛ рдЯреНрд░реИрдХ рдХрд░рддрд╛ рд╣реИ, рдЙрд╕реА рд╕рдордп рдЗрд╕рдХреЗ рдЖрдЙрдЯрдкреБрдЯ рдХреЛ рдкрдврд╝ рд░рд╣рд╛ рд╣реИ рдФрд░ рдЕрдкрдиреЗ рдХрдорд╛рдВрдб рднреЗрдЬ рд░рд╣рд╛ рд╣реИред рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░: рдмреВрд╕реНрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЖрдзреБрдирд┐рдХ C ++ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдХреЗ рд▓рд┐рдП рд╕реА-рд╕реНрдЯрд╛рдЗрд▓ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХреЛ рдЕрдкрдирд╛рдиреЗ рдореЗрдВ рдПрдХ рдмрд╣реБрдд рд╣реА рдореВрд▓реНрдпрд╡рд╛рди рдЕрдиреБрднрд╡ред

рдореБрдЭреЗ рдЕрдзрд┐рдХ рдЕрдиреБрднрд╡реА Boost.Asio рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЗ рд╕реБрдЭрд╛рд╡реЛрдВ рдХреЛ рдкрдврд╝рдиреЗ рдФрд░ рдореЗрд░реЗ рд╕рдорд╛рдзрд╛рди рдХреЛ рдмреЗрд╣рддрд░ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЦреБрд╢реА рд╣реЛрдЧреА :-)ред

Source: https://habr.com/ru/post/hi430488/


All Articles