网络编程在线英英词典之服务器代码框架搭建(二)

服务器流程图

在这里插入图片描述

服务端框架

#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个客户端都运行的情况下可以查看到相应的进程
在这里插入图片描述

关闭一个客户端后,查看有没有僵尸进程
通过下图,可以看到并没有产生僵尸进程
在这里插入图片描述
再把另一个客户端也关闭,也没有僵尸进程
在这里插入图片描述
到此,客户端和服务器的框架基本搭建完成,后面就是具体功能的实现
下一篇进行注册模块的实现

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值