nginx系列--(三)--http
本文主要介绍http模块accept read流程,!!!请求对应的响应直接在read流程里就会返回给用户,而不需要通过write事件,和redis一样,基本都不通过eventloop write事件来发送响应给客户端,除非一次发送不完,nginx write事件则只会写邮件的时候ssl ocsp的时候才会触发,略,
!!!http模块和stream模块的实现原理基本一样,都是通过handler来执行差异化操作,而主eventloop流程用的都是同一套代码
下拉刷新:间歇性奖励
无线上划:人类在没有标识的情况下很容易过量
#访问localhost:10086/hello返回的是nginx/html/hello/index.html
location /hello {root html; #root表示设置根目录,然后会自动访问hello目录,即要求location 路径对应的目录要一致index index.html index.htm;
}#访问localhost:10086/hello返回的是nginx/html/index.html
location /hello {alias html; #alias表示直接用这个目录index index.html index.htm;
}
!!!笔记:源码流程第一个断点最好不要用入口点,而是要打在执行流程中,比如你要debug http处理请求流程,那么就不要把第一个断点打在请求分发的地方,因为这个dispatch点是可以接受各种不同类型的请求,后续会因为请求会走不同的调用路线,所以我们最好打在具体流程中,即我们要debughttp流程,那么就把断点打在http_handler中,而不是打在调用httphandler的地方,因为调用者肯定是调用handler,而handler是一个指针,不同请求,handler值不同,所以应该直接打在http_handler中,然后有http_handler再网上。可以在handler中打断点,但这样需要step_into往下走才知道在哪里会走到handler,在哪跳转到http_handler,所以直接在http_handler中打断点然后往上回溯要比handler中打断点,然后一行一行step into要简单的多。反正断点的核心就是关键路径上多打几个断点。
!!!注意:nginx是多进程,需要特殊设置,否则因为处理都是在子进程中而导致我们打的断点不起作用
!!!nginx是每个worker都可以同时处理监听套接字以及客户端套接字,nginx并没有分配一个专门的进程来处理监听套接字,而是每个worker在每一轮事件循环开始前都竞争一次accept_mutex,!!!每一轮都竞争accept_mutex肯定会降低效率的,不过如果启用了linux epoll的epollexclusive,就可以不开启accept_mutex,因为此时只会有一个进程的epoll中的listen fd会触发读事件,这是linux操作系统提供的,此时则不用每次都竞争accept_mutex锁,也就是说accept_mutex锁此时会失效,不过nginx肯定会对这个进行一个封装。
nginx可以关闭后台模式;nginx也可以以单进程多线程的方式运行
笔记:nginx对请求的处理流程是一样的,eventloop_for_死循环+epoll_wait+for_所有fd+handler,然后handler是一个指针,也就是说流程是一样的,只是调用的handler不同而已,注意,handler不止一个,他用一个数组来存,并按顺序调用,因为这个handler是注册制的,就是说如何处理tcp/udp发来的数据,完全由注册的handler决定,也就是说如果要是nginx支持自定义的x协议,那么流程如下:1:把handler数组册到指定的handler中;2:handler中的数组要有序,因为他是按顺序调用的,所以我们只要按顺序来注册,那么就可以保证请求按我们指定的流程来处理。
笔记:自己读完以后再去网上找文章查看对应的文章
!!!笔记:默认nginx应用层只支持http,所以conf里最外层的http{xxx}就告诉nginx这个块对应的是http模块。默认的nginx传输层支持TCP和udp,所以conf里最外层的stream{xxx}就告诉nginx这个块对应的是tcp/udp,也就是说我们的处理函数接触的是传输层的原始字节流,我们可以选择转发也可以选择自己解析成应用层协议进一步处理。原始字节流的含义取决于我们怎么解析。nginx的http模块就相当于在原始的stream模块之上添加了http字节流解析模块,这个模块可以把字节流解析成http协议,nginx的http模块把这一切都实现了,就无须我们自己实现了。
!!!笔记:nginx的http模块把http协议的处理分成了11个阶段,而stream模块则分成了7个阶段
!!!笔记:nginx 根据conf中的分块名来调用对应的模块。nginx中http模块和stream模块在系统中的名字分别是http和stream,如果把http模块注册的名字改成http_abc,那么conf中对应的http{xx}就要改成http_abc{xx},否则就会报错找不到对应的模块
!!!笔记(猜测):如果要nginx支持新的应用层协议,那么就只能自己实现新的xx模块,然后配置文件里就能用xx{yy}来定义了,不过这样如果自己实现的话工作量就打了,要自己来解析配置,就很麻烦了
如果要支持
2:http处理流程
直接百度断点ngx_http_handler+搜索epoll_wait打下断点,一共两个断点,就可以抓住主线
2-1:模块启动和listenfd注册到epoll流程
笔记:流程同stream模块一模一样,已经在stream文章的模块启动部分叙述了,这里不再重复,只是简单记录一下
nginx.mainngx_cycle.ngx_init_cyclengx_conf_file.ngx_conf_parse for ; ; ......cmd->set #cmd->set就是各个模块对应的set函数,不同的模块对应不同的函数#比如stream模块就调用ngx_stream_block,http就用ngx_http_block#!!!也就是说nginx用函数指针来实现了一种多态的效果#!!!也就是说可以用同一套代码流程来加载http、stream模块3: http块,这是最顶层的http 块 ngx_http.ngx_http_block ngx_conf_file.ngx_conf_parse ......ngx_http.ngx_http_init_phases ngx_http.ngx_http_init_phase_handlers ngx_http.ngx_http_optimize_servers ngx_http.ngx_http_init_listening ngx_http.ngx_http_add_listeningls=ngx_create_listening ls.handler=ngx_http_init_connection #!!!listenfd对新连接的处理函数设置为ngx_http_init_connection#!!!stream模块中则设置为ngx_stream_init_connection#!!!再次强调,ngx通过函数指针来模拟了多态,#!!!也就是同一套代码可以同时处理httpfd和streamfd#!!!下面的代码不管是http还是stream,都是同一个处理流程:注册到epollfd#!!!因为nginx中http和strema模块的不同在于处理函数的不同,而nginx把不同的handler封装在event_t结构体中#!!!而event_t结构体又包含在connection结构体中,clientfd存在epollfd中的就是connection结构,#!!!也就是说不管是http还是stream,用的都是connection结构,而他们的区别只有字段值的不同#!!!正因为如此,所以可以用同一个epollfd来同时处理httpserver-listenfd、streamserver-listenfd#!!!、httpclientfd、streamclientfd、streamupstreamfd上的读写事件......ngx_process_cycle.ngx_master_process_cycle ngx_process_cycle.ngx_start_worker_processes ......unistd.fork #fork子进程......rev->handler = ngx_event_accept; #!!!设置accept事件的处理函数为ngx_event_accept#!!!nginx把fd、handler都封装在ngx_event_t结构体中#!!!然后ngx_event_t结构又封装在connection结构中#!!!connection结构会作为epoll_events的data字段丢到epollfd中#!!!封装使得epoll_eventloop流程代码可以通用#!!!即不论是httpfd事件还是streamfd事件还是listenfd事件ngx_add_event(rev, NGX_READ_EVENT, NGX_EXCLUSIVE_EVENT) #!!!注册listenfd的read事件到epollfd,并且是exclusive模式#!!!accept_handler为ngx_event_acceptee.data.ptr = (void *) ((uintptr_t) c | ev->instance) #data字段为c,c是一个connection对象指针epoll_ctl(ep, op, c->fd, &ee) #这样我们直接从data取出connection对象#也就是说connection对象保存了一个连接的所有状态#redis也是一样的操作,所以epoll类型的应该都是一样的操作......2:执行eventloop,略,详情见eventloop源码流程
1-2:http listenfd accept流程
ngx_proces_cycle.ngx_worker_process_cycle #这里是子进程里面的流程1:!!!初始化eventloop(初始化+注册相关fd到eventloop)......ngx_add_event(rev, NGX_READ_EVENT, NGX_EXCLUSIVE_EVENT) #!!!注册listenfd的read事件到epollfd,并且是exclusive模式......2:!!!执行eventLoopfor ; ; #死循环,即eventloop,事件循环ngx_event.ngx_process_events_and_timers #处理事件和定时器 ngx_epoll_module.ngx_epoll_process_events #到此处时已经是epoll_wait返回的fd了,所以直接处理fd就行了#!!!如果触发了读事件就调用rev->handler(rev=connection->read_events)#!!!如果触发了写事件就调用wev->handler(wev=connection->write_events)wev = c->write;if ((revents & EPOLLOUT) && wev->active) wev->ready = 1;wev->handler #accept只注册了read事件,没有注册write事件,所以revents&EPOLLOUT=0#!!!accept事件对应读事件,所以调用rev->handlerif ((revents & EPOLLIN) && rev->active) : rev->ready = 1;ngx_event_accept.ngx_event_accept #不管是http还是stream,listenfd注册流程都是一样的以及accept函数都是一样的#因为所有的不同都封装在handler中,#即conection里的read_events/write_events对象的handler中
----------------在此之上的流程和stream accept一模一样----------------------------------------------------ngx_http_request.ngx_http_init_connection #!!!即ls->handler,nginx通过函数指针来实现同一套代码同时处理http和stream#笔记:listenfd对应的read events handler为ngx_event_accept#此处的ls->handler是用来处理新建立的连接的#比如stream模块中对应的ls->handler就是与upsteam建立连接#同样的,ngx_http_init_connenction和#ngx_stream_init_connection的逻辑基本是一样的#只不过ngx_http_init_connection少了个连接upstream的操作#笔记:stream_init_connection中设置了clientfd.rev.handler=ngx_stream_session_handler;#但是在cscf->handler即ngx_stream_proxy_handler中#会重新设置为ngx_stream_proxy_downstream_handler;#笔记:clientfd放在session中,然后传递session给这个函数rev = c->read;rev->handler = ngx_http_wait_request_handler; #!!!设置http clientfd的read_events_handler#ngx_http_finalize_request中调用ngx_http_finalize_connection时#会根据是否开启keepalive选项来决定是否把rev->handler设置为ngx_http_keepalive_handler#默认是会的,也就是第一次是走wait_request_handler#但是第二个请求就会走keepalive_handler了c->write->handler = ngx_http_empty_handler; ngx_event.ngx_handle_read_event #把clientfd注册到epollfd中#笔记:http模块中accept时就注册到epollfd中了#而stream模块则是等到upstream处理第一次write时才会注册到epollfd中#!!!#define NGX_CLEAR_EVENT EPOLLET 就是说nginx默认是边缘触发ngx_event_accept.ngx_reorder_accept_events #处理accept公平问题,略
1-3:eventloop过程中,http clientfd对应的读事件处理流程
nginx.mainngx_process_cycle.ngx_master_process_cycle......unistd.fork #fork子进程......ngx_proces_cycle.ngx_worker_process_cycle #这里是子进程里面的流程1:!!!初始化eventloop(初始化+注册相关fd到eventloop)......2:!!!执行eventLoopfor ; ; #死循环,即eventloop,事件循环ngx_event.ngx_process_events_and_timers #处理事件和定时器ngx_epoll_module.ngx_epoll_process_eventsunistd.epoll_wait#本次处理clientfd read eventsngx_http_request.ngx_http_keepalive_handler #ngx_http_request.ngx_http_wait_request_handler处理新连接,这个处理旧连接#处理流程很简单,就是一个http协议解析器,先解析请求,然后再调用handler处理请求#解析过程很简单:先解析请求行,然后解析header,解析完header后调用handler处理请求#解析的过程中会从conn中取出历史数据,如果不是一个完整行,就标记,等待下一次读取#直到解析完整个请求。ngx_recv.ngx_unix_recv #c->rev,这是个函数指针,实际是ngx_unix_recv#没有数据可读取时就会返回NGX_AGAINsocket2.recv #调用linux系统调用从网络缓冲区读取数据到nginx内存缓冲区,肯定是for循环+非阻塞读取if (n == NGX_AGAIN) : #如果是NGX_AGAIN,则会把读事件重新注册到对应的监听fd中ngx_event.ngx_handle_read_event #把读事件重新注册到对应的监听fd中。因为不同os中支持的模型不同,#不同模型的处理不同,所以需要这个函数,比如如果是linxu的epoll, #就是把fd+读事件重新注册到epollfd中,如果已存在就什么也不做return #这里重新注册读事件后就返回了ngx_connection.ngx_reusable_connection #暂不清楚ngx_http_request.ngx_http_process_request_line #!!!rev->handler(),调用handler函数来处理事件#!!!再次强调,nginx通过函数指针来实现同一套#!!!eventloop代码同时可以处理http和stream请求#这里就开始解析http请求,就是状态机,一边读取一边解析for: #状态机,直到处理完请求或者没数据可读或者出错if rc == NGX_AGAIN: #不完整的一行,需要继续读取ngx_http_request.ngx_http_read_request_header #读取rc=ngx_http_request.ngx_http_parse_request_line #解析请求行,即从字节流中解析出请求行if rc=NGX_OK: ngx_http_request.ngx_http_process_request_uri #根据解析出的请求行处理uringx_http_request.ngx_http_set_virtual_server #ngx_http_request.ngx_http_process_request_headers #解析headers,和解析请求行一样的流程,边读边解析#即如果rc==NGX_AGAIN就继续读取一行,然后解析#笔记:他不是一个外置函数(ngx_http_keepalive_handler ),#然后在这个外置函数里第一步解析请求行,然后第二步解析header#而是一种尾调用的关系,即是嵌套的,即外置函数调用函数解析请求行,#然后在请求行解析函数的最后一行调用解析headers的函数,#然后在解析headers的函数最后一行又调用handler处理函数#!!!http只需要解析http头部,而data部分则是由handler来处理#因为数据部分是对用户有意义,而无关于http协议,handler就是来处理具体数据的 ngx_http_request.ngx_http_read_request_header #读取一行ngx_http_request.ngx_http_parse_header_line #解析一行if rc == NGX_OK:continue: #header有多行,所以NGX_OK表示成功解析一行if rc == NGX_HTTP_PARSE_HEADER_DONE: #NGX_HTTP_PARSE_HEADER_DONE表示请求头解析完了,就要处理请求了#这里再次说明http解析的过程就是就是一个状态机,就是边读边解析ngx_http_request.ngx_http_process_request_header #处理全部请求头ngx_http_request.ngx_http_process_request #处理完请求头后这里处理请求c->read->handler = ngx_http_request_handler; #nginx_http_request_handler就是#在收完请求头但是还没有收完整个请求之间起作用#!!!再次强调,http协议中读完请求头和请求体就可以处理请求了#!!!不必等到收到body部分,比如getc->write->handler = ngx_http_request_handler; #ngx_http_request_handler就是根据事件类型来调用对应的event_handlerif (ev->write) {r->write_event_handler(r);} else {r->read_event_handler(r);} r->read_event_handler = ngx_http_block_reading; #!!!对于同一个连接上的请求,nginx是顺序处理的,#处理一个请求nginx只会调用一次ngx_http_process_request#而nginx在处理完header后就调用ngx_http_process_request了#如果不重置clientfd的read->handler和write->handler,#那么如果还没处理完,下一个请求来了#比如tcp粘包,缓冲区数据为body+下一个request,#那么就会再次触发clientfd的读取事件,读取到下一个请求#,然后就会再次调用ngx_http_process_reqeust#我猜测(是我猜的):ngx_http_process_reqeust不是无状态的函数#导致对于同一个连接必须处理完当前请求才能继续处理下一个请求#为了避免嵌套,所以nginx选择的解决办法是:#读取到一个完整的请求头即代表开始处理一个请求后#就会重置读取写入事件的handler,来避免再次调用http_process_request,#ngx_http_request_handler只是简单地根据事件类型来#调用对应的event_handler,简单地读取、读取丢弃、或者直接不读取,#就算读取了也不会解析数据,这样也就不会再次调用http_process_reqeust,#所以我们设置对应的read_event_handler=block_reading,#block_reading:如果是边缘触发则本次调用相当于空操作即不读取任何数据#如果是水平触发,就从epoll中移除clientfd,更简单暴力#!!!注意:在当前请求的处理过程中也许会重置read_event_handelr#比如在static_handler中如果不需要请求体(比如get /index.html)#那么就会重置read_event_handler=ngx_http_discard_request_body,#就是读取body,然后丢弃bodyngx_http_core_module.ngx_http_handlerif !r->internal: #如果是外部请求,那么就要调用所有handlerr->keepalive=r->headers_in.connection_type #header中会有keepalive的设置r->phase_handler=0 #handler是一个数组,phase_handler表示当前handler的下表#phase_handler=0表示从第一个handler开始处理,#因为handler是一个接一个调用的else:r->phase_handler=server_rewrite_index #如果是内部请求(即内部的请求重定向等)则从server_rewrite_index开始#!!!就是说不必所有请求都走完http处理的所有阶段ngx_http_core_module.ngx_http_core_run_phases #循环调用phase_handler数组中的所有handler来处理请求while (ph[r->phase_handler].checker): #checker是对handler的包装,ph是phase_handler数组,#phase_handler就是数组下标#handler有好多,不过都是按顺序来的即一个handler对应一个处理步骤#这个phase_handler数组是在nginx_http_block中填充的,#默认是11个阶段14个handlerrc = ph[r->phase_handler].checker(r, &ph[r->phase_handler]) #handler处理后会自动给phase_handler+1#!!!发送响应给client这个功能是放在handler中的#这里仅仅记录发送静态页面给handler,略去了一大堆其他的handler/** ph表示phase_handler,ph是对handler的一个包装,* checker负责对handler的处理结果进行善后工作比如更新状态* 发送响应给client也算作一个handler,所以在handler中处理,handler是一个函数指针* static_handler专门用来处理静态页面,发送响应的时候也分两步,同时也是尾调用* 第一步执行filter_chain,对数据进行处理,处理完之后再执行output_chain,* output_chain内也要执行一个filter_chain,也是尾调用,* 如果没有设置写延迟,那么最终调用writev来把数据写到发送缓冲区,* 如果设置了就...暂不清楚*/ngx_http_core_module.ngx_http_core_content_phase #注意:有好几个ngx_http_core_content_phase阶段#其中一个phase阶段的handler就是ngx_http_static_handlerngx_http_static_module.ngx_http_static_handler #!!!ph->handler,此处是static_handler,负责处理静态页面 #!!!再次强调:nginx通过函数指针来模拟多态#!!!更广阔一点:c框架都是用函数指针来实现同一套代码处理不同的事件#!!!就是说框架的骨架是类型无关的,类型差异都封装在一个变量中#!!!nginx中就是eventloop骨架是描述符类型无关的(httpfd/listenfd/streamfd)#!!!这些fd的处理差异都封装在event_t结构,event_t封装在connection结构中#!!!eventloop骨架与connetion打交道即conn结构封装了不同fd事件处理的差异...deal something and get result metadata...r->read_event_handler = ngx_http_discarded_request_body_handler; ngx_http_output_filter #响应数据元信息处理好了,#这里就调用output_filter对响应数据进行处理#output_filter是一个链表,同时也是尾调用,#所以如果链表很长,那么嵌套就会很深ngx_http_range_body_filterngx_http_copy_filterngx_output_chain #outputchain也是一个filter_chain#负责对要写的数据进行处理ngx_http_trailers_filterngx_http_charset_body_filterngx_http_ssi_body_filterngx_http_postpone_filterngx_http_gzip_body_filterngx_http_chunked_body_filterngx_http_write_filterngx_linux_sendfile_chainif: #nginx会根据实际情况来决定是sendfile还是writev,因为效率不同ngx_linux_sendfilesendfile.sendfile #就是调用linux的sendfile来发送数据else:ngx_writevuio.writev #就是调用ubuntu的writev来把数据写到发送缓冲区ngx_http_request.ngx_http_finalize_request #各个http模块在执行完某个操作都需要调用这个函数,#来把请求的引用计数减去1,当引用计数为0时才会真正释放一个请求#有很多if,这里举两个:NGX_DECLINED和r->bufferedif rc == NGX_DECLINED:ngx_http_core_module.ngx_http_core_run_phases #如果此时请求所有阶段还没有处理完,#那么继续执行直到所有阶段都走完if 请求行和请求头收到了但是请求体还没收到&&请求体不可丢弃: #收完请求头后就会设置#read->handler=ngx_http_reqeust_handler#这个函数主要用来处理不能一次性读完写完的情况c->read->handler = ngx_http_request_handler;c->write->handler = ngx_http_request_handler;if r->buffered || c->buffered || r->postponed: #如果一次数据没有写完,就向epollfd中注册写事件#然后就在下一次事件循环中处理,这一点和redis一样ngx_http_request.ngx_http_set_write_handler r->http_state = NGX_HTTP_WRITING_REQUEST_STATE #所以说nginx处理http请求就是一个状态机#nginx就是通过这个状态来记录当前请求处理到哪一步了#所以即使一个请求的数据还没有全部收到#即使需要中断当前执行以待下次执行#nginx都可以正确处理r->write_event_handler = ngx_http_writer; #fd可写事件的handler。要么异步io,要么直接写发送缓冲区if wev->delayed || r->aio: #如果是延迟或者异步处理ngx_event.ngx_handle_write_eventif lowat>0: #lowat:需要低水位发送的字节数ngx_event.ngx_send_lowatif !wev->active && !wev->ready: #不一定会再次把write_event放到epollfd中ngx_epoll_module.ngx_epoll_add_event #define ngx_add_event ngx_event_actions.add#add函数实际是ngx_epoll_add_event函数#注意:它是直接初始化一个结构体来初始化actions的所有字段的epoll_ctl(add,NGX_WRITE_EVENT) #向epollfd注册写事件else:ngx_http_core_module.ngx_http_output_filter #不需要延迟处理则通过ngx_http_write就是把数据写到发送缓冲区ngx_event.ngx_handle_write_event #把event事件注册到epollfd中ngx_epoll_module.ngx_epoll_add_event epoll_ctl(add,NGX_WRITE_EVENT)ngx_http_request.ngx_http_finalize_connection #!!!这个finalize_request和#!!!finalize_connection有点乱和有些错,但无伤大雅if 请求处理完了&&keepalive==true:c->read->handler=ngx_http_keepalive_handlerelse if 请求行和请求头收到了但是请求体还没收到&&请求体可丢弃ngx_add_timer(c->read,time) #http请求收到请求行请求头后就可以开始处理了#此时read->handler=ngx_http_request_handler#ngx_add_timer是确保在指定时间内结束整个请求if rc==NGX_OK: #如果某个handler返回NGX_OK就表示请求处理结束,不再调用后面的handlerreturn ngx_http_request.ngx_http_run_posted_requests #请求处理完了,执行请求后的处理
1-3-1:ngx_http_request_handler流程
代码很简单,就直接贴源代码。反正就是对于一个请求,收完请求头之后对应的read->handler就设置成ngx_http_request_handler,一旦整个请求处理完毕,如果keepalive为false,那么该连接就会关闭,下一次新请求到来的时候就要重新走一遍accept、ngx_http_wait_request_handler,如果keepalive为true,那么连接就不会关闭,在ngx_http_finalize_request的时候就会把read->handler设置成ngx_http_keepalive_handler,该连接上的下次请求到来的时候就是走ngx_http_keepalive_handler。至于stream read流程放下了,还有ngx_read/write_event_handler的设置就暂时跳过了,还有ngx_http_finalize_request和ngx_http_finalize_connection的部分的代码流程笔记有些乱以及有些地方是错的,但是大体是对的,暂时先放下了,反正无伤大雅。因为今天还有2分钟就下班了 2024/10/25 17:58
static void
ngx_http_request_handler(ngx_event_t *ev)
{ngx_connection_t *c;ngx_http_request_t *r;c = ev->data;r = c->data;ngx_http_set_log_request(c->log, r);ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,"http run request: \"%V?%V\"", &r->uri, &r->args);if (c->close) {r->main->count++;ngx_http_terminate_request(r, 0);ngx_http_run_posted_requests(c);return;}if (ev->delayed && ev->timedout) {ev->delayed = 0;ev->timedout = 0;}if (ev->write) {r->write_event_handler(r);} else {r->read_event_handler(r); #比如对于某些不需要的请求体,直接丢弃#即此时的read_event_handler为ngx_http_discard_request_body即丢弃请求体并清除定时器}ngx_http_run_posted_requests(c);
}
相关文章:

nginx系列--(三)--http
本文主要介绍http模块accept read流程,!!!请求对应的响应直接在read流程里就会返回给用户,而不需要通过write事件,和redis一样,基本都不通过eventloop write事件来发送响应给客户端,…...

通过Wireshark抓包分析,体验HTTP请求的一次完整交互过程
目录 一、关于Wireshark 1.1、 什么是Wireshark 1.2、下载及安装 二、HTTP介绍 2.1、HTTP请求过程介绍 2.2 、TCP协议基础知识 2.2.1、概念介绍 2.2.2、TCP协议的工作原理 2.2.3、三次握手建立连接 2.3.4、四次挥手断开连接 2.3、Wireshark抓包分析过程 2.3.1、三次握…...

Requestium:Python中的Web自动化新贵
文章目录 Requestium:Python中的Web自动化新贵背景:为何选择Requestium?Requestium是什么?如何安装Requestium?简单的库函数使用方法场景应用常见Bug及解决方案总结 Requestium:Python中的Web自动化新贵 背…...

2024版红娘金媒10.3婚恋相亲系统源码小程序(亲测)
1. 红娘服务 红娘服务模块是该系统的一大特色。专业红娘会通过分析用户的个人资料和偏好, 为用户提供精准的配对建议和个性化服务。用户可以预约红娘服务,通过红娘的介入,提升配对成功率。 2. 相亲活动 相亲活动模块用于组织和管理线下或线…...

k8s-实战——ES集群部署
文章目录 yaml文件es-pvc.yamles-svc.yamles-cluster-sts.yaml创建elasticsearch集群yaml文件 es-pvc.yaml 通过nfs服务进行新增pv并通过labels关联pvc前置准备需要提前准备pv的服务器以及挂在路径--- apiVersion: v1 kind: PersistentVolume metadata:name: nfs-es-pv-data-...

无人机的就业前景怎么样?
无人机的就业前景在当前及未来一段时间内都非常广阔。随着低空经济的蓬勃发展,无人机在农业、公安、测绘、交通、应急救援、影视拍摄等多个领域得到了广泛应用,对无人机操控员和相关专业人才的需求也随之急剧增加。 一、无人机操控员的就业前景 1. 高需…...

【学习】软件测试中V模型、W模型、螺旋模型三者介绍
在软件工程的星辰大海之中,存在着三种独特的航路图:V模型、W模型以及螺旋模型。它们分别以各自的方式描绘了软件开发与测试的不同旅程。 首先映入眼帘的是V模型——一个以垂直线条贯穿始终的简洁图形。这个模型如同一座倒立的“V”字形山峰,…...

Kafka存储机制大揭秘:从日志结构到清理策略的全面解析
文章目录 一、前言二、日志存储结构1.日志文件结构2.topic3.partition4.segment索引文件5.message结构6.message查找过程 三、存储策略1.顺序写2.页缓存3.零拷贝4.缓存机制 四、日志格式演变1.V0 版本2.V1 版本3.V0/V1消息集合4.V2 版本消息格式5.V2版本消息集合 五、偏移量维护…...

显卡服务器和普通服务器之间的区别有哪些?
显卡服务器也被称之为GPU服务器,显卡服务器与普通的服务器之间有着很明显的区别,下面就让我们共同来了解一下吧! 普通服务器的主要处理器通常都是配备的中央处理器,可以用于执行大部分通用计算任务和操作系统的管理;而…...

国产科技里程碑:自主算力走向世界,“表格编程”横空出世
近日,中国高科技领域迎来里程碑式的进展。 据安徽省量子计算工程研究中心官方消息,本源量子计算科技(合肥)股份有限公司(简称“本源量子”)成功向海外销售了其第三代自主超导量子计算机“本源悟空”的机时。…...

人工智能如何改变未来生活:从医疗到日常的全面升级
人工智能如何改变未来生活:从医疗到日常的全面升级 随着人工智能(AI)技术的进步,我们正逐渐看到它为各行各业带来的巨大变革。从医疗、企业到日常生活,AI通过简化流程、提高效率,甚至改善生活质量…...

第112届全国糖酒会(3月成都)正式官宣!
作为食品饮料行业内备受瞩目的年度盛事,全国糖酒商品交易会(简称“糖酒会”)一直是各大厂商与经销商展现企业风采、寻觅合作伙伴及签署订单的关键舞台。2024年10月31日,第111届全国糖酒商品交易会(秋糖)在深…...

NFT Insider #154:The Sandbox Alpha 4 第四周开启,NBA Topshot NFT 销量激增至新高
市场数据 加密艺术及收藏品新闻 NBA 赛季开幕推动 Topshot NFT 销量激增至新高 随着波士顿凯尔特人队和纽约尼克斯队在 10 月 22 日开启 2024-2025 NBA 赛季的序幕,NBA Topshot 的 NFT 销售量达到了自上赛季季后赛以来的最高水平。截止到 10 月 27 日的这一周&…...

【Canal 中间件】Canal 实现 MySQL 增量数据的异步缓存更新
文章目录 一、安装 MySQL1.1 启动 mysql 服务器1.2 开启 Binlog 写入功能1.2.1创建 binlog 配置文件1.2.2 修改配置文件权限1.2.3 挂载配置文件1.2.4 检测 binlog 配置是否成功 1.3 创建账户并授权 二、安装 RocketMQ2.1 创建容器共享网络2.2 启动 NameServer2.3 启动 Broker2.…...

独立开发的个人品牌打造:个人IP与独立开发的结合
引言 个人品牌程序员也需要打造。在当今的创意经济中,个人IP与独立开发的结合成为了一种趋势,为个体带来了前所未有的机会和可能性。本文将探讨如何通过打造个人IP来增强独立开发的影响力,并探索这种结合为个人带来的潜在价值。 个人IP的重…...
每天一题:洛谷P2002 消息扩散
题目背景 本场比赛第一题,给个简单的吧,这 100 分先拿着。 题目描述 有 n 个城市,中间有单向道路连接,消息会沿着道路扩散,现在给出 n 个城市及其之间的道路,问至少需要在几个城市发布消息才能让这所有 …...

【深度学习】用LSTM写诗,生成式的方式写诗系列之一
Epoch 4: 100%|███████████████████████████████████████████████████████████| 63/63 [00:07<00:00, 8.85batch/s, acc18.5, loss5.8] [5] loss: 5.828, accuracy: 18.389 , lr:0.001000 Epoch 5: 100%|███…...

HomeAssistant自定义组件学习-【二】
#要说的话# 前面把中盛科技的控制器组件写完了。稍稍熟悉了一些HA,现在准备写窗帘控制组件,构想的东西会比较多,估计有些难度,过程会比较长,边写边记录吧! #设备和场景环境# 使用的是Novo的电机…...

如何看待AI技术的应用前景?
文章目录 如何看待AI技术的应用前景引言AI技术的现状1. AI的定义与分类2. 当前AI技术的应用领域 AI技术的应用前景1. 经济效益2. 社会影响3. 技术进步 AI技术应用面临的挑战1. 数据隐私与安全2. 可解释性与信任3. 技能短缺与就业影响 AI技术的未来发展方向1. 人工智能的伦理与法…...

Unity中的屏幕坐标系
获得视口宽高 拖动视口会改变屏幕宽高数值 MousePosition 屏幕坐标系的原点在左下角,MousePosition返回Z为0也就是纵深为0的Vector3 但是如果鼠标超出屏幕范围不会做限制,所以可能出现负数或者大于屏幕宽高的情况,做鼠标拖拽物体时需要注…...

标题点击可跳转网页
要实现点击标题跳转到网页的功能,你可以在Vue组件中使用<a>标签(锚点标签)并设置href属性为网页的URL。如果你希望使用uni-app的特性来控制页面跳转,可以使用uni.navigateTo方法(这适用于uni-app环境,…...

易语言模拟真人动态生成鼠标滑动路径
一.简介 鼠标轨迹算法是一种模拟人类鼠标操作的程序,它能够模拟出自然而真实的鼠标移动路径。 鼠标轨迹算法的底层实现采用C/C语言,原因在于C/C提供了高性能的执行能力和直接访问操作系统底层资源的能力。 鼠标轨迹算法具有以下优势: 模拟…...

Linux:生态与软件安装
文章目录 前言一、Linux下安装软件的方案二、包管理器是什么?三、生态问题相关的理解1. 什么操作系统是好的操作系统?2. 什么是生态?3. 软件包是谁写的?这些工程师为什么要写?钱的问题怎么解决? 四、我的服务器怎么知…...

R 语言与其他编程语言的区别
R 语言与其他编程语言的区别 R 语言作为一种专门用于统计计算和图形的编程语言,与其他编程语言相比有一些独特的特点和区别。本文将详细介绍这些区别,帮助你更好地理解 R 语言的优势和适用场景。 1. 专为统计和数据分析设计 统计功能 内置统计函数&…...

RC低通滤波器Bode图分析(传递函数零极点)
RC低通滤波器 我们使得R1K,C1uF;电容C的阻抗为Xc; 传递函数 H ( s ) u o u i X C X C R 1 s C 1 s C R 1 1 s R C (其中 s j ω ) H(s)\frac{u_{o} }{u_{i} } \frac{X_{C} }{X_{C}R} \frac{\frac{1}{sC} }{\…...

基于深度学习的网络入侵检测
基于深度学习的网络入侵检测是一种利用深度学习技术对网络流量进行实时监测与分析的方法,旨在识别并防范网络攻击和恶意活动。随着网络环境日益复杂,传统的入侵检测系统(IDS)在面对不断变化的攻击模式时,往往难以保持高…...

《构建一个具备从后端数据库获取数据并再前端显示的内容页面:前后端实现解析》
一、前端页面:布局与功能 1. 页面结构 我们先来看前端页面的 HTML 结构,它主要由以下几个部分组成: <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewp…...

Rust 力扣 - 59. 螺旋矩阵 II
文章目录 题目描述题解思路题解代码题目链接 题目描述 题解思路 使用一个全局变量current记录当前遍历到的元素的值 我们只需要一圈一圈的从外向内遍历矩阵,每一圈遍历顺序为上边、右边、下边、左边,每遍历完一个元素后current 我们需要注意的是如果上…...

2.4w字 —TS入门教程
目录 1. 什么是TS 2. TS基本使用 3 TS基础语法 3.1 基础类型约束 3.11 string,number,boolean, null和undefined 3.12 any 3.13 unknown 3.14 void 3.15 数组 3.16 对象 3.2 函数的约束 3.21 普通写法 3.22 函数表达式 3.22 可选…...

java: 未结束的字符文字 报错及解决:将编码全部改为UTF-8或者GBK
报错: 解决: 将编码都改成UTF-8或者GBK:...