一、云词典项目:
采用C语言编写,采用了数据库和网络编程。
有四个功能:注册、登录、查询、查阅历史查阅记录。
作为练习的项目,写完就没有去优化。
后来发现了如果查阅比较靠后的单词需要执行较长的时间,解决方法是先把文件内容写入数据库中,再去查阅,写完后发现那样开始运行时录入数据库也需要耗费较长时间,不过查阅起来就快多了。这里是原先的项目代码。
二、项目流程图
三、代码部分
①服务端代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/epoll.h>
#include <string.h>
#include <sqlite3.h>
#include "head.h"
pass_t pass;
void server_registration(int fd, sqlite3 *db);
void server_login(int fd, sqlite3 *db);
void query_(FILE *fp, int fd);
int main(int argc, char const *argv[])
{
int sockfd, acceptfd;
int sendbyte, recvbyte;
char *errmsg;
//1.打开或创建数据库
sqlite3 *db = NULL;
if (sqlite3_open("./cidian.db", &db))
{
fprintf(stderr, "sqlite3 open err:%s\n", sqlite3_errmsg(db));
return -1;
}
//2.在数据库中创建表
if (sqlite3_exec(db, "create table namepass(name char,password char);", NULL, NULL, &errmsg))
{
fprintf(stderr, "create err:%s\n", errmsg);
return -1;
}
FILE *fp = fopen("./dict.txt", "r");
if (fp == NULL)
{
perror("fopen err\n");
return -1;
}
if (argc != 2)
{
printf("please input %s <port>\n", argv[0]);
return -1;
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
perror("socket err.");
return -1;
}
struct sockaddr_in serveraddr, caddr;
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(caddr);
if (bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
{
perror("bind err.");
return -1;
}
if (listen(sockfd, 5) < 0)
{
perror("listen err.");
return -1;
}
//引入epoll实现IO多路复用 sockfd-读
struct epoll_event event; //暂时保存要添加到树上的文件描述符事件
struct epoll_event revents[20]; //保存从链表中获取产生事件的文件描述符
//1.创建树
int epfd = epoll_create(1);
//2.将关心文件描述符添加到树上
event.data.fd = sockfd;
event.events = EPOLLIN | EPOLLET;
epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &event);
//调用epoll_wait函数循环到链表中获取事件
int n;
while (1)
{
n = epoll_wait(epfd, revents, 20, -1);
if (n < 0)
{
perror("epoll err.");
return -1;
}
for (int i = 0; i < n; i++)
{
if (revents[i].data.fd == sockfd)
{
acceptfd = accept(sockfd, (struct sockaddr *)&caddr, &len);
if (acceptfd < 0)
{
perror("accept err.");
return -1;
}
printf("client:ip=%s port=%d\n",
inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port));
//链接成功后用于通信的文件描述符添加到表中,收-读事件
event.data.fd = acceptfd;
event.events = EPOLLIN | EPOLLET;
epoll_ctl(epfd, EPOLL_CTL_ADD, acceptfd, &event);
}
else
{
recvbyte = recv(revents[i].data.fd, &pass, sizeof(pass), 0);
if (recvbyte < 0)
{
perror("recv err.");
return -1;
}
else if (recvbyte == 0)
{
printf("%d client exit.\n", revents[i].data.fd);
close(revents[i].data.fd);
epoll_ctl(epfd, EPOLL_CTL_DEL, revents[i].data.fd, NULL);
}
else
{
printf("%d:type:%d op:%s\n", revents[i].data.fd, pass.type, pass.operate);
switch (pass.type)
{
case registration:
server_registration(revents[i].data.fd, db);
break;
case login:
server_login(revents[i].data.fd, db);
break;
case quit:
printf("%d client exit.\n", revents[i].data.fd);
close(revents[i].data.fd);
epoll_ctl(epfd, EPOLL_CTL_DEL, revents[i].data.fd, NULL);
break;
case query:
query_(fp,revents[i].data.fd);
fseek(fp,0,SEEK_SET);
break;
}
}
}
}
}
close(sockfd);
sqlite3_close(db);
fclose(fp);
return 0;
}
void server_registration(int fd, sqlite3 *db)
{
char **ftp = NULL;
int sendbyte;
int n, l, k = 0;
char sql[128];
char *errmsg;
char buf[128] = "";
if (sqlite3_get_table(db, "select name from namepass;", &ftp, &n, &l, &errmsg))
{
fprintf(stderr, "select err:%s\n", errmsg);
return;
}
for (int i = 0; i < n + 1; i++)
{
for (int j = 0; j < l; j++)
{
if (!strcmp(pass.name, ftp[k++]))
{
sprintf(buf, "User name already exists");
sendbyte = send(fd, buf, sizeof(buf), 0);
if (sendbyte < 0)
{
perror("send err\n");
return;
}
return;
}
}
}
sprintf(sql, "insert into namepass values(\"%s\",\"%s\");", pass.name, pass.password);
if (sqlite3_exec(db, sql, NULL, NULL, &errmsg))
{
fprintf(stderr, "insert err:%s\n", errmsg);
return;
}
sprintf(buf, "registration succeeded");
sendbyte = send(fd, buf, sizeof(buf), 0);
if (sendbyte < 0)
{
perror("send err\n");
return;
}
}
void server_login(int fd, sqlite3 *db)
{
char **ftp = NULL;
int sendbyte;
int n, l, k = 0;
char sql[128];
char *errmsg;
char buf[128] = "";
if (sqlite3_get_table(db, "select * from namepass;", &ftp, &n, &l, &errmsg))
{
fprintf(stderr, "select err:%s\n", errmsg);
return;
}
for (int i = 0; i < n + 1; i++)
{
for (int j = 0; j < l; j++)
{
if (!strcmp(pass.name, ftp[k++]))
{
if (!strcmp(pass.password, ftp[k]))
{
sprintf(buf, "login succeeded");
}
else
{
sprintf(buf, "password error");
}
sendbyte = send(fd, buf, sizeof(buf), 0);
if (sendbyte < 0)
{
perror("send err\n");
return;
}
return;
}
}
}
}
void query_(FILE *fp, int fd)
{
char buf[128];
int sendbyte;
while (strncmp(pass.operate, buf, strlen(pass.operate)))
{
fgets(buf, sizeof(buf), fp);
fflush(fp);
}
/* if(buf[strlen(bbuf)-1]=='\n')
buf[strlen(bbuf)-1]='\0';*/
sendbyte = send(fd, buf, sizeof(buf), 0);
if (sendbyte < 0)
{
perror("send err\n");
return;
}
}
②客户端代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "head.h"
#include <signal.h>
#include <time.h>
pass_t pass;
void show(int *choose);
void choose_client(int *choose,int sockfd);
void show_senior(int *choose);
void registration_();
void login_();
void query_(int *choose);
void history_();
int main(int argc, char const *argv[])
{
int recvbyte, sendbyte;
int i = 1;
time_t t;
struct tm *tm_now;
time(&t);
tm_now = localtime(&t);
char buf[128] = "";
FILE *fp = fopen("./history.txt", "a+");
if (fp == NULL)
{
perror("fopen err\n");
}
if (argc != 3)
{
printf("please input %s <ip> <port>\n", argv[0]);
return -1;
}
int sockfd;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
perror("socket err\n");
return -1;
}
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\n");
return -1;
}
int choose;
show(&choose);
choose_client(&choose,sockfd);
while (1)
{
sendbyte = send(sockfd, &pass, sizeof(pass), 0);
if (sendbyte < 0)
{
perror("send err\n");
return -1;
}
recvbyte = recv(sockfd, buf, sizeof(buf), 0);
if (recvbyte < 0)
{
perror("recv err\n");
return -1;
}
else if (recvbyte == 0)
{
return 0;
}
else
{
printf("%s", buf);
putchar(10);
if (!strcmp(buf, "User name already exists"))
{
registration_();
}
else if (!strcmp(buf, "registration succeeded"))
{
show(&choose);
choose_client(&choose,sockfd);
}
else if (!strcmp(buf, "login succeeded"))
{
break;
}
else if (!strcmp(buf, "password error"))
{
show(&choose);
}
}
}
pid_t pid = fork();
if (pid < 0)
{
perror("fork eer\n");
return -1;
}
else if (pid == 0)
{
while (1)
{
recvbyte = recv(sockfd, buf, sizeof(buf), 0);
if (recvbyte < 0)
{
perror("recv err\n");
return -1;
}
else if (recvbyte == 0)
{
printf("quit\n");
break;
}
else
{
printf("meaning:%s", buf);
}
}
}
else
{
while (1)
{
show_senior(&choose);
choose_client(&choose,sockfd);
fprintf(fp, "%d-%d-%d %d:%d:%d %s\n", tm_now->tm_year + 1900, tm_now->tm_mon + 1, tm_now->tm_mday, tm_now->tm_hour, tm_now->tm_min, tm_now->tm_sec,pass.operate);
fflush(fp);
sendbyte = send(sockfd, &pass, sizeof(pass), 0);
if (sendbyte < 0)
{
perror("send err\n");
return -1;
}
if (pass.type == quit)
{
kill(pid, SIGINT);
wait(NULL);
break;
}
}
}
close(sockfd);
fclose(fp);
return 0;
}
void registration_()
{
printf("input name:");
scanf("%s", pass.name);
getchar();
printf("input passworld:");
scanf("%s", pass.password);
getchar();
pass.type = registration;
return;
}
void show(int *choose)
{
printf("*********************************\n");
printf("*0.registration 1.login 2.quit*\n");
printf("*********************************\n");
printf("please choose:");
scanf("%d", choose);
getchar();
}
void choose_client(int *choose,int sockfd)
{
switch (*choose)
{
case registration:
registration_();
break;
case login:
login_();
break;
case quit:
pass.type=quit;
int sendbyte = send(sockfd, &pass, sizeof(pass), 0);
if (sendbyte < 0)
{
perror("send err\n");
return;
}
raise(SIGINT);
case query:
query_(choose);
break;
case history:
history_();
break;
default:
printf("choose err\n");
choose_client(choose,sockfd);
break;
}
}
void login_()
{
printf("input name:");
scanf("%s", pass.name);
getchar();
printf("input passworld:");
scanf("%s", pass.password);
getchar();
pass.type = login;
return;
}
void show_senior(int *choose)
{
printf("*********************************\n");
printf("*** 2.quit 3.query 4.history ***\n");
printf("*********************************\n");
printf("please input choose:");
scanf("%d", choose);
getchar();
}
void query_(int *choose)
{
printf("input individual word:");
scanf("%s", pass.operate);
getchar();
pass.type = query;
return;
}
void history_()
{
char buf[32];
FILE*fp=fopen("./history.txt","r");
if(fp==NULL)
{
perror("fopen err\n");
return;
}
while( fgets(buf,sizeof(buf),fp)!=NULL)
{
printf("%s",buf);
}
}
③头文件
#ifndef __HEAD_H__
#define __HEAD_H__
enum type_t
{
registration,
login,
quit,
query,
history,
};
//1.定一个消息结构体 :
typedef struct
{
int type;
char name[32];
char password[32];
char operate[128];
} pass_t;
#endif