嵌入式学习项目实战 --- 在线词典

2023-05-16

目录

一、前言

二、项目功能

三、程序流程

1、客户端

2、服务器

四、代码实现

1、客户端代码

2、服务器代码

3、Makefile


一、前言

本文学习自【华清远见】的一个开源嵌入式项目在线词典综合实战,涵盖了网络编程、文件I/O、并发程序设计、数据库开发等多方面知识,对想要学习嵌入式开发、锻炼提升编程能力的小伙伴来说是一个非常不错的实战项目。接下来咋们先梳理下项目要实现的具体功能,设计程序流程,最后再开始具体的编程实现

二、项目功能

1、需要基于tcp实现一个供用户操作的客户端;在客户端中有两级菜单,一级菜单中用户可进行注册、登录、退出操作;登录后进入二级菜单,二级菜单中可进行单词查询、历史记录查询、退出操作

2、需要基于tcp实现一个多并发的服务器,用于响应客户端的注册、登录、单词查询、历史记录查询请求,同时需要将用户注册的用户信息(用户名、密码)、单词查询记录(用户名、查询时间、查询单词)分别保存到sqlite3数据库的用户表和记录表中。具体如下:

  • 客服端登录时,在数据库的用户表中匹配注册的用户名和密码,返回登录结果;
  • 客户端查询单词时,在词典的txt文件中查找对应的单词,如若找到则返回对应的注释信息;
  • 客户端查询历史记录时,从数据库的记录表中,将当前登录用户的查询记录(用户名、查询时间、查询单词)信息返回给客户端

3、客户端与服务器之间的交互过程如下:

三、程序流程

1、客户端

 

2、服务器

 

四、代码实现

1、客户端代码

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


#define NAME_LEN 32

#define MSGTYPE_R 11 //user - register
#define MSGTYPE_L 22 //user - login
#define MSGTYPE_Q 33 //user - query
#define MSGTYPE_H 44 //user - history

// 通信双方的信息结构体
typedef struct {
	int type;
	char name[NAME_LEN];
	char data[256];
}MSG_T;

/*
struct sockaddr
{
    uint8_t        sa_len;
    sa_family_t    sa_family;
    char           sa_data[14];
};
/* members are in network byte order */
/*
struct sockaddr_in
{
    uint8_t        sin_len;
    sa_family_t    sin_family;
    in_port_t      sin_port;
    struct in_addr sin_addr;
#define SIN_ZERO_LEN 8
    char            sin_zero[SIN_ZERO_LEN];
};

struct in_addr
{
    in_addr_t s_addr;
};
*/

// 注册
int do_register(int sockfd, MSG_T *msg)
{
	printf("register ... \n");
	
	memset(msg, 0, sizeof(MSG_T));
	msg->type = MSGTYPE_R;
	printf("input name:"); scanf("%s", msg->name); getchar();
	printf("input passwd:"); scanf("%s", msg->data); getchar();
	
	if (send(sockfd, msg, sizeof(MSG_T), 0) < 0)
	{
		printf("fail to send register msg.\n");
		return -1;
	}
	
	if (recv(sockfd, msg, sizeof(MSG_T), 0) < 0)
	{
		printf("fail to register.\n");
		return -1;
	}
	
	//ok !  或者 user already exist.
	printf("%s\n", msg->data);
	
	return 1;
}

// 登录, 必服务器返回 "OK" 才表示登录成功
// 返回值:1 成功,-1 失败,0 其他
int do_login(int sockfd, MSG_T *msg)
{
	printf("login ...\n");
	
	memset(msg, 0, sizeof(MSG_T));
	msg->type = MSGTYPE_L;
	printf("input name:"); scanf("%s", msg->name); getchar();
	printf("input passwd:"); scanf("%s", msg->data); getchar();
	
	if (send(sockfd, msg, sizeof(MSG_T), 0) < 0)
	{
		printf("fail to send register msg.\n");
		return -1;
	}
	
	if (recv(sockfd, msg, sizeof(MSG_T), 0) < 0)
	{
		printf("fail to login.\n");
		return -1;
	}
	
	//登录成功
	if (strncmp(msg->data, "OK", 3) == 0)
	{
		printf("login ok! \n");
		return 1;
	}
	else
	{
		printf("%s\n", msg->data);
	}
	
	return 0;
}

// 单词查询
int do_query(int sockfd, MSG_T *msg)
{
	printf("query ...\n");
	
	msg->type = MSGTYPE_Q;
	while(1)
	{
		printf("input word:"); scanf("%s", msg->data); getchar();
		
		// 输入是"#"表示退出本次查询
		if (strncmp(msg->data, "#", 1) == 0)
			break;
		
		//将要查询的单词发送给服务器
		if (send(sockfd, msg, sizeof(MSG_T), 0) < 0)
		{
			printf("fail to send.\n");
			return -1;
		}
		
		//等待服务器,传递回来的单次的注释信息
		if (recv(sockfd, msg, sizeof(MSG_T), 0) < 0)
		{
			printf("fail to recv.\n");
			return -1;
		}
		printf("%s\n", msg->data);
	}
	
	return 1;
}

// 历史记录查询
int do_history(int sockfd, MSG_T *msg)
{
	printf("history ...\n");
	
	msg->type = MSGTYPE_H;

	//将消息发送给服务器
	if (send(sockfd, msg, sizeof(MSG_T), 0) < 0)
	{
		printf("fail to send.\n");
		return -1;
	}
		
	while(1)
	{
		//等待服务器,传递回来的单次的注释信息
		if (recv(sockfd, msg, sizeof(MSG_T), 0) < 0)
		{
			printf("fail to recv.\n");
			return -1;
		}

		if (msg->data[0] == '\0')
		    break;

		//输出历史记录信息    
		printf("%s\n", msg->data);
	}
	
	return 1;

}

// ./client 192.168.0.107 10000
// 知识点:
//	1、在一个套接字被创建时,其默认是工作在阻塞模式下,即所有socket相关的数据发送、接收函数都会阻塞,
//	直到数据发送、接收成功,函数才继续执行
//	2、可以通过fcntl来设置成阻塞或非阻塞模式。https://blog.csdn.net/haoyu_linux/article/details/44306993
int main(int argc, const char *argv[])
{
	int sockfd;
	struct sockaddr_in server_addr;
	int input_nbr;
	MSG_T send_msg;
	
	if (argc != 3)
	{
		printf("usage: %s serverip port\n", argv[0]);
		return -1;
	}
	
	// 申请socket
	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
	{
		perror("fail to socket\n");
		return -1;
	}	
	
	server_addr.sin_family  = AF_INET;
	server_addr.sin_addr.s_addr = inet_addr(argv[1]);
	server_addr.sin_port = htons(atoi(argv[2]));
    bzero(&(server_addr.sin_zero), sizeof(server_addr.sin_zero));
    
    /*连接到服务器*/
    if (connect(sockfd, (struct sockaddr*)&server_addr, sizeof(struct sockaddr)) < 0)
	{
		perror("fail to connect\n");
		return -1;
	}
	
	while (1)
	{
		printf("***********************************************\n");
		printf("*******  1.register   2.login   3.quit  *******\n");
		printf("***********************************************\n");
		printf("please choose:");
		
		scanf("%d", &input_nbr);
		getchar();//回收垃圾字符
		
		// 一级菜单
		switch (input_nbr)
		{
			case 1:
				do_register(sockfd, &send_msg);
				break;
				
			case 2:
				if (do_login(sockfd, &send_msg) == 1)
				{
					goto _login;
				}
				break;
				
			case 3:
				close(sockfd);
				exit(0);
				break;
			
			default:
				printf("Invalid data cmd. \n");
				break;
		}
	}
	
	//二级菜单,登录后进行单词查询
_login:
	while(1)
	{
		printf("***********************************************\n");
		printf("*****1.query_word  2.history_record  3.quit****\n");
		printf("***********************************************\n");
		printf("please choose:");
		
		input_nbr = 0;
		scanf("%d", &input_nbr);
		getchar();//回收垃圾字符
		
		
		switch (input_nbr)
		{
			case 1:
				do_query(sockfd, &send_msg);
				break;
				
			case 2:
				do_history(sockfd, &send_msg);
				break;
				
			case 3:
				close(sockfd);
				exit(0);
				break;
			
			default:
				printf("Invalid data cmd. \n");
				break;
		}
	}
	
	return 0;
}

2、服务器代码

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

#define NAME_LEN 32

#define MSGTYPE_R 11 //user - register
#define MSGTYPE_L 22 //user - login
#define MSGTYPE_Q 33 //user - query
#define MSGTYPE_H 44 //user - history

#define DATABASE "my.db"

// 通信双方的信息结构体
typedef struct {
	int type;
	char name[NAME_LEN];
	char data[256];
}MSG_T;

/*
struct sockaddr
{
    uint8_t        sa_len;
    sa_family_t    sa_family;
    char           sa_data[14];
};
/* members are in network byte order */
/*
struct sockaddr_in
{
    uint8_t        sin_len;
    sa_family_t    sin_family;
    in_port_t      sin_port;
    struct in_addr sin_addr;
#define SIN_ZERO_LEN 8
    char            sin_zero[SIN_ZERO_LEN];
};

struct in_addr
{
    in_addr_t s_addr;
};
*/

// 注册
int do_register(int sockfd, MSG_T *msg, sqlite3 *db)
{
	char sql[128] = {0};
	char *errmsg = NULL;

	//sprintf(sql, "create table if not exists user(name text primary key, passwd text);");
	sprintf(sql, "insert into user values('%s', '%s');", msg->name, msg->data);
	if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
	{
		printf("%s\n", errmsg);
		memset(msg->data, 0, strlen(msg->data));
		sprintf(msg->data, "user(%s) already exist.!", msg->name);
	}
	else
	{
		printf("client user(%s) register success\n", msg->name);
		memset(msg->data, 0, strlen(msg->data));
		strcpy(msg->data, "register ok !");
	}

	//返回应答
	if (send(sockfd, msg, sizeof(MSG_T), 0) < 0)
	{
		printf("fail to send\n");
		return 0;
	}
	
	return 1;
}

// 登录, 必服务器返回 "OK" 才表示登录成功
// 返回值:1 成功,-1 失败,0 其他
int do_login(int sockfd, MSG_T *msg, sqlite3 *db)
{
	char sql[128] = {0};
	char *errmsg = NULL, **result = NULL;
	int nrow, ncolumn;
	
	//sprintf(sql, "create table if not exists user(name text primary key, passwd text);");
	//sprintf(sql, "insert into user values('%s', '%s');", msg->name, msg->data);
	sprintf(sql, "select * from user where name='%s' and passwd='%s';", msg->name, msg->data);
	if (sqlite3_get_table(db, sql, &result, &nrow, &ncolumn, &errmsg) != SQLITE_OK)
	{
		printf("%s\n", errmsg);
	}
	else
	{
		printf("sqlite3 get table ok! \n");
	}

	//查询成功,数据库中拥有此用户
	if (nrow == 1)
	{
		printf("client user(%s) login success\n", msg->name);
		memset(msg->data, 0, strlen(msg->data));
		strcpy(msg->data, "OK");
	}
	else //用户名或密码错误
	{
		printf("client user(%s) login fail! \n", msg->name);
		memset(msg->data, 0, strlen(msg->data));
		strcpy(msg->data, "user or passwd wrong! \n");
	}

	//返回应答
	if (send(sockfd, msg, sizeof(MSG_T), 0) < 0)
	{
		printf("fail to send\n");
		return 0;
	}
	
	return 1;

}

//根据单词从dirt.txt文本中查找对应的注释信息
//返回值: -1 文件打开失败; 0 单词未找到; 1 查找成功
int do_searchword(MSG_T *msg, char *word)
{
    FILE *fp = NULL;
    int word_len = strlen(word);
    char row_data[512] = {'\0'};
    int res = 0;
    char *p; //指向注释
    
    //打开文件
    if ((fp = fopen("dict.txt", "r")) == NULL)
    {
        perror("fail to open dict.txt.\n");
        return -1;
    }

    //打印客户端要查询的单词
    word_len = strlen(word);
    printf("%s, len = %d\n", word, word_len );

    //读取文件 行数据(一行一行读取),对比要查询的单词
    //如果成功,该函数返回相同的 str 参数。
    //如果到达文件末尾或者没有读取到任何字符,str 的内容保持不变,并返回一个空指针。
    //如果发生错误,返回一个空指针。
    while (fgets(row_data, 512, fp) != NULL)
    {
        res = strncmp(row_data, word, word_len);//每行对比前word_len个字节

        if (res != 0)
            continue;

        if (row_data[word_len] != ' ') //单词跟注释之间没有空格
            goto _end;

        // 找到了单词,跳过所有的空格
        p = row_data + word_len;
        while (*p == ' ')
        {
            p++;
        }

        strcpy(msg->data, p);
        fclose(fp);
        return 1;
    }

_end:
    fclose(fp);
    return 0; //文件对比完,单词未找到
}

//获取系统时间
void get_date(char *data)
{
    time_t rowtime; //typedef long     time_t;
//    struct tm {
//                   int tm_sec;    /* Seconds (0-60) */
//                   int tm_min;    /* Minutes (0-59) */
//                   int tm_hour;   /* Hours (0-23) */
//                   int tm_mday;   /* Day of the month (1-31) */
//                   int tm_mon;    /* Month (0-11) */
//                   int tm_year;   /* Year - 1900 */
//                   int tm_wday;   /* Day of the week (0-6, Sunday = 0) */
//                   int tm_yday;   /* Day in the year (0-365, 1 Jan = 0) */
//                   int tm_isdst;  /* Daylight saving time */
//               };
    struct tm *info;

    // rowtime = the number of seconds since the Epoch, 1970-01-01 00:00:00 +0000 (UTC)
    time(&rowtime);

    //进行时间格式转换
    info = localtime(&rowtime);

    sprintf(data, "%d-%d-%d %d:%d:%d", info->tm_year + 1900, info->tm_mon + 1, info->tm_mday,
                                       info->tm_hour, info->tm_min, info->tm_sec);

    printf("get date is : %s\n", data);                                   
}

// 单词查询
int do_query(int sockfd, MSG_T *msg, sqlite3 *db)
{
	char sql[128] = {0};
	char word[64] = {0};
	int found = 0;
    char date[128] = {0};
    char *errmsg;

    printf("\n");//显示换行
    
    //单词查找
	strcpy(word, msg->data);
	found = do_searchword(msg, word);

	if (found == 1)// 找到了单词,需要将 name,date,word 插入到历史记录表中去
	{
	    get_date(date);//获取系统时间

        //sprintf(sql, "insert into user values('%s', '%s');", msg->name, msg->data);
	    sprintf(sql, "insert into record values('%s', '%s', '%s')", msg->name, date, word);
	    if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
	    {
	        printf("%s\n", errmsg);
	        return -1;
	    }
	    else
	    {
	        printf("sqlite3 insert record done.\n");
	    }
	}
    else if (found == 0)//没有找到
    {
        memset(msg->data, 0, strlen(msg->data));
        strcpy(msg->data, "Not found!\n");
    }
    else if (found == -1)//dict.txt代开失败
    {
        memset(msg->data, 0, strlen(msg->data));
        strcpy(msg->data, "fail to open dict.txt.");
    }

	//将查询的结果发送给客户端
	send(sockfd, msg, sizeof(MSG_T), 0);
    
    return 0;

}


// 得到查询结果,并且需要将历史记录发送给客户端
int history_callback(void* arg,int colCount,char** colValue,char** colName)
{
	// record :  name, date, word 
	int acceptfd;
	MSG_T msg;

	acceptfd = *((int *)arg);
	sprintf(msg.data, "%s , %s", colValue[1], colValue[2]);
	send(acceptfd, &msg, sizeof(MSG_T), 0);

	return 0;
}

// 历史记录查询
int do_history(int sockfd, MSG_T *msg, sqlite3 *db)
{
	char sql[128] = {0};
	char *errmsg;

	//查询数据库
	//会先执行*sql对应的功能命令,然后将结果传递给回调函数,回调函数根据结果再进一步执行
	//关于回调函数详细可参考https://blog.csdn.net/u012351051/article/details/90382391
    sprintf(sql, "select * from record where name = '%s'", msg->name);
	if(sqlite3_exec(db, sql, history_callback,(void *)&sockfd, &errmsg)!= SQLITE_OK)
	{
		printf("%s\n", errmsg);
	}
	else
	{
		printf("sqlite3 query record done.\n");
	}

	// 所有的记录查询发送完毕之后,给客户端发出一个结束信息
	msg->data[0] = '\0';

	send(sockfd, msg, sizeof(MSG_T), 0);
	
	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);

	return 0;
}

// ./server 192.168.0.107 10000
// 知识点:
//	1、在一个套接字被创建时,其默认是工作在阻塞模式下,即所有socket相关的数据发送、接收函数都会阻塞,
//	直到数据发送、接收成功,函数才继续执行
//	2、可以通过fcntl来设置成阻塞或非阻塞模式。https://blog.csdn.net/haoyu_linux/article/details/44306993
int main(int argc, const char *argv[])
{
	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 (argc != 3)
	{
		printf("usage: %s serverip port\n", argv[0]);
		return -1;
	}
	
	/*********************数据库操作*********************/
	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操作*********************/
	// 申请socket
	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
	{
		perror("fail to socket\n");
		return -1;
	}	
	
	server_addr.sin_family = AF_INET;
	server_addr.sin_addr.s_addr = inet_addr(argv[1]);
	server_addr.sin_port = htons(atoi(argv[2]));
    bzero(&(server_addr.sin_zero), sizeof(server_addr.sin_zero));
    
    //绑定套接字
    if (bind(sockfd, (struct sockaddr*)&server_addr, sizeof(struct sockaddr)) < 0)
	{
		perror("fail to bind.\n");
		return -1;
	}
	
	//将套接字设为监听模式
	if (listen(sockfd, 5) < 0)
	{
		perror("fail to listen.\n");
		exit(1);
	}
	printf("listen success.\n");
	
	//处理僵尸进程
	signal(SIGCHLD, SIG_IGN);
	
	while (1)
	{
		//接收客户端的连接请求
		if ((acceptfd = accept(sockfd, (struct sockaddr *)&client_addr, &addrlen)) < 0)
		{
			perror("fail to accept\n");
			return -1;
		}
		if (inet_ntop(AF_INET, &client_addr.sin_addr, ipv4_addr, addrlen) < 0)
		{
			perror("fail to inet_ntop\n");
			return -1;
		}
		printf("client(%s:%d) is connected!\n", ipv4_addr, htons(client_addr.sin_port));

		//创建子进程
		if ((pid = fork()) < 0)
		{
			perror("fail to fork!\n");
			return -1;
		}
		else if (pid == 0) //子进程,处理客服端具体的消息
		{
			close(sockfd);
			do_client(acceptfd, db);
		}
		else //父进程,用来接收客户端的连接请求
		{
			close(acceptfd);//父进程不需要子进程的套接字
		}
	}
	
	return 0;
}

3、Makefile

all:client server
.PHONY : all

cc = gcc

client : client.c
	$(cc) client.c -o client
server : server.c
	$(cc) server.c -o server -lsqlite3

.PHONY : clean
clean:
	rm client server

 

 

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

嵌入式学习项目实战 --- 在线词典 的相关文章

  • VMware虚拟机安装CentOS8连不上网问题

    VMware虚拟机安装CentOS8连不上网 改了半天VMware中CentOS的网卡 xff0c 从 桥接模式 改到 NAT模式 34 都不管用 终极解决方案 1 选中你的虚拟机 xff0c 比如我的CentOS8 2 点击菜单栏中的 编
  • Ubuntu更换软件源

    更换 Ubuntu 的软件源 对于Ubuntu系统 xff0c 不同的版本的源都不一样 xff0c 每一个版本都有自己专属的源 而对于 Ubuntu 的同一个发行版本 xff0c 它的源又分布在全球范围内的服务器上 Ubuntu 默认使用的
  • Eclipse本地运行MapReduce

    环境说明 xff1a Linux环境下已搭建好hadoop集群 xff0c windows本地安装Eclipse 远程启动MapReduce任务 1 下载并安装eclipse插件 xff1a hadoop eclipse plugin XX
  • nvm 管理你的node

    1 安装nvm 2 nvm 管理命令 nvm ls remote 可以会列出所有可用的 Nodejs 版本 nvm install v11 0 0 就可以把这个版本的 Nodejs 安装到我们的机器上了 nvm list 可以查看当前已安装
  • ssh免密登录配置+调试讲解(超详细)+原理解析

    有写的不对的地方 xff0c 欢迎各位同学评论指正 xff0c 博主会进行修改 前 言 集群搭建中 xff0c 常常需要配置ssh免密登录 xff0c 而每台机器情况不一样 xff0c 本来博主认为没多少东西 xff0c 结果 xff0c
  • Windows和Ubuntu双系统双引导教程

    一 参考资料 Windows和Ubuntu双系统安装教程 二 步骤 1 下载EasyBCD xff0c 并安装 2 设置Windows引导 3 设置Ubuntu引导 4 启动系统 遇到这种情况 xff0c 直接Enter回车 选择系统
  • 大数据技术原理与应用(第七章 MapReduce)

    目录 7 1 MapReduce简介 MapReduce与传统并行计算框架对比 MapReduce模型 MapReduce策略 MapReduce理念 计算向数据靠拢 MapReduce架构 Master Slave Map函数和Reduc
  • FreeRTOS多任务调度原理(基于Cortex-M4)

    目录 1 Cortex M4中SysTick的重要性 2 Cortex M4中的中断管理 3 Cortex M4中影子栈指针 4 Cortex M4中SVC和PendSV异常 5 多任务启动 6 PendSV业务流程 7 系统时钟节拍详解
  • Pytorch 线性回归 grad清零报错:w.grad.data.zero_() AttributeError: 'NoneType' object has no attribute 'data'

    学习了https github com L1aoXingyu code of learn deep learning with pytorch blob master chapter3 NN linear regression gradie
  • 查看一台机器的vnc端口及vnc是否开启

    netstat lnpt grep Xvnc 查的到端口说明开的 如果没开用命令开 systemctl start vncserver 64 1 service
  • CMMI等级划分和对照

    CMMI xff08 Capability Maturity Model Integration xff09 即软件成熟度集成模型 是力图通过一套模型改善软件质量 xff0c 规范软件过程管理的模型 由于软件开发的随意和变动性比较大 xff
  • 关于解决校园网Drcom经常掉线的问题

    关于解决一些电脑由于使用WIFI共享而导致校园网Drcom经常掉线 xff1a 第一种方式 xff1a 打开控制面板 gt 网络和共享中心 gt 更改适配器设置 xff0c 再找到无线网络连接如下图所示 xff1a 鼠标右键 点开属性栏 找
  • pytorch学习日记(二)——之cv2,matplotlib,PIL比较及与Tensor的转换

    用python进行图像处理中分别用到过matplotlib pyplot PIL cv2三种库 xff0c 这三种库图像读取和保存方法各异 xff0c 并且图像读取时顺序也有差异 xff0c 如plt imread和PIL Image op
  • Python123第七周编程题

    1 文本的平均列数 span class token keyword with span span class token builtin open span span class token punctuation span span c
  • 如何完全卸载PyCharm

    进入bin文件 xff0c 找到uninstall xff0c 双击即可
  • 递归算法的简单示例

    1 xff0c 递归实现sum 函数 span class token keyword def span span class token function sum span span class token punctuation spa
  • 记事本文件保存为JAVA文件

    如何将记事本文件保存为java文件 xff1f 1 xff0c 在将记事本文件保存后 xff0c 在通过将文件名 xff08 以hello为例 xff09 后缀改为 java后 xff0c 通过查看其属性发现其格式为hello java t
  • 队列的简单示例

    1 xff0c 队列的简单应用 热土豆问题 span class token keyword from span pythonds span class token punctuation span basic span class tok
  • Git使用经验指南小结

    在使用git的时候 xff0c 每次都要查询需要的命令 xff0c 费时费力 xff0c 在这里简单总结下容易遗忘的点与命令行 xff1a 1 xff0c 首先需要安装git 安装完成后 xff0c 通过以下指令查看git版本 span c
  • 正版matlab安装详解——基于linux服务器平台正版非镜像安装

    想要在学校服务器上安装matlab 但是搜索了半天 xff0c 没有发现什么详细的攻略 xff0c 先将其总结如下 xff1a 1 在根据当前服务器环境选择合适的matlab后 xff0c 上传至服务器文件夹 xff1b 并完成解压 xff

随机推荐

  • 【疑难杂症】Ubuntu安装uWsgi出现的问题

    在Ubuntu环境下安装uWsgi的时候出现了一些问题 1 xff1a 安装时出现错误 xff1a x86 64 linux gnu gcc pthread plugins python python plugin o In file in
  • 基于Hexo框架快速搭建个人博客--搭建(一)

    基于Hexo框架快速搭建个人博客 搭建 xff08 一 xff09 一 HEXO框架二 安装Node js三 安装Git四 安装Hexo五 设置主题六 本地发布文章七 总结 博客链接 xff1a 会思想的苇草i文章链接 xff1a 基于He
  • 安装UR5功能包(翻译)

    翻译地址 由于本人能力有限 xff0c 难免存在模糊或错误之处 xff0c 希望见谅和指正 如果能够对你有点帮助 xff0c 我会感到荣幸 安装 有两种方法用来安装UR5功能包 第一种是直接使用二进制包来安装 xff0c 第二种是在catk
  • 李飞飞发表研究新成果:视觉推理的推断和执行程序(HR)

    原文 论文导读 xff1a 目前进行视觉推理的方法都是通过黑箱结构将输入直接映射到输出 xff0c 而不是对潜在的推理过程进行明确建模 这样一来 xff0c 黑箱模型学习到的是利用数据内的偏置而不是学习进行视觉推理的过程 受到模块化网络的启
  • 构建Linux Samba支持任意WIN10访问(无需改策略)

    传统方式构建的Linux Samba无法直接被WIN10访问 xff0c 大多需要在要访问的WIN10系统上改变组策略 这个方法虽然可行 xff0c 但是大量WIN10系统的组策略修改较为繁琐 之所以WIN10无法访问是当SAMBA连接开始
  • VNC SERVER 安装

    1 用root用户身份运行以下命令 yum install tigervnc server 2 停用防火墙 systemctl stop firewalld service systemctl disable firewalld servi
  • Ubuntu 更换清华大学镜像源

    Ubuntu 更换镜像源 通常我们使用ubunntu的时候总是出现网络过慢导致的更新下载失败等问题 Ubuntu默认的服务器是在国外 xff0c 自然连接就很慢 这里我们更换成国内的镜像源 xff0c 这里使用清华镜像源 操作步骤如下 xf
  • C语言strtok函数的用法

    先理解strtok函数的定义 xff0c 尤其是指针方面的 xff0c 需要自己理解 原型 xff1a char strtok char s const char delim include lt string h gt 分解字符串为一组字
  • ubuntu mate18.04+树莓派4B+ROS安装详细教程

    前记 最近项目需要 xff0c 需要给树莓派4B 安装Ubuntu mate xff0c 本来是一件很简单的事情 xff0c 因为Ubuntu mate官网已经开始支持树莓派4B了 xff0c 但是实际操作后 xff0c 才发现烧录官方的桌
  • FreeRTOS可视化追踪软件 —— 破解Tracealyzer 4.2.12

    方法一 愚人节破解Tracealyzer 4 2 12 xff08 若发这里不妥 xff0c 可通知删贴 xff09 http www stmcu org cn module forum thread 620069 1 1 html 4 3
  • tensorflow2(GPU)显卡版安装

    准备工作 硬件 xff1a 一张算力3 5以上的NVIDIA显卡 查询链接 link 软件 xff1a Miniconda3 pycharm NVIDIA显卡驱动 30系列以前 xff1a cuda 10 1 cudnn 10 1 v7 6
  • elasticsearch底层引擎替换之索引创建+文档添加

    最近在改elasticsearch的源码 xff0c 真的蛋疼 xff0c 现在先记录一下遇到的问题 首先 xff0c 我们在做的是替换掉elasticsearch的底层引擎 xff0c 也就是把lucene替换成我们自己的引擎 这个工作起
  • Winform 集成零散dll进exe的方法

    Winform程序经常需要引用一些第三方控件 xff0c 这些控件大多以DLL的形式提供 另外 xff0c 一般USB桥芯片的官方提供 net操作类库也都是DLL形式提供的 因此一个稍大的项目中往往有一大堆的零散的DLL文件 xff0c 而
  • vncserver 使用遇到的问题

    今天使用vncserver遇到了几个问题 xff0c 如下 xff1a 1 使用普通账户无法修改该账户下的vncpasswd xff1a 解决方法 xff1a 打开 vnc目录 xff0c ls l看一下发现 passwd这个文件的用户和用
  • slf4j的MDC对象和ThreadLocal简单分析

    MDC xff08 Mapped Diagnostic Context xff0c 映射调试上下文 xff09 是 log4j 和 logback 提供的一种方便在多线程条件下记录日志的功能 某些应用程序采用多线程的方式来处理多个用户的请求
  • springboot中@bean的lite模式

    当 64 Beans相互依赖时 xff0c 表示依赖关系就像一个bean方法调用另一个方法一样简 单 xff1a 64 Configuration public class AppConfig 64 Bean public Foo foo
  • spring bean解析源码分析

    转自https www jianshu com p 19e01388ccc5 前言 Spring源码分析是一个系列 xff0c 源码是Spring 4 X xff0c 本系列主要分析Spring的代码执行流程 xff0c 过于细节的内容将不
  • springboot remote shell简单实例

    springboot项目可以使用远程shell进行监控和管理 xff08 在2 0版本就不可以使用了 xff0c 此处要注意 xff09 使用时先添加spring boot remote shell 的依赖 xff0c gradle项目自己
  • 2021-08-30 创建tensor时,注意不要让梯度消失了

    下面这种是错误的 xff0c 梯度会消失 data span class token operator 61 span torch span class token punctuation span tensor span class to
  • 嵌入式学习项目实战 --- 在线词典

    目录 一 前言 二 项目功能 三 程序流程 1 客户端 2 服务器 四 代码实现 1 客户端代码 2 服务器代码 3 Makefile 一 前言 本文学习自 华清远见 的一个开源嵌入式项目在线词典综合实战 xff0c 涵盖了网络编程 文件I