Tcp、select函数实现在线词典(C语言)
生活随笔
收集整理的這篇文章主要介紹了
Tcp、select函数实现在线词典(C语言)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
功能:
注冊:添加用戶名和密碼到數據庫。
登錄:檢索數據庫,查詢是否符合。
查詢:檢索字典文本文件,查詢結果存入數據庫中。
歷史:檢索數據庫,將登錄賬戶的查詢歷史打印。
TCP服務器:
聲明與定義
#define ERRLOG(msg) \do \{ \printf("%s %s(%d):", __FILE__, __func__, __LINE__); \perror(msg); \exit(-1); \} while (0) //消息結構體封裝 typedef struct msg {char code;char name[20];char txt[128]; } msg_t;sqlite3 *sql_init();//數據庫初始化 int log_sql(msg_t *clientmsg, sqlite3 *my_sql, int clientfd);//注冊 int select_sql(msg_t *clientmsg, sqlite3 *my_sql, int clientfd);//登錄 int printf_sql(msg_t *clientmsg, sqlite3 *my_sql, int clientfd);//檢索單詞 int history_sql(msg_t *clientmsg, sqlite3 *my_sql, int clientfd);//查看歷史 int str_deal(char *buf);//字符串處理 int time_get(char *timestr);//獲取時間主函數體
//檢查輸入if (3 != argc){printf("Usage: %s <IP> <port>\n", argv[0]);return -1;} 1、第一步配置服務器結構體和套接字 //套接字int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (-1 == sockfd){ERRLOG("socket error");} //配置服務器結構體struct sockaddr_in serveraddr;memset(&serveraddr, 0, sizeof(serveraddr));serveraddr.sin_family = AF_INET;serveraddr.sin_port = htons(atoi(argv[2]));serveraddr.sin_addr.s_addr = inet_addr(argv[1]);socklen_t serveraddr_len = sizeof(serveraddr);if (-1 == bind(sockfd, (struct sockaddr *)&serveraddr, serveraddr_len)){ERRLOG("bind error");}if (-1 == listen(sockfd, 5)){ERRLOG("listen error");} 2、配置select函數的文件句柄 int maxfd = 0;fd_set readfds;fd_set readfdstemp;FD_ZERO(&readfds);FD_ZERO(&readfdstemp);//將套接字描述符添加到句柄中FD_SET(sockfd, &readfds);maxfd = maxfd > sockfd ? maxfd : sockfd; 3、初始化數據庫 sqlite3 *my_sql = sql_init(); 4、通過select函數檢索句柄實現的邏輯結構 int ret = 0;//保存有幾個文件描述符就緒int i = 0;//在循環中代表了文件描述符int clientfd;//客戶端連接創建的套接字int nbyte = 0;//接受多少字節while (1){FD_ZERO(&readfdstemp);readfdstemp = readfds;//阻塞等待有1個或者多個文件描述符就緒ret = select(maxfd + 1, &readfdstemp, NULL, NULL, NULL);if (ret == -1){PRINT_ERR("select init error");}else{//遍歷句柄,區分有客戶端連接還是客戶端發送消息for (i = 3; i < (maxfd + 1) && ret != 0; i++){if (FD_ISSET(i, &readfdstemp)){if (i == sockfd){if ((clientfd = accept(i, NULL, NULL)) == -1){PRINT_ERR("accept error");}printf("新用戶已連接\n");FD_SET(clientfd, &readfds);maxfd = maxfd > clientfd ? maxfd : clientfd;}else{memset(&severmsg, 0, sizeof(severmsg));if ((nbyte = recv(i, &severmsg, sizeof(severmsg), 0)) == -1){PRINT_ERR("recv error");}else if (nbyte == 0){printf("用戶斷開連接\n");FD_CLR(i, &readfds);close(i);continue;}//根據結構體中的操作碼.code判斷客戶端需求switch (severmsg.code){case '1':log_sql(&severmsg, my_sql, i);break;case '2':select_sql(&severmsg, my_sql, i);break;case '3':printf_sql(&severmsg, my_sql, i);break;case '4':history_sql(&severmsg, my_sql, i);break;}}//每次處理完一個就緒,已就緒的文件描述符就減少了一個ret--;}}}}功能模塊
數據庫初始化:
客戶端
聲明與定義
#define ERRLOG(msg) \do \{ \printf("%s %s(%d):", __FILE__, __func__, __LINE__); \perror(msg); \exit(-1); \} while (0)typedef struct msg {char code;char name[20];char txt[128]; } msg_t;int log_sql(msg_t *clientmsg, int sockfd); int select_sql(msg_t *clientmsg, int sockfd); int printf_sql(msg_t *clientmsg, int sockfd); int history_sql(msg_t *clientmsg, int sockfd);主函數體
if (3 != argc){printf("Usage: %s <IP> <port>\n", argv[0]);return -1;} 1、配置服務器和服務器結構體、連接服務器 int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (-1 == sockfd){ERRLOG("socket error");}struct sockaddr_in serveraddr;memset(&serveraddr, 0, sizeof(serveraddr));serveraddr.sin_family = AF_INET;serveraddr.sin_port = htons(atoi(argv[2]));serveraddr.sin_addr.s_addr = inet_addr(argv[1]);socklen_t serveraddr_len = sizeof(serveraddr);if (-1 == connect(sockfd, (struct sockaddr *)&serveraddr, serveraddr_len)){ERRLOG("connect error");} 2、邏輯及實現 msg_t clientmsg;memset(&clientmsg, 0, sizeof(clientmsg));while (1){printf("************************************************\n");printf("**************1、注冊 2、登錄 *******************\n");printf("************************************************\n");scanf(" %c", &(clientmsg.code));printf("請輸入用戶名和密碼:");scanf("%s %s", clientmsg.name, clientmsg.txt);switch (clientmsg.code){case '1':log_sql(&clientmsg, sockfd);break;case '2':select_sql(&clientmsg, sockfd);if (clientmsg.code == '2'){ //如果登陸失敗,服務器傳回錯誤碼5goto NEXT;}break;}memset(clientmsg.txt, 0, sizeof(clientmsg.txt));clientmsg.code = 0;} NEXT:while (1){printf("************************************************\n");printf("**********1、查詢 2、歷史 3、登出***************\n");printf("************************************************\n");scanf(" %c", &(clientmsg.code));switch (clientmsg.code){case '1':clientmsg.code = '3';printf("輸入單詞:");scanf("%s", clientmsg.txt);printf_sql(&clientmsg, sockfd);break;case '2':clientmsg.code = '4';history_sql(&clientmsg, sockfd);break;}memset(clientmsg.txt, 0, sizeof(clientmsg.txt));clientmsg.code = 0;}功能模塊
1、注冊模塊 int log_sql(msg_t *clientmsg, int sockfd) {int nbyte = 0;if (send(sockfd, clientmsg, sizeof(msg_t), 0) == -1){PRINT_ERR("send error");}if ((nbyte = recv(sockfd, clientmsg, sizeof(msg_t), 0)) == -1){PRINT_ERR("recv error");}if (clientmsg->code == '5'){printf("注冊成功\n");}else{printf("用戶名已被注冊\n");}return 0; } 2、登錄 int select_sql(msg_t *clientmsg, int sockfd) {int nbyte = 0;if (send(sockfd, clientmsg, sizeof(msg_t), 0) == -1){PRINT_ERR("send error");}if ((nbyte = recv(sockfd, clientmsg, sizeof(msg_t), 0)) == -1){PRINT_ERR("recv error");}if (clientmsg->code == '5'){printf("用戶名或密碼不正確,請確認用戶名和密碼或注冊\n");}else{printf("登錄成功\n");}return 0; } 3、查詢 int printf_sql(msg_t *clientmsg, int sockfd) {int nbyte = 0;if (send(sockfd, clientmsg, sizeof(msg_t), 0) == -1){PRINT_ERR("send error");}if ((nbyte = recv(sockfd, clientmsg, sizeof(msg_t), 0)) == -1){PRINT_ERR("recv error");}printf("%s\n", clientmsg->txt);return 0; } 4、歷史查看 int history_sql(msg_t *clientmsg, int sockfd) {int nbyte = 0;if (send(sockfd, clientmsg, sizeof(msg_t), 0) == -1){PRINT_ERR("send error");}//判斷是否接收完畢while (strcmp(clientmsg->txt,"**over**")){if ((nbyte = recv(sockfd, clientmsg, sizeof(msg_t), 0)) == -1){PRINT_ERR("recv error");}printf("%s\n", clientmsg->txt);}return 0; }總結
以上是生活随笔為你收集整理的Tcp、select函数实现在线词典(C语言)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php实现国外邮箱,发送电子邮件 · 国
- 下一篇: Plotly中绘制三种经典的股票交易图表