04 http连接处理(上)

基础知识:epoll、http报文格式、状态码和有限状态机
代码:对服务端处理http请求的全部流程进行简要介绍,然后结合代码对http类及请求接收进行详细分析。

epoll

epoll_create函数

#include <sys/epoll.h>
int epoll_create(int size)

创建一个指示epoll内核事件表的文件描述符,该描述符将用作其他epoll系统调用的第一个参数,size不起作用。

epoll_ctl函数

#include <sys.epoll.h>
int epoll_ctl(int epfd,int op,struct epoll_event *event)

该函数用于操作内核事件表监控的文件描述符上的事件:注册、修改、删除

  • epfd:为epoll_create的句柄
  • op:表示动作,用3个宏来表示
    EPOLL_CTL_ADD注册新的fd到epfd
    EPOLL_CTL_MOD修改已经注册的fd的监听事件
    EPOLL_CTL_DEL从epfd删除一个fd
  • event:告诉内核需要监听的事件
    上述event是epoll_event结构体指针类型,表示内核所监听的事件,具体定义如下:
struct epoll_event{
__unit32_t events;
epoll_data_t data;
};
  • events描述事件类型,其中epoll事件类型有以下几种:
    EPOLLIN表示对应的文件描述符可读(包括对端SOCKET正常关闭)
    EPOLLOUT表示对应的文件描述符可以写
    EPOLLPRI表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来)
    EPOLLERR表示对应的文件描述符发生错误
    EPOLLHUP表示对应的文件描述符被挂断
    EPOLLET将EPOLL设为边缘触发Edge Triggered模式,这是相对于水平触发Level Triggered而言的
    EPOLLONESHOT只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里

epoll_wait函数

#include <sys/epoll.h>
int epoll_wait(int epfd,struct epoll_event *events,int maxevents,int timeout)

该函数用于等待所监控文件描述符上有事件的产生,返回就绪的文件描述符个数

  • events:用来存内核得到事件的集合
  • maxevents:告之内核整个events有多大,这个maxevents的值大于创建epoll_create()时的size
  • timeout超时时间
    -1:阻塞
    0:立即返回,非阻塞
    大于0:指定毫秒
  • 返回值:成功返回有多少文件描述符就绪,事件到时返回0,出错返回-1

select/poll/epoll

  • 调用函数
    select和poll都是一个函数,epoll是一组函数
  • 文件描述符数量
    select通过线性表描述文件描述符集合,文件描述符有上限,一般是1024,但可以修改源码,重新编译内核,不推荐
    poll是链表描述,突破了文件描述符上限,最大可以打开文件的数目
    epoll通过红黑树描述,最大可以打开文件的数目,可以通过命令ulimit -n number修改,仅对当前终端有效
  • 将文件描述符从用户传给内核
    select和poll通过将所有文件描述符拷贝到内核态,每次调用都需要拷贝
    epoll通过epoll_create建立一棵红黑树,通过epoll_ctl将要监听的文件描述符注册到红黑树上
  • 内核判断就绪的文件描述符
    select和poll通过遍历文件描述符集合,判断哪个文件描述符上有事件发生
    epoll_create时,内核除了帮我们在epoll文件系统里建了个红黑树用于存储以后epoll_ctl传来的fd外,还会再建立一个list链表,用于存储准备就绪的事件,当epoll_wait调用时,仅仅观察这个list链表里有没有数据即可
    epoll是根据每个fd上面的回调函数(中断函数)判断,只有发生了事件的socket才会主动的去调用callback函数,其他空闲状态socket则不会,若是就绪事件,插入list
  • 应用程序索引就绪文件描述符
    select/poll只返回了事件的文件描述符的个数,若知道是哪个事件发生了事件,同样需要遍历
    epoll返回的发生了事件的个数和结构体数组,结构体包含socket的信息,因此直接处理返回的数组即可
  • 工作模式
    select和poll都只能工作在相对低效的LT模式下
    epoll则可以工作在ET高效模式,并且epoll还支持EPOLLONESHOT事件,该事件能进一步减少可读、可写和异常事件被触发的次数。
  • 应用场景
    当所有的fd都是活跃连接,使用epoll,需要建立文件系统,红黑书和链表对于此来说,效率反而不高,不如select和poll
    当监测的fd数目较小,且各个fd都比较活跃,建议使用select或者poll
    当监测的fd数目非常大,成千上万,且单位时间只有其中一部分fd处于就绪状态,这个时候使用epoll能够明显提升性能。

ET、LT、EPOLLONESHOT

  • LT水平触发模式
    epoll_wait检测到文件描述符有事件发生,则将通知给应用程序,应用程序可以不立即处理该事件;当下一次调用epoll_wait时,epoll_wait还会再次向应用程序报告此事件,直至被处理。
  • ET边缘触发模式
    epoll_wait检测到文件描述符有事件发生,则将其通知给应用程序,应用程序必须立即处理该事件;必须要一次性将数据读取完,使用非阻塞I/O,读取到出现eagain
  • EPOLLONESHOT
    一个线程读取某个socket上的数据后开始处理数据,在处理过程中该socket上又有新数据可读,此时另一个线程被唤醒读取,此时出现两个线程处理同一个socket
    我们期望的是一个socket连接在任一时刻都只被一个线程处理,通过epoll_ctl对该文件描述符注册epolloneshot事件,一个线程处理socket时,其他线程无法处理,当线程处理完后,需要通过epoll_ctl重置epolloneshot事件

HTTP报文格式

HTTP报文分为请求报文和响应报文两种,每种报文必须按照特有格式生成,才能浏览器端识别。其中,浏览器端向服务器发送的为请求报文,服务器处理后返回给浏览器端的为响应报文。

请求报文

HTTP请求报文由请求行、请求头部、空行和请求数据四个部分组成。
请求分为GET和POST两种。

  • GET

在这里插入图片描述

  • POST
1     POST / HTTP1.1
2     Host:www.wrox.com
3     User-Agent:Mozilla/4.0 (compatible;MSIE 6.0; Windowa NT 5.1;SV1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)
4     Content-Type:application/x-www-form-urlencoded
5     Content-Length:40
6     Connection:Keep-Alive
7     空行
8     name=Professional%20Ajax&publisher=Wiley
  • 请求行:说明请求类型,要访问的资源以及所使用的HTTP版本

GET说明请求类型为GET,/562f25980001b1b106000338.jpg(URL)为要访问的资源,该行的最后一部分说明使用的是HTTP1.1版本。

  • 请求头部:紧接着请求行(第一行)之后的部分,用来说明服务器要使用的附加信息。

HOST,给出请求资源所在服务器的域名
User-Agent,HTTP客户端程序的信息,该信息由你发出请求使用的浏览器来定义,并且在每个请求中自动发送等。
Accept,说明用户代理可处理的媒体类型。
Accept-Encoding,说明用户代理支持的内容编码。
Accept-Language,说明用户代理能够处理的自然语言集
Content-Type,说明实现主体的媒体类型
Content-Length,说明实现主体的大小
Connection,连接管理,可以是Keep-Alive或close

  • 空行,请求头部后面的空行是必须的即使第四部分请求数据为空,也必须有空行
  • 请求数据也叫主体,可以添加任意的其他数据

响应报文

HTTP响应也由四个部分组成,分别是:状态行、消息报头、空行和响应正文
在这里插入图片描述

  • 状态行,由HTTP协议版本号,状态码,状态消息 三部分组成

第一行为状态行,(HTTP/1.1)表明HTTP版本为1.1版本,状态码为200,状态消息为OK

  • 消息报头,用来说明客户端要使用的一些附加信息

第二行和第三行为消息报头,Date生成响应的日期和时间;Content-Type指定了MME类型的HTML(text/html),编码类型是UTF-8

  • 空行,消息报头后面的空行是必须的
  • 响应正文,服务器返回给客户端的文本信息。空行后面的html部分为响应正文。

HTTP状态码

  • 1xx:指示信息-表示请求已接收,继续处理。
  • 2xx:成功-表示请求正常处理完毕
    200 OK:客户端请求被正常处理
    206 Partial content:客户端进行了范围请求
  • 3xx:重定向-要完成请求必须进行更进一步的操作
    301 Moved Permanently:永久重定向,该资源已被永久移动到新位置,将来任何对该资源的访问都要使用本响应返回的若干个URL之一。
    302 Found:临时重定向,请求的资源现在临时从不同的URI中获得
  • 4xx:客户端错误-请求有语法错误,服务器无法处理请求
    400 Bad Request:请求报文存在语法错误
    403 Forbidden:请求被服务器拒绝
    404 Not Found:请求不存在,服务器上找不到请求的资源
  • 5xx:服务器端错误-服务器处理请求出错
    500 Internal Server Error:服务器在执行请求时出现错误

有限状态机

有限状态机,是一种抽象的理论模型,它能够把有限个变量描述的状态变化过程,以可构造可验证的方式呈现出来。比如,封闭的有向图。
有限状态机可以通过if-else,switch-case和函数指针来实现,从软件工程的角度看,主要是为了封装逻辑。
带有状态转移的有限状态机示例代码。

STATE_MACHINE(){
	State cur_State=type_A;
	while(cur_State!=type_C){
		Package _pack=getNewPackage();
		switch(){
			case type_A:
				process_pkg_state_A(_pack);
				cur_State=type_B;
				break;
			case type_B:
				process_pkg_state_B(_pack);
				cur_State=type_C;
				break;
		}
	}
}

该状态机包含三种状态:type_A,type_B和type_C。其中,type_A是初始状态,type_C是结束状态。
状态机的当前状态记录在cur_State变量中,逻辑处理时,状态机先通过getNewPackage获取数据包,然后根据当前状态对数据进行处理,处理完后,状态机通过改变cur_State完成状态转移。
有限状态机一种逻辑单元内部的一种高效编程方法,在服务器编程中,服务器可以根据不同状态或者消息类型进行相应的处理逻辑,使得程序逻辑清晰易懂。

http处理流程

首先对http报文处理的流程进行简要介绍,然后具体介绍http类的定义和服务器接收http请求的具体过程。

http报文处理流程

  • 浏览器发出http连接请求,主线程创建http对象接收请求并将所有数据读入对应buffer,将改对象插入任务队列,工作线程从任务队列中取出一个任务进行处理。
  • 工作线程取出任务后,调用process_read函数,通过主、从状态机请求报文进行解析。
  • 解析完之后,跳转do_request函数生成响应报文,通过process_write写入buffer,返回给浏览器端。

http类

http_conn.h中,主要是http类的定义。

class http_conn{
	public:
		//设置读取文件的名称m_real_file大小
		static const int FILENAME_LEN=200;
		//设置读缓冲区m_read_buf大小
		static const int READ_BUFFER_SIZE=2048;
		//设置写缓冲区m_write_buf大小
		static const int WRITE_BUFFER_SIZE=1024;
		//报文的请求方法,本项目只用到GET和POST
		enum METHOD{GET=0,POST,HEAD,PUT,DELETE,TRACE,OPTIONS,CONNECT,PATH};
		//主状态机的状态
		enum CHECK_STATE{CHEACK_STATE_QEQUESTLINE=0,CHECK_STATE_HEADER,CHECK_STATE_CONTENT};
		//报文解析的结果
		enum HTTP_CODE{NO_REQUEST,GET_REQUEST,BAD_REQUEST,NO_RESOURCE,FORBIDDEN_REQUEST,FILE_REQUEST,INTERNAL_ERROR,CLOSED_CONNECTION};
		//从状态机的状态
		enum LINE_STATUS{LINE_OK=0,LINE_BAD,LINE_OPEN};

	public:
		http_conn(){}
		~http_conn(){}
	
	public:
		//初始化套接字地址,函数内部会调用私有方法init
		void init(int sockfd,const sockaddr_in &addr);
		//关闭http连接
		void close_conn(bool real_close=true);
		void process();
		//读取浏览器端发来的全部数据
		bool read_once();
		//响应报文写入函数
		bool write();
		sockaddr_in *get_address(){
			return &m_address;
		}
		//同步线程初始化数据库读取表
		void initmysql_result();
		//CGI使用线程池初始化数据库表
		void initresultFile(connection_pool *connPool);

	private:
		void init();
		//从m_read_buf读取,并处理请求报文
		HTTP_CODE process_read();
		//向m_write_buf写入响应报文数据
		bool process_write(HTTP_CODE ret);
		//主状态机解析报文中的请求行数据
		HTTP_CODE parse_request_line(char* text);
		//主状态机解析报文中的请求头数据
		HTTP_CODE parse_headers(char* text);
		//主状态机解析报文中的请求内容
		HTTP_CODE parse_content(char* text);
		//生成响应报文
		HTTP_CODE do_request();

		//m_start_line是已经解析的字符
		//get_line用于将指针向后偏移,指向未处理的字符
		char* get_line(){return m_read_buf+m_start_line;};

		//从状态机读取一行,分析是请求报文的哪一部分
		LINE_STATUS parse_line();
		
		void unmap();
		
		//根据响应报文格式,生成对应8个部分,以下函数均由do_request调用
		bool add_reponse(const char* format,...);
		bool add_content(const char* content);
		bool add_status_line(int status,const char* title);
		bool add_headers(int content_length);
		bool add_content_type();
		bool add_content_length(int content_length);
		bool add_linger();
		bool add_blank_line();

	public:
		static int m_epollfd;
		static int m_user_count;
		MYSQL *mysql;

	private:
		int m_sockfd;
		sockaddr_in m_address;

		//存储读取的请求报文数据
		char m_read_buf[READ_BUFFER_SIZE];
		//缓冲区中m_read_buf中数据的最后一个字节的下一个位置
		int m_read_idx;
		//m_read_buf读取的位置m_checked_idx
		int m_checked_idx;
		//m_read_buf中已经解析的字符个数
		int m_start_line;

		//存储发出的响应报文数据
		char m_write_buf[WRITE_BUFFER_SIZE];
		//指示buffer中的长度
		int m_write_idx;
		
		//主状态机的状态
		CHECK_STATE m_check_state;

		//请求方法
		METHOD m_method;
		
		//以下为解析请求报文中对应的6个变量
		//存储读取文件的名称
		char m_real_file[FILENAME_LEN];
		char *m_url;
		char *m_version;
		char *m_host;
		int m_content_length;
		bool m_linger;

		char *m_file_address;//读取服务器上的文件地址
		struct stat m_file_stat;
		struct iovec m_iv[2];//io向量机制iovec
		int m_iv_count;
		int cgi;//是否启用的POST
		char *m_string;//存储请求头数据
		int bytes_to_send;//剩余发送字节数
		int bytes_have_send;//已发送字节数
};

在http请求接收部分,会涉及到init和read_once函数,但init仅仅是对私有成员变量进行初始化,不用过多讲解。
read_once读取浏览器端发送来的请求报文,直到无数据可读或对方关闭连接,读取到m_read_buffer中,并更新m_read_idx。

//循环读取客户数据,直到无数据可读或对方关闭连接
bool http_conn::read_once()
{
	if(m_read_idx>=READ_BUFFER_SIZE)
	{
		return false;
	}
	int bytes_read=0;
	while(true)
	{
		//从套接字接收数据,存储在m_read_buf缓冲区
		bytes_read=recv(m_sockfd,m_read_buf+m_read+idx,READ_BUFFER_SIZE-m_read_idx,0);
		if(bytes_read==-1){
			//非阻塞ET模式下,需要一次性将数据读完
			if(errno==EAGAIN||errno==EWOULDBLOCK){
				break;
			return false;
			}
		}else if(bytes_read==0){
			return false;
		}
		//修改m_read_idx的读取字节数1
		m_read_idx+=bytes_read;
	}
	return true;
}

epoll相关代码

项目中epoll相关代码部分包括非阻塞模式、内核事件表注册事件、删除事件、重置EPOLLONESHOT事件四种。

  • 非阻塞模式
//对文件描述符设置非阻塞模式
int setnoblocking(int fd){
	int old_option=fcntl(fd,F_GETFL);//获取文件fd的当前状态
	int new_option=old_option|O_NONBLOCK;
	fcntl(fd,F_SETFL,new_option);
	return old_option;
}
  • 内核事件表注册新事件,开启EPOLLONESHOT,针对客户端连接的描述符,listenfd不用开启
void addfd(int epollfd,int fd,bool one_shot)
{
	epoll_event event;
	event.data.fd=fd;

#ifdef ET
	event.events=EPOLLIN|EPOLLET|EPOLLRDHUP;
#endif

#ifdef LT
	event.events=EPOLLIN|EPOLLRDHUP;
#endif

	if(one_shot)
		event.events|=EPOLLONESHOT;
	epoll_ctl(epollfd,EPOLL_CTL_ADD,fd,&event);
	setnonblocking(fd);
}
  • 内核事件表删除事件
void removefd(int epollfd,int fd){
	epoll_ctl(epollfd,EPOLL_CTL_DEL,fd,0);
	close(fd);
}
  • 重置EPOLLONESHOT事件
void modfd(int epollfd,int fd,int ev){
	epoll_event event;
	event.data.fd=fd;

#ifdef ET
	event.events=ev|EPOLLET|EPOLLONESHOT|EPOLLRDHUP;
#endif

#ifdef LT
	event.events=ev|EPOLLONESHOT|EPOLLRDHUP;
#endif
	
	epoll_ctl(epollfd,EPOLL_CTL_MOD,fd,&event);
}

服务器接收http请求

浏览器端发出http连接请求,主线程创建http对象接收请求并所有数据读入对应buffer,将该对象插入任务队列,工作线程从任务队列取出一个任务进行处理。

//创建MAX_FD个http类对象
http_conn* user=new http_conn[MAX_FD];

//创建内核事件表
epoll_event events[MAX_EVENT_NUMBER];
epollfd=epoll_create(5);
assert(epollfd!=-1);

//将listenfd放在epoll数上
addfd(epollfd,listenfd,false);

//将上述epollfd赋值给http类对象的m_epollfd属性
http_conn::m_epollfd=epollfd;

while(!stop_server){
	//等待所监控文件描述符上有事件的产生
	int number=epoll_wait(epollfd,events,MAX_EVENT_NUMBER,-1);
	if(number<0&&errno!=EINTR){
		break;
	}
	//对所有就绪事件进行处理
	for(int i=0;i<number;i++){
		int sockfd=events[i].data.fd;

		//处理新到的客户连接
		if(sockfd==listenfd){
			struct sockaddr_in client_address;
			socklen_t client_addrlength=sizeof(client_address);
//LT水平触发
#ifdef LT
			int connfd=accept(listenfd,(struct sockaddr*)&client_address,&client_addrlength);
			if(connfd<0){
				continue;
			}
			if(http_conn::m_user_count>=MAX_FD){
				show_error(connfd,"Internal server busy");
				continue;
			}
			users[connfd].init(connfd,client_address);
#endif

//ET非阻塞边缘触发
#ifdef ET
			//需要循环接收数据
			while(1)
			{
				int connfd=accept(listenfd,(struct sockaddr *)&client_address,&client_addrlength);
				if(connfd<0){
					break;
				}
				if(http_conn::m_user_count>=MAX_FD){
					show_error(connfd,"Internal server busy");
					break;
				}
				users[connfd].init(connfd,client_address);
			}
			continue;
#endif
		}
	
		//处理异常事件
		else if(events[i].events&(EPOLLRDRDHUP|EPOLLHUP|EPOLLERR)){
			//服务器端关闭连接
		}
		//处理信号
		else if((sockfd==pipefd[0])&&(events[i].events&EPOLLIN))
		{
		}
		
		//处理客户连接上接收到的数据
		else if(events[i].events&EPOLLIN){
			//读入对应缓冲区
			if(users[sockfd].read_once()){
				//若监测到读事件,将该事件放入请求队列
				pool->append(users+sockfd);
			}
			else{
				//服务器关闭连接
			}
		}
	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/51954.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

回归预测 | MATLAB实现TCN-BiLSTM时间卷积双向长短期记忆神经网络多输入单输出回归预测

回归预测 | MATLAB实现TCN-BiLSTM时间卷积双向长短期记忆神经网络多输入单输出回归预测 目录 回归预测 | MATLAB实现TCN-BiLSTM时间卷积双向长短期记忆神经网络多输入单输出回归预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 1.MATLAB实现TCN-BiLSTM时间卷积…

CleanMyMac X4.14.1中文版如何清理 Mac系统?CleanMyMac 真的能断网激活吗?

CleanMyMac X4.14.1中文版如何清理 Mac系统&#xff1f;Mac系统在使用过程中都会产生大量系统垃圾&#xff0c;如不需要的系统语言安装包&#xff0c;视频网站缓存文件&#xff0c;mac软件卸载残留的注册表等。 随着时间推移&#xff0c;mac系统垃圾就会越来越多&#xff0c;电…

美团小图币代挂教程

登陆美团官网获取对应的cookie 美团官网&#xff0c;点击右上角登陆对应账号。登陆成功后使用f12来获取 cookie 此时如果没有任何数据&#xff0c;点击网页刷新。找到如下的网络请求 赋值cookie项的全部内容&#xff0c;此时已经获取到对应账号的cookie 使用cookie登陆代挂…

Web博客项目及jwt的学习

这几天完善了发布博客&#xff0c;完成了收藏博客的功能 博客项目 一共有三种身份&#xff1a; 访客&#xff08;未登录&#xff09;&#xff0c;用户&#xff0c;管理员。 其中管理员拥有的功能最多&#xff0c;其次是用户&#xff0c;然后是访客。 从功能上看&#xff1a…

一文3000字从0到1使用Selenium进行自动化测试

对于很多刚入门的测试新手来说&#xff0c;大家都将自动化测试作为自己职业发展的一个主要阶段。可是&#xff0c;在成为一名合格的自动化测试工程师之前&#xff0c;我们不仅要掌握相应的理论知识&#xff0c;还要进行大量的实践&#xff0c;积累足够的经验&#xff0c;以便快…

7.7 SpringBoot实战 管理员借阅审核列表 --分页和枚举的使用

文章目录 前言一、需求二、定义接口 BookAdminController三、核心实现 BookBorrowService新建 BookBorrowService 接口定义如下&#xff1a;新建 BookBorrowServiceImpl 类&#xff0c;核心实现逻辑&#xff1a;新建 BookBorrowBO 四、图书借阅状态枚举 BookBorrowStatusEnum五…

华为数通HCIA-数通网络基础

基础概念 通信&#xff1a;两个实体之间进行信息交流 数据通信&#xff1a;网络设备之间进行的通信 计算机网络&#xff1a;实现网络设备之间进行数据通信的媒介 园区网络&#xff08;企业网络&#xff09;/私网/内网&#xff1a;用于实现园区内部互通&#xff0c;并且需要部…

better scoll的使用以及注意事项以及左联右

下载better scoll的核心 在你要使用的页面引入 在data里面定义一个对象 然后在createad里面放一个nexttick异步操作。 上面是获取这个left-box节点是父节点 记住里面只能有一个子节点如果循环了 就要再包一个div就是一个子节点 左联右 首先也要获取 右边的 父节点 然后配…

(树) 剑指 Offer 28. 对称的二叉树 ——【Leetcode每日一题】

❓ 剑指 Offer 28. 对称的二叉树 难度&#xff1a;简单 请实现一个函数&#xff0c;用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样&#xff0c;那么它是对称的。 例如&#xff0c;二叉树 [1,2,2,3,4,4,3] 是对称的。 1/ \2 2/ \ / \3 4 4 3但是下面这个…

了解Unity编辑器之组件篇Layout(八)

Layout&#xff1a;用于管理和控制UI元素的排列和自动调整一、Aspect Ratio Fitter&#xff1a;用于根据宽高比自动调整UI元素的大小 Aspect Mode&#xff1a;用于定义纵横比适配的行为方式。Aspect Mode属性有以下几种选项&#xff1a; &#xff08;1&#xff09;None&#xf…

安全学习DAY12_信息打点-Web应用信息搜集

信息打点-Web应用 文章目录 信息打点-Web应用业务资产企业查信息的目的 Web应用信息搜集Web网站域名搜集WEB单域名WEB子域名OneForAll&#xff08;子域名收集工具&#xff09; WEB网站架构资产WEB指纹识别资产 常用查询平台汇总查企业信息查备案信息查公众号信息域名注册查询IP…

基于 Docker 的深度学习环境:Windows 篇

本篇文章&#xff0c;我们聊聊如何在 Windows 环境下使用 Docker 作为深度学习环境&#xff0c;以及快速运行 SDXL 1.0 正式版&#xff0c;可能是目前网上比较简单的 Docker、WSL2 配置教程啦。 写在前面 早些时候&#xff0c;写过一篇《基于 Docker 的深度学习环境&#xff…

幅度调制与角度调制

文章目录 前言一、调制简介1、调制定义2、调制目的3、调制的分类 二、幅度调制&#xff08;线性调制&#xff09;1、幅度调制的一般模型2、常规双边带调幅 AM①、AM 信号的产生②、AM 调制器的模型③、AM 波形和频谱④、AM 信号的特点⑤、AM 包络检波⑥、调幅系数 3、抑制载波双…

【用IDEA基于Scala2.12.18开发Spark 3.4.1 项目】

目录 使用IDEA创建Spark项目设置sbt依赖创建Spark 项目结构新建Scala代码 使用IDEA创建Spark项目 打开IDEA后选址新建项目 选址sbt选项 配置JDK debug 解决方案 相关的依赖下载出问题多的话&#xff0c;可以关闭idea&#xff0c;重启再等等即可。 设置sbt依赖 将sbt…

neo4j教程-Cypher操作

Cypher基础操作 Cypher是图形存储数据库Neo4j的查询语言&#xff0c;Cypher是通过模式匹配Neo4j数据库中的节点和关系&#xff0c;从而对数据库Neo4j中的节点和关系进行一系列的相关操作。 下面&#xff0c;通过一张表来介绍一下常用的Neo4j操作命令及相关说明&#xff0c;具…

基于峰谷分时电价引导下的电动汽车充电负荷优化(matlab代码)

目录 1 主要内容 峰谷电价优化 电动汽车充电负荷变化 2 部分代码 3 程序结果 1 主要内容 该程序基本复现《基于峰谷分时电价引导下的电动汽车充电负荷优化》&#xff0c;代码主要做的是基于NSGA-II的电动汽车充电负荷优化&#xff0c;首先&#xff0c;在研究电动汽车用户充…

【VSCode部署模型】导出TensorFlow2.X训练好的模型信息

参考tensorflow2.0 C加载python训练保存的pb模型 经过模型训练及保存&#xff0c;我们得到“OptimalModelDataSet2”文件夹&#xff0c;模型的保存方法(.h5或.pb文件)&#xff0c;参考【Visual Studio Code】c/c部署tensorflow训练的模型 其中“OptimalModelDataSet2”文件夹保…

HDFS中namenode安全模式

HDFS中namenode安全模式 安全模式的现象探究step1step2step3step4 安全模式的概述控制进入时间和离开条件安全模式自动进入离开安全模式手动进入离开 安全模式的现象探究 step1 HDFS集群在停机状态下&#xff0c;使用hdfs -daemon命令逐个进程启动集群&#xff0c;观察现象首…

太猛了,靠“吹牛”过顺丰一面,月薪30K

说在前面 在40岁老架构师尼恩的&#xff08;50&#xff09;读者社群中&#xff0c;经常有小伙伴&#xff0c;需要面试美团、京东、阿里、 百度、头条等大厂。 下面是一个5年小伙伴成功拿到通过了顺丰面试&#xff0c;拿到offer&#xff0c;月薪30K。 现在把面试真题和参考答…

音视频——压缩原理

H264视频压缩算法现在无疑是所有视频压缩技术中使用最广泛&#xff0c; 最流行的。随着 x264/openh264以及ffmpeg等开源库的推出&#xff0c;大多数使用者无需再对H264的细节做过多的研究&#xff0c;这大降低了人们使用H264的成本。 但为了用好H264&#xff0c;我们还是要对…