telnet 简单客户端学习

来源:互联网 发布:icloud怎么用恢复数据 编辑:程序博客网 时间:2024/06/06 16:12
  1. #include <sys/types.h>   
  2. #include <unistd.h>   
  3. #include <sys/socket.h>   
  4. #include <string.h>   
  5. #include <netinet/in.h>   
  6. #include <stdio.h>   
  7. #include <stdlib.h>   
  8. #include <arpa/inet.h>   
  9. #include <fcntl.h>   
  10. #include <errno.h>   
  11.   
  12. #define MAX_PARAMTER 3  //参数个数   
  13. /*TELNET命令*/  
  14. #define IAC 255    //TELNET协商语句以此开头   
  15. #define WILL 251   //请求本方动作,应答同意要求本方  
  16. #define WONT 252   //请求本方不动作,应答不同意本方动作或同意本方不动作  
  17. #define DO   253   //请求对方动作,应答同意对方要求动作  
  18. #define DONT 254   //请求对方不动作,应答不同意对方要求动作或同意对方不动作  
  19. /*TELNET选项*/  
  20. #define ECHO 1      //TELNET回显选项,TELNET协商语句以此为最后一部分(子协议除外)  
  21.   
  22. #define NEGONATION_LENTH 3 //TELNET协商语句长度  
  23.   
  24. #define MAX_COMMAND 1024  //终端输入最大长度   
  25. #define MAX_RECEIVE 1024  //接收最大长度  
  26. #define MAX_SEND    1024  //发送最大长度   
  27.   
  28. /*用于区别是发来的请求还是应答(由于请求应答相同有对称性)*/  
  29. #define SERVER_ECHO_ON  1 //已成为服务器回显状态  
  30. #define SERVER_ECHO_OFF 0 //还未成服务器为回显状态  
  31.   
  32. #define STD_IN 0  //标准输入输出文件描述符   
  33.   
  34. unsigned char echo_status = 0; //回显状态  
  35. int sockfd = -1;  //SOCKET文件描述  
  36. int telnet_connect = 0; //TELNET通断控制变量  
  37.   
  38. int init_socket(char* server_ip, char * server_port)  
  39. {  
  40.     sockfd = socket(AF_INET, SOCK_STREAM, 0); //参数1为IPV4,参数2为TCP链接,参数3固定为0  
  41.       
  42.     if (sockfd < 0)  
  43.     {  
  44.         printf("Socket error\n");  
  45.         return -1;  
  46.     }  
  47.   
  48.     struct sockaddr_in server_addr;  //服务器地址信息  
  49.       
  50.     bzero(&server_addr, sizeof(server_addr));  //清空server_addr  
  51.   
  52.     server_addr.sin_family = AF_INET;            //IPV4  
  53.     server_addr.sin_addr.s_addr = inet_addr(server_ip);     //服务器IP地址  
  54.     server_addr.sin_port = htons((unsigned short)(atoi(server_port)));   //服务器端口  
  55.     /* 
  56.     if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)  //一般服务器需要绑定,客户端其实不需要绑定,绑定是绑定自己不是绑定服务器 
  57.     { 
  58.         printf("Bind error\n"); 
  59.         return -1; 
  60.     } 
  61.     */  
  62.     if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)   //与服务器取得链接  
  63.     {  
  64.         printf("Connect error\n");  
  65.         return -1;  
  66.     }  
  67.   
  68.     telnet_connect = 1;  
  69.     return 0;  
  70. }  
  71.   
  72. int deal_telnet_protocol(unsigned char* receive_server)  
  73. {  
  74.     unsigned char client_send[NEGONATION_LENTH];  
  75.     int i = 0;  
  76.   
  77.     client_send[0] = receive_server[0];   //IAC  
  78.     client_send[2] = receive_server[2];   //服务器要求的选项  
  79.   
  80.     switch (receive_server[1])  
  81.     {  
  82.         case WILL:                                //如果收到服务器要求改变状态  
  83.             {  
  84.                 if (receive_server[2] == ECHO)     //查看选项是否为回显  
  85.                 {  
  86.                     if (echo_status == SERVER_ECHO_OFF)   //查看现在的服务器ECHO状态,通过使用状态位判断服务器发来的为请求还是应当,因为telnet的请求命令和应答都相同有对称性(由于客户端没发生过请求,服务器端也就不会发应答,发来的数据都是请求,其实不用判断)  
  87.                     {                                    //如果现在是服务器回显状态,则ECHO的状态没有改变,不发送应答,如果不是服务器回显状态,则ECHO的状态改变了,发送应答  
  88.                         client_send[1] = DO;             //同意服务器端开启ECHO选项  
  89.                         echo_status = SERVER_ECHO_ON;  //修改服务器ECHO状态为ON  
  90.                     }  
  91.                     else  
  92.                     {  
  93.                         return 0;                 //否则不应答  
  94.                     }  
  95.                 }  
  96.                 else                              //其他服务器端选项都不同意,因为客户端从没有向服务器发送命令,  
  97.                 {                                 //因此服务器发来的数据不可能是应答,都是请求,因此其实不需要判断状态  
  98.                     client_send[1] = DONT;          
  99.                 }  
  100.                 break;  
  101.             }  
  102.         case WONT:  
  103.             {  
  104.                 if (receive_server[2] == ECHO)  //查看选项是否为回显  
  105.                 {  
  106.                     if (echo_status == SERVER_ECHO_ON) //现在状态是否为ON  
  107.                     {  
  108.                         client_send[1] = DONT;  
  109.                         echo_status = SERVER_ECHO_OFF;  
  110.                     }  
  111.                     else  
  112.                     {  
  113.                         return 0;               //否则不应答  
  114.                     }  
  115.   
  116.                 }  
  117.                 else                           //WONT如果要回复只能用DONT  
  118.                 {  
  119.                     client_send[1] = DONT;           
  120.                 }  
  121.                 break;  
  122.             }  
  123.         case DO:                               //其余的要求客户端做的选项都拒绝  
  124.             {  
  125.                 client_send[1] = WONT;           
  126.                 break;  
  127.             }  
  128.         case DONT:                             //DONT选项只能用WONT来应答  
  129.             {  
  130.                 client_send[1] = WONT;           
  131.                 break;  
  132.             }  
  133.         default:  
  134.             {  
  135.                 printf("Receive error telnet command\n");  
  136.                 return -1;  
  137.             }  
  138.     }  
  139.       
  140.     if (send(sockfd, client_send, NEGONATION_LENTH, 0) < 0) //发送应答数据包  
  141.     {  
  142.         printf("send ack error\n");  
  143.         return -1;  
  144.     }  
  145.   
  146.     printf("\n+++++++++++++send+++++++++++++++\n");  
  147.     for (i = 0; i < NEGONATION_LENTH; i++)  
  148.     {  
  149.         printf("%d.[%d<%c>] ", i, client_send[i], client_send[i]);  
  150.     }  
  151.     printf("\n++++++++++++++++++++++++++++++++\n");  
  152.       
  153.     return 0;  
  154. }  
  155.   
  156. int  cs_communcate(void)  
  157. {  
  158.     int re_recv = -1;  
  159.     int i = 0;  
  160.     int deal_lenth = 0;   //处理的数据长度  
  161.     unsigned char* p_server = NULL; //指向手到服务器数据的指针  
  162.   
  163.     unsigned char server_data[MAX_RECEIVE];  //接收到的服务数据  
  164.     unsigned char server_negonation[NEGONATION_LENTH];  
  165.       
  166.     re_recv = recv(sockfd, server_data, MAX_RECEIVE, 0); //接收服务器发来的数据  
  167.       
  168.     if (re_recv > 0)  
  169.     {  
  170.         printf("\n-------------receive-------------\n");  
  171.         for(i = 0; i < re_recv; i++)  
  172.         {  
  173.             printf("%d.[%d<%c>] ", i, server_data[i], server_data[i]);  
  174.             if (!((i + 1) % 4))  
  175.             {  
  176.                 printf("\n");  
  177.             }  
  178.         }  
  179.         printf("\n-------------------------------\n\n");  
  180.   
  181.         deal_lenth = 0;  
  182.         p_server = server_data;  
  183.         while (deal_lenth < re_recv)  
  184.         {  
  185.             if ((*p_server == IAC) && (*(p_server + 1) != IAC) )   //判断接收到的是否为协商语句(请求或应答,实际上因client未发送请求所以不可能为应答)  
  186.             {  
  187.                 memcpy(server_negonation, p_server, NEGONATION_LENTH); //缓存协商语句   
  188.                 deal_telnet_protocol(server_negonation);  //处理每条服务器发来的协商语句  
  189.   
  190.                 p_server += NEGONATION_LENTH;  
  191.                 deal_lenth += NEGONATION_LENTH;  
  192.             }  
  193.             else                                                 //如果是服务器发来的数据则把它显示到终端上  
  194.             {  
  195.                 write(STD_IN, p_server, strlen(p_server) + 1);  
  196.                 deal_lenth = re_recv;                            //认为收到的如果为数据则它在一包的最后,或者独立为一包数据  
  197.             }  
  198.         }     
  199.   
  200.     }  
  201.   
  202.     return 0;  
  203.       
  204. }  
  205.   
  206. int send_usrcommand()  
  207. {  
  208.     int i = 0;  
  209.     char usr_command[MAX_COMMAND];  //终端发送的用户命令(不是TELNET协议中的命令)  
  210.   
  211.     if (read(STD_IN, usr_command, MAX_COMMAND) > 0) //如果读取用户命令成功则将其发送给服务器  
  212.     {  
  213.         fflush(stdout);  //清空输出缓冲区的内容,这样用户可以一次发送带空格的命令  
  214.   
  215.         if (!strcmp(usr_command, "exit\n"))    //如果输入字符串为exit则断开TELNET控制连接  
  216.         {  
  217.                 telnet_connect = 0;  
  218.                 close(sockfd);  
  219.                 return 0;  
  220.         }  
  221.   
  222.         if (send(sockfd, usr_command, strlen(usr_command) - 1, 0) < 0) //发送命令但不发送回车符  
  223.         {  
  224.             printf("Send usr command error\n");  
  225.             return -1;  
  226.         }  
  227.   
  228.         printf("\n+++++++++++++send+++++++++++++++\n");  
  229.         for(i = 0; i < strlen(usr_command) - 1; i++)     
  230.         {  
  231.             printf("%d.[%d<%c>] ", i, usr_command[i], usr_command[i]);  
  232.             if (!((i + 1) % 4))  
  233.             {  
  234.                 printf("\n");  
  235.             }  
  236.         }  
  237.         printf("\n++++++++++++++++++++++++++++++++\n");  
  238.   
  239.         if (send(sockfd, "\r\n", 2, 0) < 0)   //NVT中以换行回车作为一个命令的结束(NVT用于在TELNET中连接不同操作系统,nvtasc码的转换由操作系统实现)  
  240.         {  
  241.             printf("Send usr command error\n");  
  242.             return -1;  
  243.         }  
  244.           
  245.         printf("\n+++++++++++++send+++++++++++++++\n");  
  246.         printf("%d.[%d<%c>]  %d.[%d<%c>]"'\n''\r');  
  247.         printf("\n++++++++++++++++++++++++++++++++\n");  
  248.     }  
  249.   
  250.     return 0;  
  251. }  
  252.   
  253. int main(int argc, char** argv)  
  254. {  
  255.     if (argc != MAX_PARAMTER)  
  256.     {  
  257.         printf("2 parameters please\n");  
  258.         return -1;  
  259.     }  
  260.   
  261.     if (init_socket(argv[1], argv[2]) < 0)  
  262.     {  
  263.         return -1;  
  264.     }  
  265.   
  266.     fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL) | O_NONBLOCK); //设置SOCKET文件为非阻塞方式  
  267.     fcntl(STD_IN, F_SETFL, fcntl(sockfd, F_GETFL) | O_NONBLOCK); //设置标准输入文件为非阻塞方式  
  268.   
  269.     while (telnet_connect)  //当将sockfd和标准输入输出STD_IN设置为非阻塞后,如果一方收到数据则继续接收,如果两方都收不到数据则效果为等待从键盘输入数据何等待接收  
  270.     {  
  271.         if(cs_communcate() < 0)  //处理服务发来的数据  
  272.         {  
  273.             close(sockfd);  
  274.             return -1;  
  275.         }  
  276.   
  277.         if (send_usrcommand() < 0) //处理终端用户发来的命令  
  278.         {  
  279.             close(sockfd);  
  280.             return -1;  
  281.         }  
  282.     }  
  283.   
  284.     return 0;  
  285. }  
0 0
原创粉丝点击