這篇文件是創建在一下兩篇文章基礎上完成的 不少重複的內容不會在這章提到
https://www.cnblogs.com/y-c-y/p/11685405.html telnet協議相關
https://www.cnblogs.com/y-c-y/p/11686916.html MQTT協議相關html
從這裏開始就假設對MQTT和telnet協議的實現已經有必定的基礎了python
這張時序圖是整個程序的時序 數據流向也是按章箭頭的流向來的
正則表達式
一下爲實現代碼 部分的if 0是關掉了調試用信息服務器
其中的 telnet.c telnet.h utils.c utils.h都已經在以前的文章中貼出來了 此次主要是控制部分網絡
cloud_terninal.csession
#include <stdio.h> #include <stdlib.h> #include <mosquitto.h> #include <string.h> #define HOST "localhost" #define PORT 1883 #define KEEP_ALIVE 60 #define MSG_MAX_SIZE 512 #define TOPIC_NUM 3 bool session = true; const static char* topic[TOPIC_NUM] = { "Gai爺:", "ycy ", "CCYY " }; void my_message_callback(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *message) { if(message->payloadlen){ printf(">%s %s", message->topic, (char *)message->payload); //printf("--sdfs----%ld-----------------\n",strlen((char *)message->payload)); }else{ printf("%s (null)\n", message->topic); } fflush(stdout); } void my_connect_callback(struct mosquitto *mosq, void *userdata, int result) { int i; if(!result){ /* Subscribe to broker information topics on successful connect. */ mosquitto_subscribe(mosq, NULL, "CCYY ", 2); }else{ fprintf(stderr, "Connect failed\n"); } } void my_subscribe_callback(struct mosquitto *mosq, void *userdata, int mid, int qos_count, const int *granted_qos) { int i; printf("Subscribed (mid: %d): %d", mid, granted_qos[0]); for(i=1; i<qos_count; i++){ printf(", %d", granted_qos[i]); } printf("\n"); } void my_log_callback(struct mosquitto *mosq, void *userdata, int level, const char *str) { /* Pring all log messages regardless of level. */ printf("%s\n", str); } int main() { struct mosquitto *mosq = NULL; char buff[MSG_MAX_SIZE]; //libmosquitto 庫初始化 mosquitto_lib_init(); //建立mosquitto客戶端 mosq = mosquitto_new(NULL,session,NULL); if(!mosq){ printf("create client failed..\n"); mosquitto_lib_cleanup(); return 1; } //設置回調函數,須要時可以使用 //mosquitto_log_callback_set(mosq, my_log_callback); mosquitto_connect_callback_set(mosq, my_connect_callback); mosquitto_message_callback_set(mosq, my_message_callback); mosquitto_subscribe_callback_set(mosq, my_subscribe_callback); //鏈接服務器 if(mosquitto_connect(mosq, HOST, PORT, KEEP_ALIVE)){ fprintf(stderr, "Unable to connect.\n"); return 1; } //開啓一個線程,在線程裏不停的調用 mosquitto_loop() 來處理網絡信息 int loop = mosquitto_loop_start(mosq); if(loop != MOSQ_ERR_SUCCESS) { printf("mosquitto loop error\n"); return 1; } while(fgets(buff, MSG_MAX_SIZE, stdin) != NULL) { /*發佈消息*/ mosquitto_publish(mosq,NULL,"ycy ",strlen(buff)+1,buff,0,0); memset(buff,0,sizeof(buff)); } mosquitto_destroy(mosq); mosquitto_lib_cleanup(); return 0; }
my_task.cless
#include <stdio.h> #include <stdlib.h> #include <string.h> #include"mosquitto.h" #include"utils.h" #include"telnet.h" #define IP_ADDRESS "127.0.0.1" #define IP_PORT 23 #define SERV_PORT 3333 #define MAXLINE 1024 #define HOST "localhost" #define PORT 1883 #define KEEP_ALIVE 60 #define MSG_MAX_SIZE 512 #define TOPIC_NUM 3 #define Key_to_Fun_Size 3 typedef struct sockaddr SA; typedef void (*Fun)() ; typedef struct key_word_to_fun { char key_word[MSG_MAX_SIZE]; Fun fun; void* arg1; }Key_to_Fun; static void log_in_telnet(); bool session = true; uint32 SOCKFD = 0; const static char* topic[TOPIC_NUM] = { "Gai爺:", "ycy ", "CCYY " }; static Key_to_Fun tab_Key_to_Fun[Key_to_Fun_Size] = { {"telnet",log_in_telnet,0}, {"login",log_in_telnet,0}, {"password",log_in_telnet,0}, //{NULL,NULL} }; uint32 max(uint32 a, uint32 b) { return (a>b?a:b); } void ERR_EXIT(char* s) { perror(s); exit(EXIT_FAILURE); } void INFO_PRINT(char* s) { printf("%s",s); } static void log_in_telnet() { uint32 sockfd,isReady=0; struct sockaddr_in servaddr; uint32 hname[128]; sockfd = socket(AF_INET,SOCK_STREAM,0); bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(IP_PORT); servaddr.sin_addr.s_addr = inet_addr(IP_ADDRESS); printf("servaddr: IP is %s, Port is %d\n",inet_ntoa(servaddr.sin_addr), ntohs(servaddr.sin_port)); while(connect(sockfd,(SA*)&servaddr,sizeof(servaddr))){}; SOCKFD = sockfd; printf("connect has been ready\n"); } static void search_key_word_to_fun(char *s) { int i = 0; char temp[MSG_MAX_SIZE] = {}; for(i =0 ;i< Key_to_Fun_Size;i++) { memset(temp,0,MSG_MAX_SIZE); strcpy(temp,tab_Key_to_Fun[i].key_word); strcat(temp,"\n"); if(strstr(s,temp) != NULL) { if((i==0)&& (SOCKFD != 0)) { printf("telnet has connect!! error command !!\n"); return ; } tab_Key_to_Fun[i].fun(); return ; } } if((SOCKFD)&&(i != 0)) { writen(SOCKFD,s,strlen(s)); } } static void my_message_callback(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *message) { if(message->payloadlen){ printf(">%s %s", message->topic, (char *)message->payload); search_key_word_to_fun((char *)message->payload); //MQTT發啥 就往telnet發啥 }else{ printf("%s (null)\n", message->topic); } //fflush(stdout); } static void my_connect_callback(struct mosquitto *mosq, void *userdata, int result) { int i; if(!result){ /* Subscribe to broker information topics on successful connect. */ mosquitto_subscribe(mosq, NULL, "ycy ", 2); }else{ fprintf(stderr, "Connect failed\n"); } } static void my_subscribe_callback(struct mosquitto *mosq, void *userdata, int mid, int qos_count, const int *granted_qos) { int i; printf("Subscribed (mid: %d): %d", mid, granted_qos[0]); for(i=1; i<qos_count; i++){ printf(", %d", granted_qos[i]); } printf("\n"); } static void my_log_callback(struct mosquitto *mosq, void *userdata, int level, const char *str) { /* Pring all log messages regardless of level. */ printf("%s\n", str); } void wait_message_from_telnet(struct mosquitto *mosq,FILE *fp,uint32 sockfd) { uint32 maxfdp1,nready;//stdineof; fd_set rset; uint8 buf[MAXLINE]; uint8 respbuff[MAXLINE] = {0};; uint32 resplen; uint32 n; uint8 echo_cmd[] = {0xff,0xfb,0x01}; //stdineof = 0; FD_ZERO(&rset); writen(sockfd,echo_cmd,3); for(;;) { //if(stdineof == 0) FD_SET(fileno(fp),&rset); FD_SET(sockfd,&rset); maxfdp1 = max(fileno(fp),sockfd)+1; nready = select(maxfdp1,&rset,NULL,NULL,NULL); if(nready < 0) { ERR_EXIT("ERROR!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); } if(FD_ISSET(sockfd,&rset)) { memset(buf,0,MAXLINE); if((n = read(sockfd,buf,MAXLINE))==0) { ERR_EXIT("str_cli:server termination prematurely"); } buf[n] = '\0'; //printf("FD_ISSET(sockfd,&rset)------11------%s----22----------------\n",buf); if(buf[0] == IAC) { memset(respbuff,0,MAXLINE); resplen = get_every_frame(buf,n,respbuff,MAXLINE); writen(sockfd,respbuff,resplen); } else { writen(fileno(stdout),(char *)buf,n);//當數據比較大的時候 會形成發給cloud數據錯位 //printf("------------2------------\n"); mosquitto_publish(mosq,NULL,"CCYY ",strlen(buf)+1,buf,0,0); //printf("------------3------------\n"); memset(buf,0,MAXLINE); } //writen(fileno(stdout),buf,n); } if(FD_ISSET(fileno(fp),&rset)) { memset(buf,0,MAXLINE); if((n = readline(fileno(fp),(char *)buf,MAXLINE)) == 0) { //stdineof = 1;//此時碰到EOF 而且立刻要發生FIN序列 因此標準輸入不可讀了 shutdown(sockfd,SHUT_WR); FD_CLR(fileno(fp),&rset); INFO_PRINT("nothing input!"); continue; } else if(n >0) { /* do nothing */ } else { ERR_EXIT("some error occurred "); } //printf("FD_ISSET(fileno(fp),&rset)----%d--\n",n); //memset(buf,0,MAXLINE); writen(sockfd,(char *)buf,n); //send_message_to_cloud(sockfd,(char *)buf,n); } } } int main() { struct mosquitto *mosq = NULL; char buff[MSG_MAX_SIZE]; //libmosquitto 庫初始化 mosquitto_lib_init(); //建立mosquitto客戶端 mosq = mosquitto_new(NULL,session,NULL); if(!mosq){ printf("create client failed..\n"); mosquitto_lib_cleanup(); return 1; } //設置回調函數,須要時可以使用 //mosquitto_log_callback_set(mosq, my_log_callback); mosquitto_connect_callback_set(mosq, my_connect_callback); mosquitto_message_callback_set(mosq, my_message_callback); mosquitto_subscribe_callback_set(mosq, my_subscribe_callback); //鏈接服務器 if(mosquitto_connect(mosq, HOST, PORT, KEEP_ALIVE)){ fprintf(stderr, "Unable to connect.\n"); return 1; } //開啓一個線程,在線程裏不停的調用 mosquitto_loop() 來處理網絡信息 int loop = mosquitto_loop_start(mosq); if(loop != MOSQ_ERR_SUCCESS) { printf("mosquitto loop error\n"); return 1; } while(!SOCKFD){}; wait_message_from_telnet(mosq,stdin,SOCKFD); mosquitto_destroy(mosq); mosquitto_lib_cleanup(); return 0; }
makefilesocket
#不是系統默認庫 要記得添加鏈接選項 all:My_task @echo "" @echo "This is My_task compile......." @echo "" My_task: utils.o telnet.o my_task.o Cloud gcc -g -o My_task my_task.o utils.o telnet.o -lmosquitto -lpthread Cloud: utils.o telnet.o cloud_terminal.o gcc -g -o Cloud cloud_terminal.c -lmosquitto -lpthread my_task.o:my_task.c utils.h telnet.h gcc -g -c my_task.c cloud_terminal.o:cloud_terminal.c utils.h telnet.h gcc -g -c cloud_terminal.c utils.o:utils.c utils.h gcc -g -c utils.c telnet.o:telnet.c telnet.h gcc -g -c telnet.c clean : -rm my_task.o cloud_terminal.o utils.o telnet.o Cloud My_task
運行狀況:函數
爲了方便調試 在mytask的程序中我也打印出來登陸信息oop
=====================================================================================================
以上的程序有一點不足之處是默認登陸我本身的IP 不能從外界獲取IP 一下的程序再這個基礎上有所改動 可使用「telnet 127.0.0.1」這種命令登陸進去。
添加的部分是使用了正則表達式,包含頭文件#include <regex.h> 關於這個C語言的正則表達式的用法在此不詳說 若是要匹配中文請慎重使用 聽說對中文支持的不是很好
我在這裏碰見的問題是
我想匹配「xxx.xxx.xxx.xxx」使用的能夠識別模式串是char pattern[] = "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}";這個是沒有問題的
可是最開始我使用的是char pattern[] = "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"; 以上這兩種用法在python中是相同的結果 可是第二種狀況在C語言中不適用
my_task.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <regex.h> #include"mosquitto.h" #include"utils.h" #include"telnet.h" //#define IP_ADDRESS "127.0.0.1" #define IP_PORT 23 #define SERV_PORT 3333 #define MAXLINE 1024 #define HOST "localhost" #define PORT 1883 #define KEEP_ALIVE 60 #define MSG_MAX_SIZE 512 #define TOPIC_NUM 3 #define Key_to_Fun_Size 3 typedef struct sockaddr SA; typedef void (*Fun)() ; typedef struct key_word_to_fun { char key_word[MSG_MAX_SIZE]; Fun fun; void* arg1; }Key_to_Fun; static void log_in_telnet(); bool session = true; uint32 SOCKFD = 0; char IP_ADDRESS[] = "xxx.xxx.xxx.xxx"; const static char* topic[TOPIC_NUM] = { "Gai爺:", "ycy ", "CCYY " }; static Key_to_Fun tab_Key_to_Fun[Key_to_Fun_Size] = { {"telnet",log_in_telnet,0}, {"login",log_in_telnet,0}, {"password",log_in_telnet,0}, //{NULL,NULL} }; uint32 max(uint32 a, uint32 b) { return (a>b?a:b); } void ERR_EXIT(char* s) { perror(s); exit(EXIT_FAILURE); } void INFO_PRINT(char* s) { printf("%s",s); } uint32 match_string(char *src,char* dst,char *pattern) { //char *pattern1 = "^telnet"; char errbuf[MAXLINE]; //char match[MAXLINE]; regex_t reg; int err,nm = 10; regmatch_t pmatch[nm]; if(regcomp(®,pattern,REG_EXTENDED) < 0) { regerror(err,®,errbuf,sizeof(errbuf)); printf("err:%s\n",errbuf); return 0; } err = regexec(®,src,nm,pmatch,0); if(err == REG_NOMATCH) { printf("no match\n"); return 0; } else if(err) { regerror(err,®,errbuf,sizeof(errbuf)); printf("err:%s\n",errbuf); return 0; } for(int i=0;i<10 && pmatch[i].rm_so!=-1;i++) { int len = pmatch[i].rm_eo - pmatch[i].rm_so; if(len) { memset(dst,'\0',MAXLINE); memcpy(dst,src + pmatch[i].rm_so,len); printf("%s\n",dst); } } return 1; } static void log_in_telnet() { uint32 sockfd,isReady=0; struct sockaddr_in servaddr; uint32 hname[128]; sockfd = socket(AF_INET,SOCK_STREAM,0); bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(IP_PORT); servaddr.sin_addr.s_addr = inet_addr(IP_ADDRESS); printf("servaddr: IP is %s, Port is %d\n",inet_ntoa(servaddr.sin_addr), ntohs(servaddr.sin_port)); while(connect(sockfd,(SA*)&servaddr,sizeof(servaddr))){}; SOCKFD = sockfd; printf("connect has been ready\n"); } static void search_key_word_to_fun(struct mosquitto *mosq,char *s) { int i = 0,j = 0; char temp[MSG_MAX_SIZE] = {}; char match[MAXLINE]; char pattern[] = "[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}"; for(i =0 ;i< Key_to_Fun_Size;i++) { if(match_string(s,match,tab_Key_to_Fun[i].key_word)) { if((i==0)&& (SOCKFD != 0)) { printf("telnet has connect!! error command !!\n"); return ; } else if((i==0)&& (SOCKFD == 0)) { if(match_string(s,match,pattern)) { printf("---match------%s----------\n",match); for(j =0 ; match[j] != '\0' ;j++) { IP_ADDRESS[j] = match[j]; } IP_ADDRESS[j] = '\0'; tab_Key_to_Fun[i].fun(); } else { /* do nothing */ mosquitto_publish(mosq,NULL,"CCYY ",29,"you should put into your ip\n",0,0); } } else { tab_Key_to_Fun[i].fun(); } return ; } } if((SOCKFD)&&(i != 0)) { writen(SOCKFD,s,strlen(s)); } } static void my_message_callback(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *message) { if(message->payloadlen){ printf(">%s %s", message->topic, (char *)message->payload); search_key_word_to_fun(mosq,(char *)message->payload); //MQTT發啥 就往telnet發啥 }else{ printf("%s (null)\n", message->topic); } //fflush(stdout); } static void my_connect_callback(struct mosquitto *mosq, void *userdata, int result) { int i; if(!result){ /* Subscribe to broker information topics on successful connect. */ mosquitto_subscribe(mosq, NULL, "ycy ", 2); }else{ fprintf(stderr, "Connect failed\n"); } } static void my_subscribe_callback(struct mosquitto *mosq, void *userdata, int mid, int qos_count, const int *granted_qos) { int i; printf("Subscribed (mid: %d): %d", mid, granted_qos[0]); for(i=1; i<qos_count; i++){ printf(", %d", granted_qos[i]); } printf("\n"); } static void my_log_callback(struct mosquitto *mosq, void *userdata, int level, const char *str) { /* Pring all log messages regardless of level. */ printf("%s\n", str); } void wait_message_from_telnet(struct mosquitto *mosq,FILE *fp,uint32 sockfd) { uint32 maxfdp1,nready;//stdineof; fd_set rset; uint8 buf[MAXLINE]; uint8 respbuff[MAXLINE] = {0};; uint32 resplen; uint32 n; uint8 echo_cmd[] = {0xff,0xfb,0x01}; //stdineof = 0; FD_ZERO(&rset); writen(sockfd,echo_cmd,3); for(;;) { //if(stdineof == 0) FD_SET(fileno(fp),&rset); FD_SET(sockfd,&rset); maxfdp1 = max(fileno(fp),sockfd)+1; nready = select(maxfdp1,&rset,NULL,NULL,NULL); if(nready < 0) { ERR_EXIT("ERROR!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); } if(FD_ISSET(sockfd,&rset)) { memset(buf,0,MAXLINE); if((n = read(sockfd,buf,MAXLINE))==0) { ERR_EXIT("str_cli:server termination prematurely"); } buf[n] = '\0'; //printf("FD_ISSET(sockfd,&rset)------11------%s----22----------------\n",buf); if(buf[0] == IAC) { memset(respbuff,0,MAXLINE); resplen = get_every_frame(buf,n,respbuff,MAXLINE); writen(sockfd,respbuff,resplen); } else { writen(fileno(stdout),(char *)buf,n);//當數據比較大的時候 會形成發給cloud數據錯位 //printf("------------2------------\n"); mosquitto_publish(mosq,NULL,"CCYY ",strlen(buf)+1,buf,0,0); //printf("------------3------------\n"); memset(buf,0,MAXLINE); } //writen(fileno(stdout),buf,n); } if(FD_ISSET(fileno(fp),&rset)) { memset(buf,0,MAXLINE); if((n = readline(fileno(fp),(char *)buf,MAXLINE)) == 0) { //stdineof = 1;//此時碰到EOF 而且立刻要發生FIN序列 因此標準輸入不可讀了 shutdown(sockfd,SHUT_WR); FD_CLR(fileno(fp),&rset); INFO_PRINT("nothing input!"); continue; } else if(n >0) { /* do nothing */ } else { ERR_EXIT("some error occurred "); } //printf("FD_ISSET(fileno(fp),&rset)----%d--\n",n); //memset(buf,0,MAXLINE); writen(sockfd,(char *)buf,n); //send_message_to_cloud(sockfd,(char *)buf,n); } } } int main() { struct mosquitto *mosq = NULL; char buff[MSG_MAX_SIZE]; //libmosquitto 庫初始化 mosquitto_lib_init(); //建立mosquitto客戶端 mosq = mosquitto_new(NULL,session,NULL); if(!mosq){ printf("create client failed..\n"); mosquitto_lib_cleanup(); return 1; } //設置回調函數,須要時可以使用 //mosquitto_log_callback_set(mosq, my_log_callback); mosquitto_connect_callback_set(mosq, my_connect_callback); mosquitto_message_callback_set(mosq, my_message_callback); mosquitto_subscribe_callback_set(mosq, my_subscribe_callback); //鏈接服務器 if(mosquitto_connect(mosq, HOST, PORT, KEEP_ALIVE)){ fprintf(stderr, "Unable to connect.\n"); return 1; } //開啓一個線程,在線程裏不停的調用 mosquitto_loop() 來處理網絡信息 int loop = mosquitto_loop_start(mosq); if(loop != MOSQ_ERR_SUCCESS) { printf("mosquitto loop error\n"); return 1; } while(!SOCKFD){}; wait_message_from_telnet(mosq,stdin,SOCKFD); mosquitto_destroy(mosq); mosquitto_lib_cleanup(); return 0; }
一下是程序運行狀況
總結:
1.gdb調試方法十分有效 應當增強掌握
2.在調試過程當中出現過程序不穩定的狀況 可是很偶然 根據那幾回的分析結果 多是讀寫緩衝區的問題 好比發來的數據很快而且多 這時候讀數據的速度跟不上 就會出現顯示出現問題 這個方面我不是很瞭解 之後要了解一下這方面的知識
以上