嵌入式linux-sqlite3数据库,多进程并发服务器,在线词典

2023-05-16

文章目录

  • 1,简介:
  • 2,框架图
    • 2.1,客户端框架
    • 2.1,服务器端框架
  • 3,代码
    • 3.1,客户端代码
    • 3.2,服务器端代码

1,简介:

1,在线词典功能,分为客户端和服务器端
2,客户端有三个模块:注册、登录、查询(查询单词、查询历史记录)
3,服务器端要实现多并发服务器,这里采用多进程并发服务器:注册、登录、查询(查询单词、查询历史记录)
4,用户分为普通用户和管理员用户:管理员用户可以查询所有普通用户的历史记录,还可以看到词库中未定义的单词查询记录,普通用户只能查到自己的,词库中中有定义的记录
5,客户端和服务器通信只要通过一个信息结构体实现:

		typedef struct{
			int flag;  //1:usr or 2:root
			int type;
			char 			name[N];
			char data[256];  //password or word
		}MSG;

6,服务器端有单词词库
7,服务器端有两张数据库表格,一张用来存放用户信息,一张用来存放用户单词查询记录
8,多进程并发服务器要做僵尸进程处理

2,框架图

2.1,客户端框架

在这里插入图片描述

2.1,服务器端框架

在这里插入图片描述

3,代码

3.1,客户端代码

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h> 
#include <unistd.h>
#include <strings.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define N 20

#define R 1
#define L 2
#define Q 3
#define H 4
#define USR  1
#define ROOT 2

typedef struct{
	int flag; //1:usr or 2:root
	int type;
	char name[N];
	char data[256]; //password or word
}MSG;

int do_client(int sockfd);
int do_register(int connectfd,MSG *msg);
int do_login(int connectfd,MSG *msg);
int do_query(int connectfd,MSG *msg);
int do_history(int connectfd,MSG *msg);

int main(int argc, const char *argv[])
{
	int serverfd;
	struct sockaddr_in sin;

	if(argc != 3)
	{
		printf("usage: %s <server_ip> <server_port>\n",argv[0]);
		exit(0);
	}

	//创建流式套接字
	if((serverfd = socket(AF_INET,SOCK_STREAM,0)) < 0)
	{
		perror("socket");
		exit(-1);
	}

	//填充协议地址结构体
	bzero(&sin,sizeof(sin));
	sin.sin_family = AF_INET;
	sin.sin_port = htons(atoi(argv[2]));
	sin.sin_addr.s_addr = inet_addr(argv[1]); 

	//连接服务器
	if(connect(serverfd,(struct sockaddr *)&sin,sizeof(sin)) < 0)
	{
		perror("connect");
		goto _error1;
	}

	do_client(serverfd);

_error1:
	close(serverfd);
	return 0;
}

int do_client(int sockfd)
{
	MSG msg;
	bzero(&msg,sizeof(msg));

	msg.flag = -1;
	while(msg.flag < 0)
	{
		printf("Please choose permission [1:usr 2:root]");
		if(scanf("%d",&msg.flag) == 0)
			msg.flag = -1;
		while(getchar() != '\n');

		if(msg.flag != 1 && msg.flag != 2)
			msg.flag = -1;
	}

	/* 注册登录模块 */
	while(1)
	{
		msg.type = -1;
		while(msg.type < 0)
		{
			printf("********************************************\n");
			printf("*1:register      2:login     3:quite       *\n");
			printf("********************************************\n");
			printf("PLease choose:");

			if(scanf("%d",&msg.type) == 0)
				msg.type = -1;
			while(getchar() != '\n');
		}

		switch (msg.type)
		{
			case R:
			{
				do_register(sockfd,&msg);
				break;
			}
			case L:
			{
				if(do_login(sockfd,&msg) == 1)
				{
					goto _NEXT;
				}
				break;
			}
			case 3:
			{
				close(sockfd);
				printf("Exit the online dictionary program\n");
				exit(0);
				break;
			}
			default:
				printf("Error cmd.\n");
		}
	}
_NEXT:
	/* 查询模块 */
	while(1)
	{
		msg.type = -1;
		while(msg.type < 0)
		{
			printf("********************************************\n");
			printf("*1:query_word  2:history_record  3:quite   *\n");
			printf("********************************************\n");
			printf("Please choose:");

			if(scanf("%d",&msg.type) == 0)
				msg.type = -1;
			while(getchar() != '\n');
		}
		switch (msg.type)
		{
			case 1:
			{
				msg.type = Q;
				do_query(sockfd,&msg);
				break;
			}
			case 2:
			{
				msg.type = H;
				do_history(sockfd,&msg);
				break;
			}
			case 3:
			{
				close(sockfd);
				printf("Exit the online dictionary program\n");
				exit(0);
				break ;
			}
			default:
				printf("Error cmd.\n");
		}
	}
}

int do_register(int connectfd,MSG *msg)
{
	char str[20];
	int flag;
	
	while(1)
	{
		printf("PLease input name:");
		if(scanf("%s",msg->name)){};
		while(getchar() != '\n');

		flag = -1;
		while(flag < 0)
		{
			printf("PLease input password:");
			if(scanf("%s",str)){};
			while(getchar() != '\n');

			printf("Please confirm password:");
			if(scanf("%s",msg->data)){};
			while(getchar() != '\n');

			if(strncmp(msg->data,str,strlen(str)) == 0)
			{
				flag = 1;
			}
			else
			{
				printf("Entered passwords differ,Please re-enter them.\n");
			}
		}

		if(send(connectfd,msg,sizeof(MSG),0) < 0)
		{
			perror("do_register fail to send");
			return -1;
		}

		if(recv(connectfd,msg,sizeof(MSG),0) < 0)
		{
			perror("do_register fail to recv");
			return -1;
		}

		if(strncasecmp(msg->data,"ok",strlen("ok")) == 0)
		{
			printf("register success.\n");
			return 1;
			break;
		}
		else
		{
			printf("%s\n",msg->data);
			printf("re-register or cancel [1:re-register 2:cancel]");

			int tmp;
			if(scanf("%d",&tmp)){};
			while(getchar() != '\n');

			if(tmp == 2)
				break;
		}
	}
	return 0;
}
int do_login(int connectfd,MSG *msg)
{
	while(1)
	{
		printf("PLease input name:");
		if(scanf("%s",msg->name)){};
		while(getchar() != '\n');

		printf("PLease input password:");
		if(scanf("%s",msg->data)){};
		while(getchar() != '\n');

		if(send(connectfd,msg,sizeof(MSG),0) < 0)
		{
			perror("do_login fail to send");
			return -1;
		}

		if(recv(connectfd,msg,sizeof(MSG),0) < 0)
		{
			perror("do_login fail to recv");
			return -1;
		}

		if(strncasecmp(msg->data,"ok",strlen("ok")) == 0)
		{
			printf("login success.\n");
			return 1;
			break;
		}
		else
		{
			printf("%s\n",msg->data);
			printf("re-login or cancel [1:re-login 2:cancel]");

			int tmp;
			if(scanf("%d",&tmp)){};
			while(getchar() != '\n');

			if(tmp == 2)
				break;
		}
	}

	return 0;
}
int do_query(int connectfd,MSG *msg)
{
	while(1)
	{
		printf("Please input query_word('#' exit):");
		if(scanf("%s",msg->data)){};
		while(getchar() != '\n');

		/* 返回上级菜单 */
		if(strncmp(msg->data,"#",strlen("#")) == 0)
		{
			break;
		}

		/* 把含有有查询单词的消息结构体发送给服务器 */
		if(send(connectfd,msg,sizeof(MSG),0) < 0)
		{
			perror("do_query fail to send.");
			return -1;
		}

		/* 阻塞接受 */
		if(recv(connectfd,msg,sizeof(MSG),0) < 0)
		{
			perror("do_query fail to recv.");
			return -1;
		}

		/* 处理从服务器接受的信息 */
		printf("%s",msg->data);
	}

	return 0;
}
int do_history(int connectfd,MSG *msg)
{
	if(send(connectfd,msg,sizeof(MSG),0) < 0)
	{
		perror("do_history fail to send");
		return -1;
	}
	while(1)
	{
		if(recv(connectfd,msg,sizeof(MSG),0) < 0)
		{
			perror("do_history fail to recv");
			return -1;
		}
#if 1
		if(msg->data[0] == '\0')
		{
			break;
		}
#else
		/* 这种方法是错误的,strlen("\0")是错误的 */
		if(strncmp(msg->data,"\0",strlen("\0")) == 0)
		{
			break;
		}
#endif
		printf("%s\n",msg->data);
	}
	return 0;
}

3.2,服务器端代码

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h> 
#include <unistd.h>
#include <strings.h>
#include <string.h>
#include <netinet/in.h>
#include <sqlite3.h>
#include <signal.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <errno.h>
#include <time.h>

#define SERV_PORT 5001
#define BACKLOG 5

#define N 20

#define R 1
#define L 2
#define Q 3
#define H 4
#define USR  1
#define ROOT 2

#define DATABASE "table.db"



typedef struct{
	int flag; //1:usr or 2:root
	int type;
	char name[N];
	char data[256]; //password or word
}MSG;

typedef struct{//回调函数传参
	int fd;
	MSG msg;
}HIS_MSG;

int do_create_table(sqlite3 *db);//判断表格是否存在,不存在则创建
int do_client_handle(int newfd,struct sockaddr_in cin,sqlite3 *db);//子进程处理客户端词典请求操作
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 acceptfd,MSG msg,sqlite3 *db);
const char *get_date(char * date);//获取本地时间 
int do_searchworld(MSG *msg);//查询词典数据库文件dict.txt中的单词释义
int history_callback(void *his_msg, int f_num, char **f_value, char **f_name);//历史记录查询回调函数

int main(int argc, const char *argv[])
{
	sqlite3 *db;
	int socketfd;
	struct sockaddr_in sin;
	/* 数据库存在则打开,不存在则创建 */
	if(sqlite3_open(DATABASE,&db) != SQLITE_OK)
	{
		printf("%s\n",sqlite3_errmsg(db));
		return -1;
	}
	else
	{
		printf("open database:%s success.\n",DATABASE);
	}
	
	/* 表格不存在则创建数据库表格 */
	if(do_create_table(db) < 0)
	{
		goto _error1;//创建数据库表格失败
	}

	/* 创建流式套接字 */
	if((socketfd = socket(AF_INET,SOCK_STREAM,0)) < 0)
	{
		perror("socket");
		goto _error1;
	}
	/* 允许绑定地址快速重用 */ 
	int b_reuse = 1;
	setsockopt(socketfd,SOL_SOCKET,SO_REUSEADDR,&b_reuse,sizeof(int));

	bzero(&sin,sizeof(sin));
	sin.sin_family = AF_INET;
	sin.sin_port = htons(SERV_PORT);
	sin.sin_addr.s_addr = htonl(INADDR_ANY);// 让服务器可以绑定在任意的IP上

	/* 绑定 */
	if(bind(socketfd,(struct sockaddr *)&sin,sizeof(sin)) < 0)
	{
		perror("bind");
		goto _error2;
	}

	/* 将套接字设置为监听模式 */
	if(listen(socketfd,BACKLOG) < 0)
	{
		perror("listen");
		goto _error2;
	}

	signal(SIGCHLD,SIG_IGN) ; //处理僵尸进程

	pid_t pid;
	int status;
	int newfd;
	struct sockaddr_in cin;
	socklen_t cin_add_len = sizeof(cin);
	bzero(&cin,sizeof(cin));

	while(1)
	{
	
		/* 阻塞等待客户端连接 */
		if((newfd = accept(socketfd,(struct sockaddr *)&cin,&cin_add_len)) < 0)
		{
			perror("acept");
			goto _error2;
		}

		/* 如果连接从成功,创建子进程 */
		if((pid = fork()) < 0)
		{
			perror("fork");
			goto _error3;
		}
		else if(pid == 0)//子进程
		{
			close(socketfd);
			do_client_handle(newfd,cin,db);//子进程处理客户端词典请求操作
		}
		else //父进程
		{
			close(newfd);
			waitpid(-1, &status, WNOHANG);//以非阻塞方式回收当前进程的任意一个子进程
		}
	}
_error3:
	close(newfd);
_error2:
	close(socketfd);
_error1:
	sqlite3_close(db);
	return 0;
}

int do_create_table(sqlite3 *db)
{
	char sql[128];
	char **resultp;
	int nrow;
	int ncolumn;
	char *errmsg;

	/* 判断表格usr是否存在,不存在则创建 */
	sprintf(sql,"select * from sqlite_master where type='table' and name='usr';");
	sqlite3_get_table(db,sql,&resultp,&nrow,&ncolumn,&errmsg);
	if(nrow == 0)
	{
		sprintf(sql,"create table %s(name text primary key,permission integer,password text);","usr");
		if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK)
		{
			printf("create table:%s %s\n","usr",errmsg);
			return -1;
		}
		else
		{
			printf("create table:%s success.\n","usr");
		}
	}
	else
	{
		printf("table:%s is OK.\n","usr");
	}

	/* 判断表格record是否存在,不存在则创建 */
	sprintf(sql,"select * from sqlite_master where type='table' and name='record';");
	sqlite3_get_table(db,sql,&resultp,&nrow,&ncolumn,&errmsg);
	if(nrow == 0)
	{
		sprintf(sql,"create table %s(name text,date text,word text,is_undefine Integer);","record");
		if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK)
		{
			printf("create table:%s %s\n","record",errmsg);
			return -1;
		}
		else
		{
			printf("create table:%s success.\n","record");
		}
	}
	else
	{
		printf("table:%s is OK.\n","record");
	}
	return 0;
}

int do_client_handle(int newfd,struct sockaddr_in cin,sqlite3 *db)//子进程处理客户端词典请求操作
{
	MSG msg;
	int ret = -1;
	char ipv4_addr[16];

	inet_ntop(AF_INET,(void *)&cin.sin_addr.s_addr,ipv4_addr,sizeof(cin));
	printf("client(ip:%s port:%d) is connected.\n",ipv4_addr,ntohs(cin.sin_port));

	while(1)
	{
		bzero(&msg,sizeof(msg));
		do{
			ret = recv(newfd,&msg,sizeof(msg),0);
		}while(ret < 0 && errno == EINTR);//阻塞读取
		if(ret < 0)
		{
			perror("recv");
			close(newfd);
			return -1;
		}
		if(ret == 0) //客户端已关闭
		{
			goto _exithandle;
			break;
		}

		switch (msg.type)
		{
			case R:
				do_register(newfd,msg,db);
				break;
			case L:
				do_login(newfd,msg,db);
				break;
			case Q:
				do_query(newfd,msg,db);
				break;
			case H:
				do_history(newfd,msg,db);
				break;
			default:
				printf("Invalid data msg.\n");
		}
	}
_exithandle:
	printf("client(ip:%s port:%d) exit.\n",ipv4_addr,ntohs(cin.sin_port));
	close(newfd);
	exit(0);
	return 0;
}

int	do_register(int acceptfd,MSG msg,sqlite3 *db)
{
	char sql[128];
	char *errmsg;

	/* 将用户信息插入数据库表格usr(名字(主键),权限,密码) */
	sprintf(sql,"insert into usr values('%s',%d,'%s');",msg.name,msg.flag,msg.data);

	if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK)
	{
		printf("do_register %s\n",errmsg);
		strcpy(msg.data,"the name already exit.");//插入失败说明用户名已存在
	}
	else
	{
		printf("insert usr success.\n");
		strcpy(msg.data,"OK");
	}

	if(send(acceptfd,&msg,sizeof(MSG),0) < 0)
	{
		perror("do_register fail to send");
		return -1;
	}
	return 0;
}
int do_login(int acceptfd,MSG msg,sqlite3 *db)
{
	char sql[128];
	char *errmsg;
	char **resultp;
	int nrow;
	int ncolumn;

	sprintf(sql,"select * from  usr where name='%s';",msg.name);

	if(sqlite3_get_table(db,sql,&resultp,&nrow,&ncolumn,&errmsg) < 0)
	{
		printf("do_register %s",errmsg);
		return -1;
	}

	if(nrow == 0)
	{
		printf("login name:%s does not exit.\n",msg.name);
		strcpy(msg.data,"the name does not exit.");
	}
	else if(nrow == 1)//用户存在
	{
		if(msg.flag != atoi(resultp[ncolumn+1]))
		{
			printf("login usr permissions not match.\n");
			strcpy(msg.data,"usr permission not match.");
		}
		else if(msg.flag == atoi(resultp[ncolumn+1]))//用户和权限匹配
		{
			if(strncmp(msg.data,resultp[ncolumn+2],strlen(msg.data)) != 0)
			{
				printf("login password is wrony.\n");
				strcpy(msg.data,"password is wrong.");
			}
			else//登录成功
			{
				printf("login success.\n");
				strcpy(msg.data,"OK");
			}
		}
	}
	if(send(acceptfd,&msg,sizeof(msg),0) < 0)
	{
		perror("do_login fail to send");
		return -1;
	}


	return 0;
}
int	do_query(int acceptfd,MSG msg,sqlite3 *db)
{
	char date[20];
	int found;
	char word[20];//保存要查询的单词
	int is_undefine;
	char sql[128];
	char *errmsg;

	/* 获取本地时间 */
	get_date(date);

	/* 查询词典数据库文件dict.txt */
	strcpy(word,msg.data);
	found = (do_searchworld(&msg));

	if(found == 1)
	{
		is_undefine = 0;
	}
	if(found == 0)
	{
		is_undefine = 1;
	}

	/* 将查询信息发送给客户端:释义|The meaning of the word could not be found|错误信息 */
	if(send(acceptfd,&msg,sizeof(MSG),0) < 0)
	{
		perror("do_query fail to send.");
		return -1;
	}

	/* 一个单词查询完毕,服务端打印提示信息 */
	printf("Word:%s query finished.\n",word);


	/* 将查询信息插入数据库表格record(名字,日期时间,单词,是否未定义) */
	sprintf(sql,"insert into record values('%s','%s','%s',%d);",msg.name,date,word,is_undefine);

	if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK)
	{
		printf("do_query %s\n",errmsg);
		return -1;
	}

	return 0;
}

int	do_history(int acceptfd,MSG msg,sqlite3 *db)
{
	HIS_MSG his_msg;
	char sql[128];
	char *errmsg;

	/* 装填回调函数传参结构体 */
	his_msg.fd = acceptfd;
	his_msg.msg = msg;

	/* 装填sql语句 */
	if(msg.flag == USR)
	{
		sprintf(sql,"select * from record where name='%s' and is_undefine=%d;",msg.name,0);
	}
	if(msg.flag == ROOT)
	{
		sprintf(sql,"select * from record;");
	}

	/* 查询历史记录,执行回调函数 */
	if(sqlite3_exec(db,sql,history_callback,(void *)&his_msg,&errmsg) != SQLITE_OK)
	{
		printf("do_history %s\n",errmsg);
		return -1;
	}
	else
	{
		printf("Query history record successful.\n");
		/* 历史记录查询完了,给客户端发送查询完毕标志“\0” */
		strcpy(msg.data,"\0");
		if(send(acceptfd,&msg,sizeof(MSG),0) < 0)
		{
			perror("do_history fail to send");
			return -1;
		}
		return 1;
	}
	return 0;
}

const char *get_date(char * date)//获取本地时间 
{
	time_t t;
	struct tm tp;

	time(&t);

	tp = *localtime(&t);

	sprintf(date,"%04d-%02d-%02d %02d:%02d:%02d",tp.tm_year+1900,tp.tm_mon+1,tp.tm_mday,tp.tm_hour,tp.tm_min,tp.tm_sec);

	return date;
}

int do_searchworld(MSG *msg)//查询词典数据库文件dict.txt中的单词释义
{
	FILE *fp;
	int len;
	char str[512];
	int result;
	char *p;

	/* 打印要查询的单词信息 */
	len = strlen(msg->data);
	printf("%s , %d\n",msg->data,len);

	if((fp = fopen("dict.txt","r")) == NULL)
	{
		perror("do_searchworld fail to fopen");
		strcpy(msg->data,"can't open online dictionary database dict.txt.\n");
		return -1;
	}

	/* 从流中读取一行 */
	while(fgets(str,511,fp) != NULL)
	{
		result = strncmp(str,msg->data,len);

		if(result < 0)
		{
			continue ;
		}
		if(result > 0 || str[len] != ' ')
		{
			strcpy(msg->data,"The meaning of the word could not be found.\n");
			break;
		}

		/* 找到了查询的单词 */
		p = str +len;
		while(*p == ' ')//去掉单词释义前的空格
		{
			p++;
		}
		strcpy(msg->data,p);
		fclose(fp);
		return 1;
	}

	fclose(fp);
	return 0;
}

int history_callback(void *his_msg, int f_num, char **f_value, char **f_name)
{
	HIS_MSG *h_msg = (HIS_MSG *)his_msg;
	/*create table %s(name text,date text,word text,is_undefine Integer);","record");*/
	if(h_msg->msg.flag == USR)
	{
		sprintf(h_msg->msg.data,"%s    %s",f_value[1],f_value[2]);
		printf("%s\n",h_msg->msg.data);
	}
	if(h_msg->msg.flag == ROOT)
	{
		sprintf(h_msg->msg.data,"%-20s%s    %-15s%s",f_value[0],f_value[1],f_value[2],f_value[3]);
	}

	if(send(h_msg->fd,&h_msg->msg,sizeof(MSG),0) < 0)
	{
		perror("history_callback fail to send");
		return -1;
	}

	return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

嵌入式linux-sqlite3数据库,多进程并发服务器,在线词典 的相关文章

  • arp欺骗

    ARP工作的过程 原理及现象 ARP全称是地址解析协议 xff08 address resolution potocol xff09 xff0c 是在仅仅知道主机的IP地址时确定其物理的地址的一种协议 ARP协议的工作过程 场景 xff1a
  • LeetCode中stdout结果是正确的,输出没有

    没有返回值 xff0c 加一行return
  • gstreamer学习(一) gstreamer-rtsp-server环境安装

    gstreamer rtsp server环境安装 Linux环境下 两种方式 xff1a 第一种方式 xff0c 通过官网安装 xff08 如果是Linux环境 xff0c 可以直接通过软件包工具进行安装 xff09 xff0c 点击进入
  • 用C++打开指定网址

    用C 43 43 打开指定网址原理 system 命令 就像这样 xff1a span class token macro property span class token directive hash span span class t
  • 项目遇到的各种异常抛出及解决方法

    项目遇到的各种异常抛出及解决方法 xff1a 1 java lang NumberFormatException xff1a 类型格式异常 第一次遇到的异常抛出原因及解决方法 xff1a 项目运行没有问题 xff0c 各种接口能正常查询出数
  • 【STC8学习笔记】STC8A8K64S4A12精准延时函数设置

    在设置单片机精准的延时函数的时候 xff0c 给大家一个方法 xff0c STC ISP有一个延时函数计算器 xff0c 可以计算出想要的延时 我的例程也是基于这个软件生成的 xff0c 我生成一个1ms和1us出来 xff0c 剩下的我再
  • vc版本与vs版本对应关系

    vc版本与vs版本对应关系 最近在整理之前代码 xff0c 用cmake编译一直报错 xff0c 忘记了opencv3 1 0不支持vs2019 xff0c 所以在这里总结下vc版本与vs版本对应关系 VC版本号 VS对应版本 vc6 VC
  • cmake编译依赖opencv的c++库

    前面一篇主要讲了c 43 43 项目怎么在本地配置opencv过程 xff0c 这种方式缺点就是只能在开发着本地环境编译 xff0c 换台电脑就会出现环境配置问题 接下来主要讲解 xff0c 使用cmake编译 xff0c 生成一个依赖op
  • c++ stl 迭代器iterators(traits编程技法)

    文章目录 1 1 迭代器设计思维 stl关键所在1 2 迭代器是一种smart pointer1 3 迭代器相应型别 xff08 associated types xff09 1 4 traits编程技法 stl源代码门匙1 4 1 val
  • 如何用算法把一个十进制数转为十六进制数-C语言基础

    这一篇文章要探讨的是 如何用算法实现十进制转十六进制 并不涉及什么特别的知识点 属于C语言基础篇 在翻找素材的时候 xff0c 发现一篇以前写的挺有意思的代码 xff0c 这篇代码里面涉及的知识点没有什么好讲的 xff0c 也没有什么特别的
  • 关于 Qt使用QJsonObject解析失败的问题。

    1 问题 在QJsonObject转 toInt toLongLong 等类型时 xff0c 转换失败 但是转toString xff08 xff09 没有任何问题 列如 xff1a 解决方法 xff1a 这样 xff0c 就可以结局问题
  • char 和 string 的相互转换

    一个char字符转为string span class token keyword char span ch span class token operator 61 span span class token char 39 A 39 s
  • C++STL标准库学习总结/索引/学习建议

    前言 xff1a 如果刚刚开始学习STL标准库 xff0c 不知道从哪里入手学习的话 xff0c 建议去中国大学mooc平台 xff0c 先学习北京大学郭炜老师的 程序设计与算法 xff08 一 xff09 C语言程序设计 xff08 ht
  • Python 调用API接口方式,通过http.client调用api接口,远程调用flask接口方式

    一 创建接口 xff08 如果调用别人的接口 xff0c 跳过此条 xff09 如果没有api xff0c 首先自己写一个接口玩一下 xff1a 必备知识 xff1a 一个项目最基本的文件 xff0c 接口run py文件 config文件
  • git tag和branch的区别

    tag 和branch的区别 Git tag是一系列commit的中的一个点 xff0c 只能查看 xff0c 不能移动 branch是一系列串联的commit的线 git tag的用法 我们常常在代码封板时 使用git 创建一个tag 这
  • 结构体对齐计算(超详细讲解,一看就会)

    想要计算结构体大小 xff0c 咱就先要清楚结构体内存对齐的规则 xff1a 1 结构体的第一个成员直接对齐到相对于结构体变量起始位置为0处偏移 2 从第二个成员开始 xff0c 要对齐到某个 对齐数 的整数倍的偏移处 3 结构体的总大小
  • RTK差分编码

    一 概念 DCB xff08 Differential Code Bias 差分码偏差 xff09 是全球卫星导航系统 xff08 GNSS xff09 中 xff0c 通过不同信号得到的观测值之间存在的系统性偏差 DCB是由卫星和接收机硬
  • 详解JAVA的事件监听机制和观察者设计模式

    一 事件监听机制的三要素 事件源 事件监听器 xff0c 事件对象 监听器一般是JAVA接口 xff0c 用来约定可以执行的操作 二 事件监听机制简要说明 事件源注册一个或者多个事件监听器 xff0c 事件源对象状态发生变化或者被操作时 x
  • Nginx控制IP(段)的访问策略配置

    Nginx engine x 是一个高性能的HTTP和反向代理web服务器 xff0c 同时也提供了IMAP POP3 SMTP服务 有着负载均衡 动静分离等强大的功能 xff0c 而且还有众多三方插件来满足应用要求 这里重点介绍nginx
  • 敏捷开发-互联网时代的软件开发方式

    一 什么是敏捷开发 敏捷开发简单的描述为 xff1a 是一种应对需求快速变化的软件开发方式 敏捷开发的核心思想就是小步快跑 不断迭代 xff0c 在一次次的迭代升级中完成 小目标 最终完成那个 大目标 正因为敏捷开发的这种不断迭代升级的开发

随机推荐