服务器:

head.h

#ifndef _HEAD_H_
#define _HEAD_H_#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sqlite3.h>
#include <signal.h>
#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>//消息的类型
#define USER_REGISTER    10
#define USER_LOGIN       20
#define USER_WORD        30
#define USER_SUCCESS     40
#define USER_FAILURE     50//__attribute__((__packed__))
//作用:告诉编译器在编译的过程中取消优化对齐。
//      方便我们在发送和接收数据的时候一个字节一个字节的排列
typedef struct
{char _username[25]; //用户名char _password[25]; //密码
}__attribute__((__packed__))user_t;typedef struct
{int type;           //消息类型int size;           //消息大小union{user_t uinfo;        //用户信息char   _word[1024]; }content;//客户端填单词,服务端填写单词解释
#define word         content._word
#define username     content.uinfo._username
#define password       content.uinfo._password
}__attribute__((__packed__))mhead_t;//'\'表示多行链接上一行表示, #deifne ....do...while(0);
//表示封装成独立的语法单元,防止被语法错误。
//注意:'\'之后不要留空格,要不然编译会有警告
extern int do_client(int sockfd,sqlite3 *pdb);#define EXEC_SQL(db,sql,errmsg) do{\if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) < 0)\{\fprintf(stderr,"sqlite3 execl [%s] error : %s.\n",sql,errmsg);\exit(EXIT_FAILURE);\}\
}while(0);#endif

server.c

#include "head.h"void signal_handler(int signum)//
{waitpid(-1,NULL,WNOHANG);return;
}
int init_tcp(char *ip,char *port)//建立套接字,绑定ip和端口号
{int sockfd;struct sockaddr_in server_addr;if((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0){perror("Fail to socket");exit(EXIT_FAILURE);}bzero(&server_addr,sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_port   = htons(atoi(port));server_addr.sin_addr.s_addr = inet_addr(ip);if(bind(sockfd,(struct sockaddr *)&server_addr,sizeof(server_addr)) < 0){perror("Fail to bind");exit(EXIT_FAILURE);}listen(sockfd,5);printf("listen....\n");return sockfd;
}//.server ip port db
//数据库中已经手动创建了2个表:user_table,word_table
//注:由于我们后面函数要传承,故这里的const应该去掉
int main(int argc, char *argv[])
{int pid;   sqlite3 *pdb;int listenfd,connect_fd;int addr_len = sizeof(struct sockaddr);struct sockaddr_in peer_addr;if(argc < 4){fprintf(stderr,"Usage : %s ip port system.db.\n",argv[0]);exit(EXIT_FAILURE);}//探测子进程的改变状态,回收僵尸态子进程if(signal(SIGCHLD,signal_handler) == SIG_ERR){perror("Fail to signal");exit(EXIT_FAILURE);}if(sqlite3_open(argv[3],&pdb) != SQLITE_OK){fprintf(stderr,"sqlite3 open %s : %s.\n",argv[3],sqlite3_errmsg(pdb));exit(EXIT_FAILURE);}//初始化tcp连接,得到监听套接字listenfd = init_tcp(argv[1],argv[2]);//提取客户段的链接请求,创建子进程和客户端交互while(1){if((connect_fd = accept(listenfd,(struct sockaddr *)&peer_addr,&addr_len)) < 0){perror("Fail to accept");exit(EXIT_FAILURE);}if((pid = fork()) < 0){perror("Fail to fork");exit(EXIT_FAILURE);}//创建子进程处理客户端的请求if(pid == 0){close(listenfd);do_client(connect_fd,pdb);}close(connect_fd);}exit(EXIT_SUCCESS);
}

do_client.c

#include "head.h" int do_register(int sockfd,sqlite3 *pdb,char *_username,char *_password)
{char *errmsg;char buf[1024];char **dbresult;int nrow = 0,ncolumn = 0;char sql[1024] = {0};mhead_t *head = (mhead_t *)buf;  sprintf(sql,"select * from user_table where NAME='%s';",_username);if(sqlite3_get_table(pdb,sql,&dbresult,&nrow,&ncolumn,&errmsg) != 0){fprintf(stderr,"sqlite3 get table error : %s.\n",errmsg);exit(EXIT_FAILURE);}//没有这样的用户名if(nrow == 0){//录入数据库bzero(sql,sizeof(sql));sprintf(sql,"insert into user_table values('%s','%s');",_username,_password);EXEC_SQL(pdb,sql,errmsg);printf("ok ........\n");head->type = USER_SUCCESS;if(send(sockfd,buf,sizeof(mhead_t),0) < 0){perror("Fail to send");exit(EXIT_FAILURE);}//注册失败,用户名存在}else{head->type = USER_FAILURE;if(send(sockfd,buf,sizeof(mhead_t),0) < 0){perror("Fail to send");exit(EXIT_FAILURE);}//表示未知    printf("???????\n");}//插入到数据库之后,释放dbresult结果sqlite3_free_table(dbresult);return 0;
}int do_login(int sockfd,sqlite3 *pdb,char *_username,char *_password)
{char *errmsg;char buf[1024];char **dbresult;char sql[1024] ={0};int nrow = 0,ncolumn= 0;mhead_t *head = (mhead_t *)buf;sprintf(sql,"select * from user_table where NAME = '%s';",_username);if(sqlite3_get_table(pdb,sql,&dbresult,&nrow,&ncolumn,&errmsg) != 0){fprintf(stderr,"sqlite3 get table error404 : %s.\n",errmsg);exit(EXIT_FAILURE);}//    用户名存在if(nrow == 1){bzero(sql,sizeof(sql));sprintf(sql,"select * from user_table where PASSWORD = '%s';",_password);//确认用户名和密码是否匹配if(sqlite3_get_table(pdb,sql,&dbresult,&nrow,&ncolumn,&errmsg) != 0){perror("sqlite3_get_table");exit(EXIT_FAILURE);}else{head->type = USER_SUCCESS;if(send(sockfd,buf,sizeof(mhead_t),0) < 0){perror("Fail to send");exit(EXIT_FAILURE);}printf("..........ok\n");}}else{head->type = USER_FAILURE;if(send(sockfd,buf,sizeof(mhead_t),0) < 0){perror("Fail to send");exit(EXIT_FAILURE);}printf("??????\n");}sqlite3_free_table(dbresult);//插入到数据库之后,释放dbresult结果return 0;
}int do_query(int sockfd,sqlite3 *pdb,char *_word)
{int i,j;char *errmsg;int count = 0;char buf[1024];//定义历史记录缓存区char sql[1024] = {0};char **dbresult;int nrow = 0, ncolumn = 0;mhead_t *head = (mhead_t *)buf;sprintf(sql,"select * from  dict_table where word ='%s';",_word);if(sqlite3_get_table(pdb,sql,&dbresult,&nrow,&ncolumn,&errmsg)!=0){fprintf(stderr,"sqlite3 get table error :%s.\n",errmsg);exit(EXIT_FAILURE);}if(nrow == 1){bzero(sql,sizeof(sql));sprintf(sql,"select * from dict_table;");if(sqlite3_get_table(pdb,sql,&dbresult,&nrow,&ncolumn,&errmsg) != SQLITE_OK){fprintf(stderr,"sqlite3_get_table %s\n",errmsg);exit(EXIT_FAILURE);}for(i = 0;i <= nrow;i++){for(j = 0;j < ncolumn;j++){if(strcmp(dbresult[count],_word) == 0){strcpy(head->word,dbresult[count]);strcat(head->word, "   ");strcat(head->word,dbresult[count+1]);printf("%s\n",dbresult[count + 1]);i = nrow +1;break;}count ++;}}head->type = USER_SUCCESS;if(send(sockfd,buf,sizeof(mhead_t),0)<0){perror("Fail to send");bzero(sql,sizeof(sql));exit(EXIT_FAILURE);}}else{head->type = USER_FAILURE;if(send(sockfd,buf,sizeof(mhead_t),0)<0 ){perror("Fail to send");exit(EXIT_FAILURE);}printf("?????\n");}sqlite3_free_table(dbresult);
}
int do_client(int sockfd,sqlite3 *pdb)
{int n;int count = 0;char buf[1024];mhead_t *head = (mhead_t *)buf;   while(1){count = 0;//接收协议头while(1){n = recv(sockfd,buf + count,sizeof(mhead_t) - count,0);if(n <= 0){exit(EXIT_FAILURE);}count += n;printf("count : %d mhead_t : %ld\n",count,sizeof(mhead_t));if(count == sizeof(mhead_t))break;}switch(head->type){case USER_REGISTER:do_register(sockfd,pdb,head->username,head->password);    break;case USER_LOGIN:do_login(sockfd,pdb,head->username,head->password);break;case USER_WORD:do_query(sockfd,pdb,head->word);break;
defalut:exit(EXIT_SUCCESS);}    }return 0;
}

客户端

head.h

#ifndef _HEAD_H_
#define _HEAD_H_#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sqlite3.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
//消息的类型
#define USER_REGISTER    10
#define USER_LOGIN       20
#define USER_WORD        30
#define USER_SUCCESS     40
#define USER_FAILURE     50//__attribute__((__packed__))
//作用:告诉编译器在编译的过程中取消优化对齐。
//      方便我们在发送和接收数据的时候一个字节一个字节的排列
typedef struct
{char _username[25]; //用户名char _password[25]; //密码
}__attribute__((__packed__))user_t;typedef struct
{int type;           //消息类型int size;           //消息大小union{user_t uinfo;        //用户信息char   _word[1024]; }content;//客户端填单词,服务端填写单词解释
#define word         content._word
#define username     content.uinfo._username
#define password       content.uinfo._password
}__attribute__((__packed__))mhead_t;extern void help_info2();
extern int do_task(int sockfd);
extern int do_query(int sockfd);
extern int do_task2(int sockfd);
//'\'表示多行链接上一行表示, #deifne ....do...while(0);
//表示封装成独立的语法单元,防止被语法错误。
//注意:'\'之后不要留空格,要不然编译会有警告#define EXEC_SQL(db,sql,errmsg) do{\if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) < 0)\{\fprintf(stderr,"sqlite3 execl [%s] error : %s.\n",sql,errmsg);\exit(EXIT_FAILURE);\}\
}while(0);#endif

client.c

#include "head.h"
//用户提示界面1
void help_info1()
{printf("\t-----------------------------------------------\n");printf("\t|               HENRY   在线辞典               |\n");printf("\t|版本:0.0.1                                    |\n");printf("\t|作者:HENRY老师                                |\n");printf("\t|功能:                                         |\n");printf("\t|    [1] 登录                                  |\n");printf("\t|    [2] 注册                                  |\n");printf("\t|    [3] 退出                                  |\n");printf("\t|注意:用户只有登录成功后才能进入查单词界面     |\n");printf("\t------------------------------------------------\n");return;
}void help_info2()
{printf("\t-----------------------------------------------\n");printf("\t|               HENRY   在线辞典               |\n");printf("\t|版本:0.0.1                                    |\n");printf("\t|作者:HENRY老师                                |\n");printf("\t|功能:                                         |\n");printf("\t|    [1] 查询单词                              |\n");printf("\t|    [2] 查询历史记录                          |\n");printf("\t|    [3] 退出查询系统                                  |\n");printf("\t|注意:用户只有登录成功后才能进入查单词界面     |\n");printf("\t----------------------------------------------- \n");return;}//用户输入指令,供大家选择
enum{LOGIN    = 1,  //登陆REGISTER = 2,  //注册QUIT     = 3,  //退出QUERY    = 1,  //查询单词HISTORY  = 2,  //查询历史
};int init_tcp(char *ip,char *port)
{int sockfd;struct sockaddr_in server_addr;if((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0){perror("Fail to socket"); exit(EXIT_FAILURE);}bzero(&server_addr,sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_port = htons(atoi(port));server_addr.sin_addr.s_addr = inet_addr(ip);if(connect(sockfd,(struct sockaddr *)&server_addr,sizeof(server_addr)) < 0){perror("Fail to bind");   exit(EXIT_FAILURE);}return sockfd;
}int do_register(int sockfd)
{int n = 0;int count = 0;char buf[1024] = {0};//定义发送的协议头mhead_t *head = (mhead_t *)buf;printf("\n您正在注册,请输入用户名和密码\n");head->type = USER_REGISTER;head->size = sizeof(mhead_t);printf("Input username : ");fgets(head->username,sizeof(head->username),stdin);head->username[strlen(head->username) - 1] = '\0';printf("Input password : ");fgets(head->password,sizeof(head->password),stdin);head->password[strlen(head->password) - 1] = '\0';//发给服务器端if(send(sockfd,buf,sizeof(mhead_t),0) < 0){perror("Fail to send");exit(EXIT_FAILURE);}bzero(&buf,sizeof(buf));while(1){//接收数据,TCP是可靠的连接,若是数据//未完全接收的话,可以在接收n = recv(sockfd,buf + count,sizeof(mhead_t) - count,0);if(n <= 0){perror("Fail to send");exit(EXIT_FAILURE);}//若是数据未发送完成,再次接收的时候可补充count += n;if(count == sizeof(mhead_t))break;}if(head->type == USER_SUCCESS){printf("\n恭喜您,注册成功!\n");    return 0;}else{printf("\n很遗憾,这个用户名已经被其它用户注册过了,请重新注册");  return -1;}}int do_login(int sockfd)
{int n = 0;int count = 0;char buf[1024] = {0};mhead_t *head = (mhead_t *)buf;//定义发送的协议头printf("\n您正在登陆,请输入用户名和密码\n");head->type = USER_LOGIN;head->size = sizeof(mhead_t);printf("Input username : ");fgets(head->username,sizeof(head->username),stdin);head->username[strlen(head->username) - 1] = '\0';printf("Input password : ");fgets(head->password,sizeof(head->password),stdin);head->password[strlen(head->password) - 1] = '\0';if(send(sockfd,buf,sizeof(mhead_t),0) < 0){perror("Fail to send");exit(EXIT_FAILURE);}   bzero(&buf,sizeof(buf));while(1){n = recv(sockfd,buf + count,sizeof(mhead_t) - count,0);if(n <= 0){perror("Fail to send");exit(EXIT_FAILURE);}count += n;if(count == sizeof(mhead_t))break;}if(head->type == USER_SUCCESS){printf("\n恭喜您,登陆成功\n");do_task2(sockfd);return 0;}else{printf("\n抱歉,用户名或密码错误");return -1;}
}  int do_query(int sockfd)//单词查询
{int fd;int ret = 0;time_t t;time(&t);char buf[1024];char words[1024];int count = 0;ssize_t wr_bytes;mhead_t *head = (mhead_t *)buf;printf("\n您,正在查询单词!\n");head->type = USER_WORD;head->size = sizeof(mhead_t);printf("Input word : ");fgets(head->word,sizeof(head->word),stdin);head->word[strlen(head->word)-1] ='\0';if(send(sockfd,buf,sizeof(mhead_t),0)<0) //发送给服务器{perror("Fail to send");exit(EXIT_FAILURE);}bzero(buf,sizeof(buf));while(1){ret = recv(sockfd,buf+count,sizeof(mhead_t)-count,0);   if(ret <= 0){perror("Fail to send");exit(EXIT_FAILURE);}count += ret;if(ret == sizeof(mhead_t)){break;}}if(head->type == USER_SUCCESS) //单词存在 {printf("%s\n",head->word);fd = open("word_record.txt",O_RDWR|O_CREAT|O_APPEND,0666); //打开文件if(fd == -1){perror("open");return -1;}sprintf(words,"%s %s\n",ctime(&t),head->word);//单词以及查询时间放入数据库wr_bytes = write(fd,words,strlen(words)); //单词写入文件if(wr_bytes == -1){perror("write");return -1;}do_task2(sockfd);}else{printf("no such word\n");//该单词不存在return -1;}close(fd);
}int do_history(int sockfd)//查询历史记录
{FILE *fp;char words[1024];char * rd_bytes;fp = fopen("word_record.txt","r");//以只读方式打开文件if(fp == NULL){perror("");return -1;}fseek(fp,0,SEEK_SET);while(1){rd_bytes = fgets(words,sizeof(words),fp); //按行写入if(rd_bytes == NULL) //没有该单词{perror("read");return -1;}else if(rd_bytes == 0)//有该单词{break;//找到单词,跳出循环}else{printf("%s\n",words);}}do_task2;fclose(fp);
}int do_task(int sockfd)
{int cmd;while(1){//提示界面帮助,用户选择help_info1(); printf("\n\n请选择>");scanf("%d",&cmd);//吃掉回车键getchar();switch(cmd){//用户注册,我们先来写注册的函数case REGISTER:if(do_register(sockfd) < 0)continue;break;//用户登陆case LOGIN:    if(do_login(sockfd) < 0)continue;break;case QUIT:exit(EXIT_SUCCESS);default:printf("Unknow cmd.\n");continue;}}return 0;
}int do_task2(int sockfd)
{int cmd;while(1){//登陆成功选项页面help_info2();printf("\n\n请选择>");scanf("%d",&cmd);//吃掉回车键getchar();switch(cmd){case QUERY://用户查询单词if(do_query(sockfd) < 0)continue;break;case HISTORY://历史查询if(do_history(sockfd < 0))continue;break;case QUIT:exit(EXIT_SUCCESS);default:printf("Unknow cmd.\n");continue;}}
}//./client ip port
//由于后面要传递参数,故这里的const省略
int main(int argc, char *argv[])
{int sockfd;    int addr_len = sizeof(struct sockaddr);struct sockaddr_in peer_addr;if(argc < 3){fprintf(stderr,"Usage : %s argv[1] argv[2]\n",argv[0]);  exit(EXIT_FAILURE);}sockfd = init_tcp(argv[1],argv[2]);do_task(sockfd);return 0;
}

Linux在线词典项目,实现注册,登陆,查询单词以及查询历史记录,退出查询等功能,(涉及网络编程,进程线程,文件io,sqlite)相关推荐

  1. 基于QT的【第一个项目】设计+所有组件配合使用+网络编程局域网通信+文件IO操作+登录界面和头像+多界面跳转+JSON数据解析+表情包制作

    基于QT的第一个项目+所有组件配合使用+网络编程局域网通信+文件IO操作+登录界面和头像+多界面跳转+JSON数据解析+表情包制作 第一阶段 网络编程局域网TCP/IP聊天QT实现 main.c ma ...

  2. Linux运维系列总结-Linux系统启动过程、WEB工作原理、DHCP工作原理、DNS解析原理、NFS网络文件系统、FTP文件传输协议、PXE+KICKSTART自动安装系统

    Linux运维系列总结-Linux系统启动过程.WEB工作原理.DHCP工作原理.DNS解析原理.NFS网络文件系统.FTP文件传输协议.PXE+KICKSTART自动安装系统 1.Linux系统的启 ...

  3. Linux io模型及函数调用,Linux 网络编程的5种IO模型:信号驱动IO模型

    Linux 网络编程的5种IO模型:信号驱动IO模型 背景 这一讲我们来看 信号驱动IO 模型. 介绍 情景引入: 在信号驱动IO模型中,当用户线程发起一个IO请求操作,会给对应的socket注册一个 ...

  4. Linux网络编程——在线词典项目

    目录 一.要求 二.框架 三.各部分的实现 客户端 注册 登录 查询 历史查询 服务器 解析客户端命令 注册 登录 单词查询 时间获取 查询单词成功向数据库插入时间等信息 历史查询 四.项目源码 客户 ...

  5. 项目实战——基于Java8+JavaFX+多线程+文件IO+SQLite数据库实现的本地文件快速搜索引擎详细设计实现

    目录 一.前言介绍 二.功能展示 2.1选择所要查找的文件夹 2.2将所选目录下的所有文件进行属性展示 2.3支持搜索框查询文件(模糊查询) 2.4统计本次扫描信息 ​编辑 三.整体设计 3.1工具类 ...

  6. Linux socket 网络编程 常用头文件

    一 三种类型的套接字: 1.流式套接字(SOCKET_STREAM) 提供面向连接的可靠的数据传输服务.数据被看作是字节流,无长度限制.例如FTP协议就采用这种. 2.数据报式套接字(SOCKET_D ...

  7. Linux 网络编程-进程管道

    目录 4.1 管道 4.3.1 用 C 来建立.使用管道 4.3.2 需要注意的问题 4.2 有名管道 4.4.1 有名管道的创建 4.4.2 有名管道的 I/O 使用 4.4.3 未提到的关于有名管 ...

  8. Linux网络编程常用头文件解释

    sys/types.h:数据类型定义 sys/socket.h:提供socket函数及数据结构 netinet/in.h:定义数据结构sockaddr_in arpa/inet.h:提供IP地址转换函 ...

  9. linux服务器网络编程之线程模型

    前言   本文将主要介绍传统的和目前流行的进程/线程模型,在讲进程/线程模型之前需要先介绍一种设计模式: Reactor 模式.Reactor 模式首先是事件驱动的,有一个或多个并发输入源,有一个Se ...

  10. Linux后端服务器网络编程之线程模型丨reactor模型详解

    前言   上一篇文章<后端服务器网络编程之 IO 模型>中讲到服务器端高性能网络编程的核心在于架构,而架构的核心在于进程/线程模型的选择.本文将主要介绍传统的和目前流行的进程/线程模型,在 ...

最新文章

  1. python 中UnicodeEncodeError 错误
  2. (十)OpenStack---M版---双节点搭建---Heat安装和配置
  3. 中国移动短信网关CMPP3.0 C#源代码:使用示例
  4. C语言练习题——动态数组
  5. MySQL拷贝表的几种方式
  6. ASP.NET repeater添加序号列的方法
  7. Chrome OS 设备或将允许用户自行选择 Linux 发行版
  8. Win7搭建http文件共享
  9. vue:无法将“vue”识别为脚本_Vue3将带来巨大的性能提升
  10. 【收藏】从A到Z,26个实用Python模块/函数速览
  11. 如何在DNN4下使用VS2005进行单元测试???
  12. 如何把几张图片合成一个pdf?
  13. Linux安装libmodbus库
  14. 启动计算机管理服务,win10系统打开服务管理器的五种方法
  15. 次世代贴图材质制作的提示和秘籍
  16. 大数据平台架构与原型实现-读书笔记8
  17. 高中信息技术c语言编程题,高中信息技术招聘C语言编程题精选.doc
  18. 移动互联网时代电商如何突围?
  19. LM358与TL431验证
  20. 赵青-《剑侠情缘网络版》开发回顾

热门文章

  1. 分析思维模型:SPACE 矩阵
  2. Matlab中进行高斯滤波-学习笔记
  3. Java高并发编程实战4,synchronized与Lock底层原理
  4. 基于python的人脸识别开题报告怎么写_开题报告-人脸识别系统的研究与实现
  5. C语言-00如何学习C语言与图形库的使用
  6. 二叉树的前中后序遍历
  7. 视频去模糊论文阅读-Cascaded Deep Video Deblurring Using Temporal Sharpness Prior
  8. c语言pi算法程序,C语言计算圆周率PI
  9. Android--- UI组件AdapterView and 适配器Adapter
  10. PC常见故障及解决思路汇总(系统方面)