libssh2的简单应用

来源:互联网 发布:网络禁书40本 编辑:程序博客网 时间:2024/05/29 03:15

libssh2的官网:www.libssh2.org; 这里面提供了很多例子,比如FTP的,shell命令的等等,我在这里介绍一下shell命令的发送和接收返回数据。

example里有个文件名叫exec.c 这个文件是实现shell命令的一个例子

[cpp] view plaincopy
  1. <span style="font-size:12px;">/* 
  2.  * Sample showing how to use libssh2 to execute a command remotely. 
  3.  * 
  4.  * The sample code has fixed values for host name, user name, password 
  5.  * and command to run. 
  6.  * 
  7.  * Run it like this: 
  8.  * 
  9.  * $ ./ssh2_exec 127.0.0.1 user password "uptime" 
  10.  * 
  11.  */   
  12.    
  13. #include "libssh2_config.h"  
  14. #include <libssh2.h>  
  15.    
  16. #ifdef HAVE_WINSOCK2_H  
  17. #include <winsock2.h>  
  18. #endif  
  19. #ifdef HAVE_SYS_SOCKET_H  
  20. #include <sys/socket.h>  
  21. #endif  
  22. #ifdef HAVE_NETINET_IN_H  
  23. #include <netinet/in.h>  
  24. #endif  
  25. #ifdef HAVE_SYS_SELECT_H  
  26. #include <sys/select.h>  
  27. #endif  
  28. #ifdef HAVE_UNISTD_H  
  29. #include <unistd.h>  
  30. #endif  
  31. #ifdef HAVE_ARPA_INET_H  
  32. #include <arpa/inet.h>  
  33. #endif  
  34.    
  35. #include <sys/time.h>  
  36. #include <sys/types.h>  
  37. #include <stdlib.h>  
  38. #include <fcntl.h>  
  39. #include <errno.h>  
  40. #include <stdio.h>  
  41. #include <ctype.h>  
  42.    
  43. static int waitsocket(int socket_fd, LIBSSH2_SESSION *session)  
  44. {  
  45.     struct timeval timeout;  
  46.     int rc;  
  47.     fd_set fd;  
  48.     fd_set *writefd = NULL;  
  49.     fd_set *readfd = NULL;  
  50.     int dir;  
  51.    
  52.     timeout.tv_sec = 10;  
  53.     timeout.tv_usec = 0;  
  54.    
  55.     FD_ZERO(&fd);  
  56.    
  57.     FD_SET(socket_fd, &fd);  
  58.    
  59.     /* now make sure we wait in the correct direction */   
  60.     dir = libssh2_session_block_directions(session);  
  61.   
  62.    
  63.     if(dir & LIBSSH2_SESSION_BLOCK_INBOUND)  
  64.         readfd = &fd;  
  65.    
  66.     if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND)  
  67.         writefd = &fd;  
  68.    
  69.     rc = select(socket_fd + 1, readfd, writefd, NULL, &timeout);  
  70.    
  71.     return rc;  
  72. }  
  73.    
  74. int main(int argc, char *argv[])  
  75. {  
  76.     const char *hostname = "127.0.0.1";  
  77.     const char *commandline = "uptime";  
  78.     const char *username    = "user";  
  79.     const char *password    = "password";  
  80.     unsigned long hostaddr;  
  81.     int sock;  
  82.     struct sockaddr_in sin;  
  83.     const char *fingerprint;  
  84.     LIBSSH2_SESSION *session;  
  85.     LIBSSH2_CHANNEL *channel;  
  86.     int rc;  
  87.     int exitcode;  
  88.     char *exitsignal=(char *)"none";  
  89.     int bytecount = 0;  
  90.     size_t len;  
  91.     LIBSSH2_KNOWNHOSTS *nh;  
  92.     int type;  
  93.    
  94. #ifdef WIN32  
  95.     WSADATA wsadata;  
  96.     WSAStartup(MAKEWORD(2,0), &wsadata);  
  97. #endif  
  98.     if (argc > 1)  
  99.         /* must be ip address only */   
  100.         hostname = argv[1];  
  101.    
  102.     if (argc > 2) {  
  103.         username = argv[2];  
  104.     }  
  105.     if (argc > 3) {  
  106.         password = argv[3];  
  107.     }  
  108.     if (argc > 4) {  
  109.         commandline = argv[4];  
  110.     }  
  111.    
  112.     rc = libssh2_init (0);  
  113.   
  114.     if (rc != 0) {  
  115.         fprintf (stderr, "libssh2 initialization failed (%d)\n", rc);  
  116.         return 1;  
  117.     }  
  118.    
  119.     hostaddr = inet_addr(hostname);  
  120.    
  121.     /* Ultra basic "connect to port 22 on localhost" 
  122.      * Your code is responsible for creating the socket establishing the 
  123.      * connection 
  124.      */   
  125.     sock = socket(AF_INET, SOCK_STREAM, 0);  
  126.    
  127.     sin.sin_family = AF_INET;  
  128.     sin.sin_port = htons(22);  
  129.     sin.sin_addr.s_addr = hostaddr;  
  130.     if (connect(sock, (struct sockaddr*)(&sin),  
  131.                 sizeof(struct sockaddr_in)) != 0) {  
  132.         fprintf(stderr, "failed to connect!\n");  
  133.         return -1;  
  134.     }  
  135.    
  136.     /* Create a session instance */   
  137.     session = libssh2_session_init();  
  138.   
  139.     if (!session)  
  140.         return -1;  
  141.    
  142.     /* tell libssh2 we want it all done non-blocking */   
  143.     libssh2_session_set_blocking(session, 0);  
  144.   
  145.    
  146.     /* ... start it up. This will trade welcome banners, exchange keys, 
  147.      * and setup crypto, compression, and MAC layers 
  148.      */   
  149.     while ((rc = libssh2_session_handshake(session, sock)) ==  
  150.   
  151.            LIBSSH2_ERROR_EAGAIN);  
  152.     if (rc) {  
  153.         fprintf(stderr, "Failure establishing SSH session: %d\n", rc);  
  154.         return -1;  
  155.     }  
  156.    
  157.     nh = libssh2_knownhost_init(session);  
  158.   
  159.     if(!nh) {  
  160.         /* eeek, do cleanup here */   
  161.         return 2;  
  162.     }  
  163.    
  164.     /* read all hosts from here */   
  165.     libssh2_knownhost_readfile(nh, "known_hosts",  
  166.   
  167.                                LIBSSH2_KNOWNHOST_FILE_OPENSSH);  
  168.    
  169.     /* store all known hosts to here */   
  170.     libssh2_knownhost_writefile(nh, "dumpfile",  
  171.   
  172.                                 LIBSSH2_KNOWNHOST_FILE_OPENSSH);  
  173.    
  174.     fingerprint = libssh2_session_hostkey(session, &len, &type);  
  175.   
  176.     if(fingerprint) {  
  177.         struct libssh2_knownhost *host;  
  178. #if LIBSSH2_VERSION_NUM >= 0x010206  
  179.         /* introduced in 1.2.6 */   
  180.         int check = libssh2_knownhost_checkp(nh, hostname, 22,  
  181.   
  182.                                              fingerprint, len,  
  183.                                              LIBSSH2_KNOWNHOST_TYPE_PLAIN|  
  184.                                              LIBSSH2_KNOWNHOST_KEYENC_RAW,  
  185.                                              &host);  
  186. #else  
  187.         /* 1.2.5 or older */   
  188.         int check = libssh2_knownhost_check(nh, hostname,  
  189.   
  190.                                             fingerprint, len,  
  191.                                             LIBSSH2_KNOWNHOST_TYPE_PLAIN|  
  192.                                             LIBSSH2_KNOWNHOST_KEYENC_RAW,  
  193.                                             &host);  
  194. #endif  
  195.         fprintf(stderr, "Host check: %d, key: %s\n", check,  
  196.                 (check <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH)?  
  197.                 host->key:"<none>");  
  198.    
  199.         /***** 
  200.          * At this point, we could verify that 'check' tells us the key is 
  201.          * fine or bail out. 
  202.          *****/   
  203.     }  
  204.     else {  
  205.         /* eeek, do cleanup here */   
  206.         return 3;  
  207.     }  
  208.     libssh2_knownhost_free(nh);  
  209.   
  210.    
  211.     if ( strlen(password) != 0 ) {  
  212.         /* We could authenticate via password */   
  213.         while ((rc = libssh2_userauth_password(session, username, password)) ==  
  214.   
  215.                LIBSSH2_ERROR_EAGAIN);  
  216.         if (rc) {  
  217.             fprintf(stderr, "Authentication by password failed.\n");  
  218.             goto shutdown;  
  219.         }  
  220.     }  
  221.     else {  
  222.         /* Or by public key */   
  223.         while ((rc = libssh2_userauth_publickey_fromfile(session, username,  
  224.   
  225.                                                          "/home/user/"  
  226.                                                          ".ssh/id_rsa.pub",  
  227.                                                          "/home/user/"  
  228.                                                          ".ssh/id_rsa",  
  229.                                                          password)) ==  
  230.                LIBSSH2_ERROR_EAGAIN);  
  231.         if (rc) {  
  232.             fprintf(stderr, "\tAuthentication by public key failed\n");  
  233.             goto shutdown;  
  234.         }  
  235.     }  
  236.    
  237. #if 0  
  238.     libssh2_trace(session, ~0 );  
  239.   
  240. #endif  
  241.    
  242.     /* Exec non-blocking on the remove host */   
  243.     while( (channel = libssh2_channel_open_session(session)) == NULL &&  
  244.   
  245.            libssh2_session_last_error(session,NULL,NULL,0) ==  
  246.   
  247.            LIBSSH2_ERROR_EAGAIN )  
  248.     {  
  249.         waitsocket(sock, session);  
  250.     }  
  251.     if( channel == NULL )  
  252.     {  
  253.         fprintf(stderr,"Error\n");  
  254.         exit( 1 );  
  255.     }  
  256.     while( (rc = libssh2_channel_exec(channel, commandline)) ==  
  257.   
  258.            LIBSSH2_ERROR_EAGAIN )  
  259.     {  
  260.         waitsocket(sock, session);  
  261.     }  
  262.     if( rc != 0 )  
  263.     {  
  264.         fprintf(stderr,"Error\n");  
  265.         exit( 1 );  
  266.     }  
  267.     for( ;; )  
  268.     {  
  269.         /* loop until we block */   
  270.         int rc;  
  271.         do  
  272.         {  
  273.             char buffer[0x4000];  
  274.             rc = libssh2_channel_read( channel, buffer, sizeof(buffer) );  
  275.   
  276.             if( rc > 0 )  
  277.             {  
  278.                 int i;  
  279.                 bytecount += rc;  
  280.                 fprintf(stderr, "We read:\n");  
  281.                 for( i=0; i < rc; ++i )  
  282.                     fputc( buffer[i], stderr);  
  283.                 fprintf(stderr, "\n");  
  284.             }  
  285.             else {  
  286.                 if( rc != LIBSSH2_ERROR_EAGAIN )  
  287.                     /* no need to output this for the EAGAIN case */   
  288.                     fprintf(stderr, "libssh2_channel_read returned %d\n", rc);  
  289.             }  
  290.         }  
  291.         while( rc > 0 );  
  292.    
  293.         /* this is due to blocking that would occur otherwise so we loop on 
  294.            this condition */   
  295.         if( rc == LIBSSH2_ERROR_EAGAIN )  
  296.         {  
  297.             waitsocket(sock, session);  
  298.         }  
  299.         else  
  300.             break;  
  301.     }  
  302.     exitcode = 127;  
  303.     while( (rc = libssh2_channel_close(channel)) == LIBSSH2_ERROR_EAGAIN )  
  304.   
  305.         waitsocket(sock, session);  
  306.    
  307.     if( rc == 0 )  
  308.     {  
  309.         exitcode = libssh2_channel_get_exit_status( channel );  
  310.   
  311.         libssh2_channel_get_exit_signal(channel, &exitsignal,  
  312.   
  313.                                         NULL, NULL, NULL, NULL, NULL);  
  314.     }  
  315.    
  316.     if (exitsignal)  
  317.         fprintf(stderr, "\nGot signal: %s\n", exitsignal);  
  318.     else  
  319.         fprintf(stderr, "\nEXIT: %d bytecount: %d\n", exitcode, bytecount);  
  320.    
  321.     libssh2_channel_free(channel);  
  322.   
  323.     channel = NULL;  
  324.    
  325. shutdown:  
  326.    
  327.     libssh2_session_disconnect(session,  
  328.   
  329.                                "Normal Shutdown, Thank you for playing");  
  330.     libssh2_session_free(session);  
  331.   
  332.    
  333. #ifdef WIN32  
  334.     closesocket(sock);  
  335. #else  
  336.     close(sock);  
  337. #endif  
  338.     fprintf(stderr, "all done\n");  
  339.    
  340.     libssh2_exit();  
  341.   
  342.    
  343.     return 0;  
  344. }</span>  
做windows连接linux服务器发送shell命令的主要方法有几个简单介绍下:

1.WSAStartup(),打开socket链接库

2.socket(),初始化一个socket套接字

3.connect(),连接到ssh服务器

4.libssh2_session_init(),初始化一个ssh连接

5.libssh2_session_handshake(),将socket和session握手通信

6.libssh2_userauth_password(),验证登陆

7.libssh2_channel_open_session(),打开通道

8.libssh2_channel_exec(),发送shell命令

9.libssh2_channel_read(),读取命令处理结果


这里的8.libssh2_channel_exec(),发送shell命令和心目中想象的不太一样,不能循环发送命令,发送第一次命令时,该命令执行,但是第二次再发送时会返回一个

名字叫LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED的ERROR,也就是说这个函数只能发送一次shell命令就不能再用了,太麻烦了。


在这里这种需求怎么解决:

当调用完libssh2_channel_exec()时,将通道释放掉libssh2_channel_close(),然后再重新打开libssh2_channel_open(),再使用这个libssh2_channel_exec()发送shell命令。

但是在这里可能会出现一个问题,在libssh2_channel_open()的时候并没有把通道打开,调用libssh2_session_last_error()发现这个错误代码是LIBSSH2_ERROR_EAGAIN,在官方网站的解释是这不是一个错误,是一个阻塞的过程,也就是现在这个链接已经阻塞了,需要等等再打开。这也就是最上面那个waitsocket()的作用了。


总结:如果不能理解,简洁直白的方式就是类似于在SSH终端敲打命令的方式


0 0
原创粉丝点击