以下是利用epoll机制及sqlite3实现的一个简陋的电子词典, 功能包括用户注册登录、查词、历史记录查询及退出, 若有不足之处还望各位指点:
1. 思路
- 利用epoll机制将监听套接字挂在epoll树上监听来自不同客户端的请求, 一旦接收到请求就将连接套接字加入树中, 根据请求的类型来进行注册, 登录, 翻译, 查询历史记录, 登出的操作。
- 使用一个结构体包(pack)存放TCP传输过程中的信息, 包中的成员name在传输的过程中不能更改, 便于客户端与服务端识别对方的姓名及保存至数据库, 也方便每次登录注册翻译时查询。
- 服务端的登录, 翻译, 查询功能可以集成在一个函数中, 把数据库和接收请求类型作为函数参数, 利用switch判断请求类型, 根据不同类型来更改
char *sql
的操作, 这样就能避免重复定义
2. 成品图
3. 开发过程中产生的错误
- 在使用sqlite3_get_table执行查询单词翻译操作时出现行列返回值为0
- 当用户执行退出操作时会产生段错误
4. 错误的解决
- 在客户端传出单词信息时把从fgets中得到的单词进行尾部去换行符的操作,
buf[strlen(buf - 1)] = '\0'
, 这样就能解决行列返回值为0的问题。 - 可能是我定义的解压
(pack)
的函数有问题, 导致客户端服务端双向通信时包中的name
字段丢失导致服务端无法识别到来自客户端关闭的请求, 当改成memcpy来直接拷贝内容时就避免了name
丢失的问题。
5. 不足之处
- 该项目的语句编写不够美观而且很多逻辑上的地方都没有优化好, 功能上用户会查询到所有注册人员的翻译信息而不能查询用户自己的翻译信息, 可以在历史记录表里面创建一个用户姓名信息来对登录用户的每次翻译进行一个记录。 而且没有进行端口复用的处理, 可以利用
setsockopt
设置一下套接字属性使程序能端口复用。
6. 源码
-
head.h
/*信息包*/ typedef struct pack { int type; char name[50]; char passwd[50]; // 存储密码或其他重要信息 }pack; /******************************************客户端功能************************************************/ /*用户注册(客户端)*/ extern bool c_reg(int fd, int option, pack* msg, int msg_size, char *buf, int buf_size); /*用户登录(客户端)*/ extern bool c_login(int *key, int fd, int option, pack* msg, int msg_size, char *buf, int buf_size); /*用户翻译(客户端)*/ extern bool c_trans(int fd, int option, pack* msg, int msg_size, char *buf, int buf_size); /*用户获取历史记录(客户端)*/ extern bool c_hist(int fd, int option, pack* msg, int msg_size, char *buf, int buf_size); /******************************************服务端功能************************************************/ /*用户注册(服务端)*/ extern bool s_reg(int fd, sqlite3* db, pack* recv_info, int info_size); /*用户在线功能(服务端): 含登录确认翻译与翻译功能*/ extern bool s_online(sqlite3* db, int type, int fd, pack* recv_info, int info_size);
-
fun.c
#include "head.h" /*客户端功能*/ /*用户注册(客户端)*/ extern bool c_reg(int fd, int option, pack *msg, int msg_size, char *buf, int buf_size) { printf("Enter name: "); fgets(msg->name, sizeof(msg->name), stdin); printf("Enter passwd: "); fgets(msg->passwd, sizeof(msg->passwd), stdin); msg->type = option; memcpy(buf, (char *)msg, msg_size); send(fd, buf, buf_size, 0); // 将用户注册信息传送给服务端 memset(buf, 0, buf_size); recv(fd, buf, buf_size, 0); memcpy((char *)msg, buf, buf_size); if (msg->type == OK) { printf("Register ok\n"); return true; } else { printf("Register error\n"); } } /*用户登录(客户端)*/ extern bool c_login(int *key, int fd, int option, pack *msg, int msg_size, char *buf, int buf_size) { int count = 0; do { printf("Enter name: "); fgets(msg->name, sizeof(msg->name), stdin); printf("Enter passwd: "); fgets(msg->passwd, sizeof(msg->passwd), stdin); msg->type = option; memcpy(buf, (char *)msg, msg_size); send(fd, buf, buf_size, 0); memset(buf, 0, buf_size); /*接受登录请求结果*/ recv(fd, buf, buf_size, 0); memcpy((char *)msg, buf, buf_size); if (msg->type == 1)