root@ubuntu:~/nginx-1.16.1# ps -elf | grep nginx 1 S root 2739 1 0 80 0 - 2265 sigsus 20:09 ? 00:00:00 nginx: master process ./objs/nginx -c conf/nginx.conf 5 S root 2740 2739 0 80 0 - 2468 ep_pol 20:09 ? 00:00:00 nginx: worker process 0 S root 3492 41645 0 80 0 - 1096 pipe_w 20:11 pts/2 00:00:00 grep nginx root@ubuntu:~/nginx-1.16.1#
gdb attach worker进程
root@ubuntu:~# gdb attach 2740 GNU gdb (Ubuntu 8.1-0ubuntu3.2) 8.1.0.20180409-git Copyright (C) 2018 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details.
(gdb) b ngx_quic_read_handler Breakpoint 1 at 0xaaaae2e9bd64: file src/event/ngx_event_quic.c, line 229. (gdb) c Continuing. Breakpoint 1, ngx_quic_read_handler (rev=0xaaab145576f0) at src/event/ngx_event_quic.c:229 229 { (gdb) bt #0 ngx_quic_read_handler (rev=0xaaab145576f0) at src/event/ngx_event_quic.c:229 #1 0x0000aaaae2e8af78 in ngx_event_recvmsg (ev=0xaaab145575d0) at src/event/ngx_event_udp.c:263 #2 0x0000aaaae2e93a40 in ngx_epoll_process_events (cycle=<optimized out>, timer=<optimized out>, flags=1) at src/event/modules/ngx_epoll_module.c:902 #3 0x0000aaaae2e89a44 in ngx_process_events_and_timers (cycle=cycle@entry=0xaaab1452f8e0) at src/event/ngx_event.c:242 #4 0x0000aaaae2e91a04 in ngx_worker_process_cycle (cycle=0xaaab1452f8e0, data=<optimized out>) at src/os/unix/ngx_process_cycle.c:750 #5 0x0000aaaae2e8fd68 in ngx_spawn_process (cycle=cycle@entry=0xaaab1452f8e0, proc=proc@entry=0xaaaae2e91964 <ngx_worker_process_cycle>, data=data@entry=0x0, name=name@entry=0xaaaae31a5408 "worker process", respawn=respawn@entry=-3) at src/os/unix/ngx_process.c:199 #6 0x0000aaaae2e910a0 in ngx_start_worker_processes (cycle=cycle@entry=0xaaab1452f8e0, n=1, type=type@entry=-3) at src/os/unix/ngx_process_cycle.c:359 #7 0x0000aaaae2e92258 in ngx_master_process_cycle (cycle=0xaaab1452f8e0) at src/os/unix/ngx_process_cycle.c:131 #8 0x0000aaaae2e69d78 in main (argc=0, argv=<optimized out>) at src/core/nginx.c:382 (gdb) clearall Undefined command: "clearall". Try "help". (gdb) dis b (gdb) break info Function "info" not defined. Make breakpoint pending on future shared library load? (y or [n]) Quit (gdb) quit A debugging session is active. Inferior 1 [process 2740] will be detached. Quit anyway? (y or n) y Detaching from program: /root/nginx-1.16.1/objs/nginx, process 2740 root@ubuntu:~#
ngx_event_recvmsg
通过我们知道ngx_event_core_module模块的init_process函数ngx_event_process_init()会为每个监听套接字的读事件注册处理函数ngx_event_accept(TCP)或者ngx_event_recvmsg(UDP)
static ngx_int_t ngx_event_process_init(ngx_cycle_t *cycle) { …… ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { //对每个监听描述符创建一个对应的connection对象,封装了描述符fd c = ngx_get_connection(ls[i].fd, cycle->log); //拿到监听描述符的读事件 rev = c->read; //表示accept新连接 rev->accept = 1; //读事件的hander,type为流时走tcp的accept,否则直接走udp的recvmsg rev->handler = (c->type == SOCK_STREAM) ? ngx_event_accept : ngx_event_recvmsg; //将读事件添加到IO多路复用模型中,当采用epoll模型时ngx_add_event就是ngx_epoll_add_event //udp,当事件触发时会调用ngx_event_recvmsg if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } } }
ngx_event_recvmsg
udp读事件的handler函数ngx_event_recvmsg:
// src/event/ngx_event_udp.c void ngx_event_recvmsg(ngx_event_t *ev){ struct msghdr msg; struct iovec iov[1]; struct msghdr msg; ngx_buf_t buf; static u_char buffer[65535]; //静态读缓冲区 …… lc = ev->data; ls = lc->listening; do { ngx_memzero(&msg, sizeof(struct msghdr)); iov[0].iov_base = (void *) buffer; iov[0].iov_len = sizeof(buffer); …… msg.msg_iov = iov; msg.msg_iovlen = 1; //读取报文,读出的数据存放在iov[0].iov_base也即是buffer中 n = recvmsg(lc->fd, &msg, 0); //拿到源ip和源端口 sockaddr = msg.msg_name; socklen = msg.msg_namelen; //本地监听目的地址和端口 local_sockaddr = ls->sockaddr; local_socklen = ls->socklen; //ls代带有一个存放连接的红黑树,从红黑树找是否已经有相同四元组的连接 c = ngx_lookup_udp_connection(ls, sockaddr, socklen, local_sockaddr, local_socklen); if (c) { …… ngx_memzero(&buf, sizeof(ngx_buf_t)); buf.pos = buffer; buf.last = buffer + n; //找到则调用读事件的handler处理数据读取事件 rev = c->read; //最终,c->udp->buffer指向了读取的数据缓冲区 c->udp->buffer = &buf; rev->ready = 1; //ready为1,后面会用到 //此时handler为ngx_stream_session_handler@src/stream/ngx_stream_handler.c rev->handler(rev); if (c->udp) { c->udp->buffer = NULL; } rev->ready = 0; goto next; } //找不到则新建一个connection对象 c = ngx_get_connection(lc->fd, ev->log); if (c == NULL) { return; } c->shared = 1; c->type = SOCK_DGRAM; c->socklen = socklen; …… //将本次读到的缓冲区buffer中的数据拷贝追加到临时缓冲区c->buffer后面 c->buffer = ngx_create_temp_buf(c->pool, n); c->buffer->last = ngx_cpymem(c->buffer->last, buffer, n); //设置连接的recv和send操作函数 //ngx_udp_shared_recv是直接从c->udp->buffer拷贝出数据 c->recv = ngx_udp_shared_recv; c->send = ngx_udp_send; c->send_chain = ngx_udp_send_chain; //将新的对象插入到管理连接的红黑树中 if (ngx_insert_udp_connection(c) != NGX_OK) { ngx_close_accepted_udp_connection(c); return; } //调用监听handler处理新连接事件, //此时handler为ngx_stream_init_connection@src/stream/ngx_stream_handler.c ls->handler(c); next: if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { ev->available -= n; } } while (ev->available); }
RUST_LOG="debug" ./target/debug/examples/http3-client https://10.10.16.82:443

(gdb) p ls $3 = (ngx_listening_t *) 0xaaab1452ff90 (gdb) p *ls $4 = {fd = 6, sockaddr = 0xaaab1454e020, socklen = 16, addr_text_max_len = 15, addr_text = {len = 11, data = 0xaaab1454e030 "0.0.0.0:443"}, type = 2, backlog = 511, rcvbuf = -1, sndbuf = -1, keepidle = 0, keepintvl = 0, keepcnt = 0, handler = 0xaaaae2ea942c <ngx_http_init_connection>, servers = 0xaaab1454e040, log = {log_level = 4, file = 0xaaab1452fc38, connection = 0, disk_full_time = 0, handler = 0x0, data = 0x0, writer = 0x0, wdata = 0x0, action = 0x0, next = 0x0}, logp = 0xaaab1452f8f8, pool_size = 512, post_accept_buffer_size = 0, post_accept_timeout = 60000, previous = 0x0, connection = 0xffffac7d8010, rbtree = {root = 0xaaab14530088, sentinel = 0xaaab14530088, insert = 0xaaaae2e8b380 <ngx_udp_rbtree_insert_value>}, sentinel = {key = 0, left = 0x0, right = 0x0, parent = 0x0, color = 0 '