目录
流程图:
服务端
服务端流程示意图
服务端代码
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <sqlite3.h>
#include <time.h>
#include <sys/wait.h>
#include <string.h>
#include <signal.h>
enum type{
R = 1,
L,
Q,
H,
};
typedef struct{
int type;
char name[32];
char data[256];
}MSG;
//声明
int do_register(int acceptfd,MSG *msg,sqlite3 *db);
int do_login(int acceptfd,MSG *msg,sqlite3 *db);
int do_query(int acceptfd,MSG *msg,sqlite3 *db);
int do_history(int sockfd,MSG *msg,sqlite3 *db);
int callback(void *arg, int f_num, char **f_val, char **f_name);
int search_word(int acceptfd,MSG *msg);
int main(int argc, char const *argv[])
{
if(argc != 2){
printf("plase input:%s <port>\n",argv[0]);
return -1;
}
sqlite3 *db = NULL;
if(sqlite3_open("./student.db",&db) != SQLITE_OK){
//student 是数据库 数据库里有很多的表
fprintf(stderr,"sqlite3_open err:%s\n",sqlite3_errmsg(db));
return -1;
}
//创建用户表,注册登录时候使用
char *errmsg;
if(sqlite3_exec(db,"create table users(name char,password char)",NULL,NULL,&errmsg)!=SQLITE_OK){
fprintf(stderr,"create table err:%s\n",errmsg);
}
//创建历史记录表,查询历史记录
if(sqlite3_exec(db,"create table record(name char,word char,time char);",NULL,NULL,&errmsg)!=SQLITE_OK){
fprintf(stderr,"create table err:%s\n",errmsg);
}
//创建套接字
int sockfd;
sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd < 0){
perror("socket err\n");
return -1;
}
printf("sockfd:%d",sockfd);
struct sockaddr_in serveraddr,clientaddr;
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(atoi(argv[1]));
serveraddr.sin_addr.s_addr = inet_addr("0.0.0.0");
socklen_t len = sizeof(clientaddr);
//绑定
if(bind(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr))<0){
perror("bind err\n");
return -1;
}
printf("bind ok\n");
if(listen(sockfd,5)<0){
perror("listen err\n");
return -1;
}
printf("listen ok\n");
//处理僵尸进程
signal(SIGCHLD,SIG_IGN);
//循环接受阻塞
while(1){
int acceptfd;
acceptfd=accept(sockfd,(struct sockaddr*)&clientaddr,&len);
if(acceptfd<0){
perror("accept err\n");
return -1;
}
printf("acceptfd:%d",acceptfd);
printf("ip:%s port:%d",inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port));
pid_t pid;
pid = fork();
if(pid < 0){
perror("fork err\n");
return -1;
}else if(pid == 0){
MSG msg;
while(1){
int recvbyte;
recvbyte = recv(acceptfd,&msg,sizeof(MSG),0);
if(recvbyte<0){
perror("recv err\n");
return -1;
}else if(recvbyte == 0){
printf("client exit\n");
kill(pid,SIGKILL);
break;
}else{
switch (msg.type){
case R :
do_register(acceptfd,&msg,db);
break;
case L :
do_login(acceptfd,&msg,db);
break;
case Q :
do_query(acceptfd,&msg,db);
break;
case H :
do_history(acceptfd,&msg,db);
break;
}
}
}
}else{
printf("login!\n");
close(acceptfd);
}
}
close(sockfd);
return 0;
}
int do_register(int acceptfd,MSG *msg,sqlite3 *db){
char *errmsg;
char sql[128]; //结构体里包括type 。。 name data(passworld和word)
sprintf(sql,"insert into users values('%s','%s');",msg->name,msg->data);
if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK){
fprintf(stderr,"insert err:%s\n",errmsg);
sprintf(msg->data,"user %s already exit",msg->name);
return -1;
}else{
strcpy(msg->data,"ok");
}
//返回应答
if(send(acceptfd,msg,sizeof(MSG),0)<0){
perror("send err\n");
return -1;
}
return 0;
}
//登录
int do_login(int acceptfd,MSG *msg,sqlite3 *db){
char **res=NULL;
int row,col;
char *errmsg;
char sql[128];
sprintf(sql,"select * from users where name = '%s' and password = '%s';",msg->name,msg->data);
if(sqlite3_get_table(db,sql,&res,&row,&col,&errmsg)!=0){
fprintf(stderr,"select err:%s\n",errmsg);
return -1;
}if(row == 0){
strcpy(msg->data,"name or password err\n");
}else{
strcpy(msg->data,"ok");
}
if(send(acceptfd,msg,sizeof(MSG),0)<0){
perror("send err\n");
return -1;
}
return 0;
}
//查询
int do_query(int acceptfd,MSG *msg,sqlite3 *db){
char date[128];
char sql[128];
char *errmsg;
char word[128];
strcpy(word, msg->data);
int find = search_word(acceptfd, msg);
if (find == 1){
//获取时间
time_t t1;
struct tm *t;
t1 = time(&t1);
t = localtime(&t1);
sprintf(date, "%d-%d-%d %d:%d:%d", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
//将查询记录插入到记录表中
sprintf(sql, "insert into record values('%s','%s','%s');", msg->name, word, date);
if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != 0)
{
fprintf(stderr, "insert err:%s\n", errmsg);
return -1;
}
}else{ //没找到对应单词
strcpy(msg->data, "not found");
if (send(acceptfd, msg, sizeof(MSG), 0) < 0)
{
perror("send err");
return -1;
}
}
return 0;
}
//历史记录
int do_history(int acceptfd,MSG *msg,sqlite3 *db){
char sql[128];
char *errmsg;
sprintf(sql, "select * from record where name='%s';", msg->name);
if (sqlite3_exec(db, sql, callback, &acceptfd, &errmsg) != 0){
fprintf(stderr, "insert err:%s\n", errmsg);
}
msg->data[0] = '\0';
if (send(acceptfd, msg, sizeof(MSG), 0) < 0)
{
perror("send err");
return -1;
}
return 0;
}
//回调
int callback(void *arg, int f_num, char **f_val, char **f_name){
int acceptfd;
MSG msg;
acceptfd = *(int *)arg;
sprintf(msg.data, "%s : %s", f_val[1], f_val[2]);
if (send(acceptfd, &msg, sizeof(MSG), 0) < 0){
perror("send err");
return -1;
}
return 0;
}
//查找单词
int search_word(int acceptfd,MSG *msg){
FILE *fp = fopen("./dict.txt", "r");
if (fp == NULL){
perror("fopen err");
return -1;
}
int len = strlen(msg->data);
char word[300];
while (fgets(word, 300, fp))
{
if (word[strlen(word) - 1] == '\n'){
word[strlen(word) - 1] = '\0';
}
//fgets \n 结束
int ret = strncmp(msg->data, word, len); //比较msg->data 和 word 比较长度len
if (ret == 0 && word[len] == ' ')
{
char *p = word + len;
while (*p == ' '){
p++;
}
strcpy(msg->data, p);
}
}
if (send(acceptfd, msg, sizeof(MSG), 0) < 0)
{
perror("send err");
return -1;
}
fclose(fp);
return 1;
}
客户端
客户端流程示意图
客户端代码
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <sqlite3.h>
#include <string.h>
enum type{
R=1, //注册
L, //登录
Q, //查询
H,//历史
};
typedef struct{
int type;
char name[32];
char data[256]; //passworld or world;
}MSG;
MSG msg;
int do_register(int sockfd,MSG *msg);
int do_login(int sockfd,MSG *msg);
int do_query(int sockfd,MSG *msg);
int do_history(int sockfd,MSG *msg);
int main(int argc, char const *argv[])
{
if (argc != 3){
printf("please input:%s <ip> <port>\n", argv[0]);
return -1;
}
int sockfd,acceptfd;
sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd < 0){
perror("socket err\n");
return -1;
}
printf("sockfd:%d\n",sockfd);
struct sockaddr_in serveraddr;
serveraddr.sin_family= AF_INET;
serveraddr.sin_port= htons(atoi(argv[2]));
serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
if(connect(sockfd,(struct sockaddr *)&serveraddr,sizeof(serveraddr))<0){
perror("connect err");
return -1;
}
printf("connect ok\n");
while(1){
MSG msg;
int n;
printf("*****************************************************\n");
printf("*********** 1: register 2:login 3: quit *************\n");
printf("*****************************************************\n");
printf("****************** plase choose : *******************\n");
scanf("%d",&n);
switch (n){
case 1 :
do_register(sockfd,&msg);
break;
case 2 :
if(do_login(sockfd,&msg)==1){
goto next;
}
break;
case 3 :
close(sockfd);
exit(0);
}
}
next:
while(1){
MSG msg;
int m;
printf("***********************************************\n");
printf("**1:query_world 2:history_recond 3:quit **\n");
printf("***********************************************\n");
printf("***************** plase choose **************\n");
scanf("%d",&m);
switch (m){
case 1 :
do_query(sockfd,&msg);
break;
case 2 :
do_history(sockfd,&msg);
break;
case 3 :
close(sockfd);
exit(0);
}
}
return 0;
}
int do_register(int sockfd,MSG *msg){
msg->type = R;
printf("请输入用户名: ");
scanf("%s",msg->name);
printf("请输入密码:");
scanf("%s",msg->data);
if(send(sockfd,msg,sizeof(MSG),0)<0){
perror("send err\n");
return -1;
}
if(recv(sockfd,msg,sizeof(MSG),0)<0){
perror("recv err\n");
return -1;
}
printf("%s\n",msg->data);
return 0;
}
//登录
int do_login(int sockfd,MSG *msg){
msg->type = L;
printf("请输入用户名: \n");
scanf("%s",msg->name);
printf("请输入密码:\n");
scanf("%s",msg->data);
if(send(sockfd,msg,sizeof(MSG),0)<0){
perror("send err\n");
return -1;
}
if(recv(sockfd,msg,sizeof(MSG),0)<0){
perror("recv err\n");
return -1;
}
if(strncmp(msg->data,"ok",2)==0){
printf("用户登录成功!%s\n",msg->data);
return 1;
}
}
//查询
int do_query(int sockfd,MSG *msg){
msg->type = Q;
while(1){
printf("输入你想查的单词,#退出,请输入:");
scanf("%s",msg->data);
if(strcmp(msg->data,"#")==0){
break;
} //想要查询的目的完成
if(send(sockfd,msg,sizeof(MSG),0)<0){
perror("send err\n");
return -1;
}
if(recv(sockfd,msg,sizeof(MSG),0)<0){
perror("recv err\n");
return -1;
}
printf("**********************************\n");
printf("你想查询的单词结果:%s\n",msg->data);
printf("**********************************\n");
}
return 0;
}
int do_history(int sockfd,MSG *msg){
msg->type = H;
if(send(sockfd,msg,sizeof(MSG),0)<0){
perror("send err");
return -1;
}
while(1){
if(recv(sockfd,msg,sizeof(MSG),0)<0){
perror("send err");
return -1;
}
if(msg->data[0]=='\0'){
break;
}
printf("历史浏览记录:%s\n",msg->data);
}
return 0;
}