QT - 使用libssh2连接远程服务器,进行读写操作

主要有两个类,代码如下:

Ssh2头文件

#ifndef SSH2_H
#define SSH2_H

#include "Channel.h"
#include <libssh2.h>

#ifdef WIN32  
#pragma comment(lib,"Ws2_32.lib")
#endif

class Ssh2
{
public:
	Ssh2(const string &srvIp, int srvPort = 22);
	~Ssh2(void);

	bool Connect(const string &userName, const string &userPwd);
	bool Disconnect(void);

	Channel* CreateChannel(const string &ptyType = "vanilla");

public:
	static void S_KbdCallback(const char*, int, const char*, int, int, const LIBSSH2_USERAUTH_KBDINT_PROMPT*, LIBSSH2_USERAUTH_KBDINT_RESPONSE*, void **a);
	static string s_password;

private:
	string m_srvIp;
	int    m_srvPort;
	string m_userName;
	string m_password;
	int    m_sock;
	LIBSSH2_SESSION *m_session;
};

#endif // SSH2_H

Ssh2 源文件

#include "Ssh2.h"

string Ssh2::s_password;

void Ssh2::S_KbdCallback(const char *name, int name_len,
	const char *instruction, int instruction_len,
	int num_prompts,
	const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts,
	LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses,
	void **abstract)
{
	(void)name;
	(void)name_len;
	(void)instruction;
	(void)instruction_len;
	if (num_prompts == 1)
	{
		responses[0].text = strdup(s_password.c_str());
		responses[0].length = (int)s_password.size();
	}
	(void)prompts;
	(void)abstract;
}

Ssh2::Ssh2(const string &srvIp, int srvPort)
:m_srvIp(srvIp), m_srvPort(srvPort)
{
	m_sock = -1;
	m_session = NULL;
	libssh2_init(0);
}

Ssh2::~Ssh2(void)
{
	Disconnect();
	libssh2_exit();
}

bool Ssh2::Connect(const string &userName, const string &userPwd)
{

#ifdef WIN32  
	WSADATA wsa;
	if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) return false;
#endif

	m_sock = socket(AF_INET, SOCK_STREAM, 0);

	sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(22);
	sin.sin_addr.s_addr = inet_addr(m_srvIp.c_str());
	if (connect(m_sock, (sockaddr*)(&sin), sizeof(sockaddr_in)) != 0)
	{
		Disconnect();
		return false;
	}

	m_session = libssh2_session_init();
	if (libssh2_session_handshake(m_session, m_sock))
	{
		Disconnect();
		return false;
	}

	int auth_pw = 0;
	string fingerprint = libssh2_hostkey_hash(m_session, LIBSSH2_HOSTKEY_HASH_SHA1);
	string userauthlist = libssh2_userauth_list(m_session, userName.c_str(), (int)userName.size());
	if (strstr(userauthlist.c_str(), "password") != NULL)
	{
		auth_pw |= 1;
	}
	if (strstr(userauthlist.c_str(), "keyboard-interactive") != NULL)
	{
		auth_pw |= 2;
	}
	if (strstr(userauthlist.c_str(), "publickey") != NULL)
	{
		auth_pw |= 4;
	}

	if (auth_pw & 1)
	{
		/* We could authenticate via password */
		if (libssh2_userauth_password(m_session, userName.c_str(), userPwd.c_str()))
		{
			Disconnect();
			return false;
		}
	}
	else if (auth_pw & 2)
	{
		/* Or via keyboard-interactive */
		s_password = userPwd;
		if (libssh2_userauth_keyboard_interactive(m_session, userName.c_str(), &S_KbdCallback))
		{
			Disconnect();
			return false;
		}
	}
	else
	{
		Disconnect();
		return false;
	}


	return true;
}

bool Ssh2::Disconnect(void)
{
	if (m_session)
	{
		libssh2_session_disconnect(m_session, "Bye bye, Thank you");
		libssh2_session_free(m_session);
		m_session = NULL;
	}
	if (m_sock != -1)
	{
#ifdef WIN32  
		WSACleanup();
		closesocket(m_sock);
#else  
		close(m_sock);
#endif  
		m_sock = -1;
	}
	return true;
}

Channel* Ssh2::CreateChannel(const string &ptyType)
{
	if (NULL == m_session)
	{
		return NULL;
	}

	LIBSSH2_CHANNEL *channel = NULL;
	/* Request a shell */
	if (!(channel = libssh2_channel_open_session(m_session)))
	{
		return NULL;
	}

	/* Request a terminal with 'vanilla' terminal emulation
	* See /etc/termcap for more options
	*/
	if (libssh2_channel_request_pty(channel, ptyType.c_str()))
	{
		libssh2_channel_free(channel);
		return NULL;
	}

	/* Open a SHELL on that pty */
	if (libssh2_channel_shell(channel))
	{

		libssh2_channel_free(channel);
		return NULL;
	}

	Channel *ret = new Channel(channel);
	return ret;
}

Channel 头文件

#ifndef CHANNEL_H
#define CHANNEL_H

#include <string>
#include <libssh2.h>
#include <libssh2_sftp.h>
#include "windows.h"
#include <winsock2.h>
#include <mutex>

using namespace std;

const int CHANNEL_READ_TIMEOUT = 3000;

class Channel
{
public:
	Channel(LIBSSH2_CHANNEL *channel);
	~Channel(void);

	string Read(const string &strend = "$", int timeout = CHANNEL_READ_TIMEOUT);
	bool   Write(const string &data);
private:
	Channel(const Channel&);
	Channel operator=(const Channel&);
private:
	LIBSSH2_CHANNEL *m_channel;
	std::mutex mt_rw;
};

#endif // CHANNEL_H

Channel 源文件

#include "Channel.h"

Channel::Channel(LIBSSH2_CHANNEL*channel)
:m_channel(channel)
{

}

Channel::~Channel(void)
{
	if (m_channel)
	{
		libssh2_channel_free(m_channel);
		m_channel = NULL;
	}
}

string Channel::Read(const string &strend, int timeout)
{
	std::lock_guard<std::mutex> locker(mt_rw);
	string data;
	if (NULL == m_channel)
	{
		return data;
	}

	LIBSSH2_POLLFD *fds = new LIBSSH2_POLLFD;
	fds->type = LIBSSH2_POLLFD_CHANNEL;
	fds->fd.channel = m_channel;
	fds->events = LIBSSH2_POLLFD_POLLIN | LIBSSH2_POLLFD_POLLOUT;

	if (timeout % 50)
	{
		timeout += timeout % 50;
	}
	while (timeout > 0)
	{
		int rc = (libssh2_poll(fds, 1, 10));
		if (rc < 1)
		{
			timeout -= 50;
			Sleep(50);
			continue;
		}

		if (fds->revents & LIBSSH2_POLLFD_POLLIN)
		{
			char buffer[64 * 1024] = "";
			size_t n = libssh2_channel_read(m_channel, buffer, sizeof(buffer));
			if (n == LIBSSH2_ERROR_EAGAIN)
			{
				 
			}
			else if (n <= 0)
			{
				return data;
			}
			else
			{
				data += string(buffer);
				if ("" == strend)
				{
					return data;
				}
				size_t pos = data.rfind(strend);
				if (pos != string::npos && data.substr(pos, strend.size()) == strend)
				{
					return data;
				}
			}
		}
		timeout -= 50;
		Sleep(50);
	}
	return data;
}

bool Channel::Write(const string &data)
{
	std::lock_guard<std::mutex> locker(mt_rw);
	if (NULL == m_channel)
	{
		return false;
	}

	string send_data = data + "\n";
	return libssh2_channel_write_ex(m_channel, 0, send_data.c_str(), send_data.size()) == data.size();
}

使用方法如下:

	Ssh2 ssh("xxx.xxx.xxx.xxx");
	if (!ssh.Connect("username", "password")){
		emit logSender(QString("链接服务器失败")); return;
	}
	Channel* channel = ssh.CreateChannel();
	QString readContent;

	readContent = channel->Read("$",60000).c_str();
	emit logSender(readContent);

	channel->Write("ssh [email protected]");
	emit logSender(channel->Read(":", 60000).c_str());

	delete channel;







猜你喜欢

转载自blog.csdn.net/wyansai/article/details/80762443