服务器流程图
服务端框架
#include "net.h"
#define NAME_LEN 32
#define MSGTYPE_R 11 //register
#define MSGTYPE_L 22 //login
#define MSGTYPE_Q 33 //query
#define MSGTYPE_H 44 //history
#define DATABASE "my.db"
//通信双方的结构体
typedef struct{
int type;
char name[NAME_LEN];
char data[256];
}MSG_T;
int do_register(int sockfd, MSG_T *msg, sqlite3 *db);//声明注册函数
int do_login(int sockfd, MSG_T *msg, sqlite3 *db); //声明登录函数
int do_searchword(MSG_T *msg, char *word); //声明查找单词函数
int do_query(int sockfd, MSG_T *msg, sqlite3 *db); //声明查询函数
int history_callback(void* arg, int colCount, char** colValue, char** colName);//声明回调历史查询函数
int do_history(int sockfd, MSG_T *msg, sqlite3 *db); //声明历史查询函数
int do_client(int acceptfd, sqlite3 *db); //声明处理客户端信息函数
void get_date(char *data); //声明时间获取函数
int main(void)
{
int sockfd, acceptfd;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
socklen_t addrlen = sizeof(client_addr);
char ipv4_addr[16];//存放点分格式的ip地址
sqlite3 *db = NULL;
char *errmsg = NULL;
char sql[128] = {0};
pid_t pid;
/**************************数据库操作*********************************/
if(sqlite3_open(DATABASE, &db) != SQLITE_OK){//打开数据库
printf("%s\n", sqlite3_errmsg(db));
return -1;
}
printf("sqlite3 open %s success.\n",DATABASE);
sprintf(sql, "create table if not exists user(name text primary key, passwd text);");
if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK){
printf("%s\n", errmsg);
return -1;
}
memset(sql, 0, sizeof(sql));
sprintf(sql, "create table if not exists record (name text, date text, word text);");
if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK){//创建记录表
printf("%s\n", errmsg);
return -1;
}
/********************tcp server 操作*******************************/
//创建套接字
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0){
perror("socket");
exit(1);
}
int b_reuse = 1;
setsockopt(sockfd ,SOL_SOCKET, SO_REUSEADDR, &b_reuse, sizeof(int));
//绑定服务器
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERV_PORT);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) <0){//服务器绑定函数
perror("bind");
exit(1);
}
//将套接字设置为监听模式
if(listen(sockfd, BACKLOG) < 0){
perror("listen");
exit(1);
}
printf("server staring ... ok!\n");
//处理僵尸进程
signal(SIGCHLD, SIG_IGN);
//等待客户端连接请求
while(1){
pid_t pid = -1;
if((acceptfd = accept(sockfd, (struct sockaddr *)&client_addr, &addrlen)) < 0){//接收客户端的连接请求
perror("accept");
break;
}
//创建一个子进程用于处理已建立连接的客户的交互数据
if((pid = fork()) < 0){
perror("fork");
return -1;
}
if(pid == 0){
close(sockfd);
do_client(acceptfd, db);
}else{
close(acceptfd);
}
}
return 0;
}
int do_client(int acceptfd, sqlite3 *db){
MSG_T recv_msg;
//默认是阻塞式接收
//如果客户端断开连接 或是 主动发送close关闭连接,recv会返回0
//recv的返回值: <0 出错; =0 连接关闭; >0接收到数据大小
while(recv(acceptfd, &recv_msg, sizeof(MSG_T), 0) > 0){//接收客户端发送来的消息
switch(recv_msg.type){
case MSGTYPE_R:
do_register(acceptfd, &recv_msg, db);
break;
case MSGTYPE_L:
do_login(acceptfd, &recv_msg, db);
break;
case MSGTYPE_Q:
do_query(acceptfd, &recv_msg, db);
break;
case MSGTYPE_H:
do_history(acceptfd, &recv_msg, db);
break;
default:
printf("Invalid data msg.\n");
}
}
printf("client exit.\n");
close(acceptfd);
exit(0);
}
//注册
int do_register(int sockfd, MSG_T *msg, sqlite3 *db){
printf("do_register");
return 1;
}
//登录
int do_login(int sockfd, MSG_T *msg, sqlite3 *db){
printf("do_login");
return 1;
}
//根据单词从dirt.txt文本中查找对应的注释信息
//返回值: -1 文件打开失败; 0 单词未找到; 1 查找成功
int do_searchword(MSG_T *msg, char *word){
printf("do_searchword");
return 0;//文件对比完,单词未找到
}
int do_query(int sockfd, MSG_T *msg, sqlite3 *db){
printf("do_query");
return 0;
}
//得到查询结果,并且需要将历史记录发送给客户端
int history_callback(void* arg, int colCount, char** colValue, char** colName){
return 0;
}
int do_history(int sockfd, MSG_T *msg, sqlite3 *db){
printf("do_history");
return 0;
}
//获取系统时间
void get_date(char *data){
}
服务器框架搭建完后,可以进行一个初步的测试
先创建一个数据库
创建usr表和record表
创建一个my.db数据库sqlite3 my.db
创建用户表create table usr(name text primary key, pass text);
创建历史记录表create table record(name text, date text, word text);
然后进行一个客户端并发连接服务器的验证(目前还只能进行客户端的连接操作,其他功能还未实现)
成功打开了2个客户端,说明前面的框架搭建没有问题
通过ps axj
命令可以查看关闭客户端后是否产生僵尸进程
在1个服务器和2个客户端都运行的情况下可以查看到相应的进程
关闭一个客户端后,查看有没有僵尸进程
通过下图,可以看到并没有产生僵尸进程
再把另一个客户端也关闭,也没有僵尸进程
到此,客户端和服务器的框架基本搭建完成,后面就是具体功能的实现
下一篇进行注册模块的实现