http代理阅读2
向上游服务器发送请求处理
static void ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u, ngx_uint_t do_write) //向上游服务器发送请求 当一次发送不完,通过ngx_http_upstream_send_request_handler再次触发发送 { ngx_int_t rc; ngx_connection_t *c; c = u->peer.connection; //向上游服务器的连接信息 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http upstream send request"); if (u->state->connect_time == (ngx_msec_t) -1) {//更新upstream 连接时间耗费状态信息 u->state->connect_time = ngx_current_msec - u->state->response_time; } /*通过getsockopt测试与上游服务器的tcp连接是否异常 * BSDs and Linux return 0 and set a pending error in err * Solaris returns -1 and sets errno if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void *) &err, &len) == -1)*/ if (!u->request_sent && ngx_http_upstream_test_connect(c) != NGX_OK) { //测试连接失败 ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);//如果测试失败,调用ngx_http_upstream_next函数,这个函数可能再次调用peer.get调用别的连接。 return; } c->log->action = "sending request to upstream"; rc = ngx_http_upstream_send_request_body(r, u, do_write); if (rc == NGX_ERROR) { /* 若返回值rc=NGX_ERROR,表示当前连接上出错, 将错误信息传递给ngx_http_upstream_next方法, 该方法根据错误信息决定 是否重新向上游其他服务器发起连接; 并return从当前函数返回; */ ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR); return; } if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {//满足http错误状态码条件 结束请求 同时响应结果到请求端 ngx_http_upstream_finalize_request(r, u, rc); return; } /* 若返回值rc = NGX_AGAIN,表示请求数据并未完全发送, 即有剩余的请求数据保存在output中,但此时,写事件已经不可写, 则调用ngx_add_timer方法把当前连接上的写事件添加到定时器机制, 并调用ngx_handle_write_event方法将写事件注册到epoll事件机制中; */ //通过ngx_http_upstream_read_request_handler进行再次epoll write if (rc == NGX_AGAIN) {//协议栈缓冲区已满,需要等待发送数据出去后出发epoll可写,从而继续write if (!c->write->ready) { //这里加定时器的原因是,例如我把数据扔到协议栈了,并且协议栈已经满了,但是对方就是不接受数据,造成数据一直在协议栈缓存中 //因此只要数据发送出去,就会触发epoll继续写,从而在下面两行删除写超时定时器 ngx_add_timer(c->write, u->conf->send_timeout, NGX_FUNC_LINE); //如果超时会执行ngx_http_upstream_send_request_handler,这里面对写超时进行处理 } else if (c->write->timer_set) { //例如ngx_http_upstream_send_request_body发送了三次返回NGX_AGAIN,那么第二次就需要把第一次上面的超时定时器关了,表示发送正常 ngx_del_timer(c->write, NGX_FUNC_LINE); } //在连接后端服务器conncet前,有设置ngx_add_conn,里面已经将fd添加到了读写事件中,因此这里实际上只是简单执行下ngx_send_lowat if (ngx_handle_write_event(c->write, u->conf->send_lowat, NGX_FUNC_LINE) != NGX_OK) { ngx_http_upstream_finalize_request(r, u, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } return; } /* rc == NGX_OK */ //向后端的数据发送完毕 //当发往后端服务器的数据包过大,需要分多次发送的时候,在上面的if (rc == NGX_AGAIN)中会添加定时器来触发发送,如果协议栈一直不发送数据出去 //就会超时,如果数据最终全部发送出去则需要为最后一次time_write添加删除操作。 //如果发往后端的数据长度后小,则一般不会再上门添加定时器,这里的timer_set肯定为0,所以如果拔掉后端网线,通过ngx_http_upstream_test_connect //是判断不出后端服务器掉线的,上面的ngx_http_upstream_send_request_body还是会返回成功的,所以这里有个bug if (c->write->timer_set) { //这里的定时器是ngx_http_upstream_connect中connect返回NGX_AGAIN的时候添加的定时器 /* 2025/04/24 02:54:29[ ngx_event_connect_peer, 32] [debug] 14867#14867: *1 socket 12 2025/04/24 02:54:29[ ngx_epoll_add_connection, 1486] [debug] 14867#14867: *1 epoll add connection: fd:12 ev:80002005 2025/04/24 02:54:29[ ngx_event_connect_peer, 125] [debug] 14867#14867: *1 connect to 127.0.0.1:3666, fd:12 #2 2025/04/24 02:54:29[ ngx_http_upstream_connect, 1549] [debug] 14867#14867: *1 http upstream connect: -2 //返回NGX_AGAIN 2025/04/24 02:54:29[ ngx_event_add_timer, 88] [debug] 14867#14867: *1 <ngx_http_upstream_connect, 1665> event timer add: 12: 60000:1677807811 //这里添加 2025/04/24 02:54:29[ ngx_http_finalize_request, 2526] [debug] 14867#14867: *1 http finalize request: -4, "/test.php?" a:1, c:2 2025/04/24 02:54:29[ ngx_http_close_request, 3789] [debug] 14867#14867: *1 http request count:2 blk:0 2025/04/24 02:54:29[ ngx_worker_process_cycle, 1110] [debug] 14867#14867: worker(14867) cycle again 2025/04/24 02:54:29[ ngx_trylock_accept_mutex, 405] [debug] 14867#14867: accept mutex locked 2025/04/24 02:54:29[ ngx_epoll_process_events, 1614] [debug] 14867#14867: begin to epoll_wait, epoll timer: 60000 2025/04/24 02:54:29[ ngx_epoll_process_events, 1699] [debug] 14867#14867: epoll: fd:11 epoll-out(ev:0004) d:B27440E8 2025/04/24 02:54:29[ ngx_epoll_process_events, 1772] [debug] 14867#14867: *1 post event AEB44068 2025/04/24 02:54:29[ ngx_epoll_process_events, 1699] [debug] 14867#14867: epoll: fd:12 epoll-out(ev:0004) d:B2744158 2025/04/24 02:54:29[ ngx_epoll_process_events, 1772] [debug] 14867#14867: *1 post event AEB44098 2025/04/24 02:54:29[ ngx_process_events_and_timers, 371] [debug] 14867#14867: epoll_wait timer range(delta): 2 2025/04/24 02:54:29[ ngx_event_process_posted, 65] [debug] 14867#14867: posted event AEB44068 2025/04/24 02:54:29[ ngx_event_process_posted, 67] [debug] 14867#14867: *1 delete posted event AEB44068 2025/04/24 02:54:29[ ngx_http_request_handler, 2400] [debug] 14867#14867: *1 http run request: "/test.php?" 2025/04/24 02:54:29[ngx_http_upstream_check_broken_connection, 1335] [debug] 14867#14867: *1 http upstream check client, write event:1, "/test.php" 2025/04/24 02:54:29[ngx_http_upstream_check_broken_connection, 1458] [debug] 14867#14867: *1 http upstream recv(): -1 (11: Resource temporarily unavailable) 2025/04/24 02:54:29[ ngx_event_process_posted, 65] [debug] 14867#14867: posted event AEB44098 2025/04/24 02:54:29[ ngx_event_process_posted, 67] [debug] 14867#14867: *1 delete posted event AEB44098 2025/04/24 02:54:29[ ngx_http_upstream_handler, 1295] [debug] 14867#14867: *1 http upstream request: "/test.php?" 2025/04/24 02:54:29[ngx_http_upstream_send_request_handler, 2210] [debug] 14867#14867: *1 http upstream send request handler 2025/04/24 02:54:29[ ngx_http_upstream_send_request, 2007] [debug] 14867#14867: *1 http upstream send request 2025/04/24 02:54:29[ngx_http_upstream_send_request_body, 2095] [debug] 14867#14867: *1 http upstream send request body 2025/04/24 02:54:29[ ngx_chain_writer, 690] [debug] 14867#14867: *1 chain writer buf fl:0 s:968 2025/04/24 02:54:29[ ngx_chain_writer, 704] [debug] 14867#14867: *1 chain writer in: 080EC838 2025/04/24 02:54:29[ ngx_writev, 192] [debug] 14867#14867: *1 writev: 968 of 968 2025/04/24 02:54:29[ ngx_chain_writer, 740] [debug] 14867#14867: *1 chain writer out: 00000000 2025/04/24 02:54:29[ ngx_event_del_timer, 39] [debug] 14867#14867: *1 <ngx_http_upstream_send_request, 2052> event timer del: 12: 1677807811//这里删除 2025/04/24 02:54:29[ ngx_event_add_timer, 88] [debug] 14867#14867: *1 <ngx_http_upstream_send_request, 2075> event timer add: 12: 60000:1677807813 */ ngx_del_timer(c->write, NGX_FUNC_LINE); } /* 若返回值 rc = NGX_OK,表示已经发送完全部请求数据, 准备接收来自上游服务器的响应报文,则执行以下程序; */ if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) { if (ngx_tcp_push(c->fd) == NGX_ERROR) { ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno, ngx_tcp_push_n " failed"); ngx_http_upstream_finalize_request(r, u, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } c->tcp_nopush = NGX_TCP_NOPUSH_UNSET; } u->write_event_handler = ngx_http_upstream_dummy_handler; //数据已经在前面全部发往后端服务器了,所以不需要再做写处理 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "send out chain data to uppeer server OK"); //在连接后端服务器conncet前,有设置ngx_add_conn,里面已经将fd添加到了读写事件中,因此这里实际上只是简单执行下ngx_send_lowat if (ngx_handle_write_event(c->write, 0, NGX_FUNC_LINE) != NGX_OK) { ngx_http_upstream_finalize_request(r, u, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } //这回数据已经发送了,可以准备接收了,设置接收后端应答的超时定时器。 /* 该定时器在收到后端应答数据后删除,见ngx_event_pipe if (rev->timer_set) { ngx_del_timer(rev, NGX_FUNC_LINE); } */ ngx_add_timer(c->read, u->conf->read_timeout, NGX_FUNC_LINE); //如果超时在该函数检测ngx_http_upstream_process_header if (c->read->ready) { //读事件触发 准备处理http头部信息---此时c 表示链接上游服务器的connect可读,也就是上游服务器回复了响应报文 ngx_http_upstream_process_header(r, u); return; } }
http代理服务器(3-4-7层代理)-网络事件库公共组件、内核kernel驱动 摄像头驱动 tcpip网络协议栈、netfilter、bridge 好像看过!!!!
但行好事 莫问前程
--身高体重180的胖子
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!