nginx對埠的處理 -- 第三篇
阿新 • • 發佈:2018-12-26
微信公眾號:鄭爾多斯
關注可瞭解更多的Nginx知識。任何問題或建議,請公眾號留言;
關注公眾號,有趣有內涵的文章第一時間送達!ngx_open_listening_sockets
1ngx_int_t 2ngx_open_listening_sockets(ngx_cycle_t *cycle) 3{ 4 int reuseaddr; 5 ngx_uint_t i, tries, failed; 6 ngx_err_t err; 7 ngx_log_t *log; 8 ngx_socket_t s; 9 ngx_listening_t *ls; 10 11 reuseaddr = 1; 12#if (NGX_SUPPRESS_WARN) 13 failed = 0; 14#endif 15 16 log = cycle->log; 17 18 /* TODO: configurable try number */ 19 20 for (tries = 5; tries; tries--) { 21 failed = 0; 22 23 /* for each listening socket */ 24 25 ls = cycle->listening.elts; 26 for (i = 0; i < cycle->listening.nelts; i++) { 27 28 if (ls[i].ignore) { 29 continue; 30 } 31 32#if (NGX_HAVE_REUSEPORT) 33 34 if (ls[i].add_reuseport) { 35 36 /* 37 * to allow transition from a socket without SO_REUSEPORT 38 * to multiple sockets with SO_REUSEPORT, we have to set 39 * SO_REUSEPORT on the old socket before opening new ones 40 */ 41 42 int reuseport = 1; 43 44 if (setsockopt(ls[i].fd, SOL_SOCKET, SO_REUSEPORT, 45 (const void *) &reuseport, sizeof(int)) 46 == -1) 47 { 48 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, 49 "setsockopt(SO_REUSEPORT) %V failed, ignored", 50 &ls[i].addr_text); 51 } 52 53 ls[i].add_reuseport = 0; 54 } 55#endif 56 57 if (ls[i].fd != (ngx_socket_t) -1) { 58 continue; 59 } 60 61 if (ls[i].inherited) { 62 63 /* TODO: close on exit */ 64 /* TODO: nonblocking */ 65 /* TODO: deferred accept */ 66 67 continue; 68 } 69 70 s = ngx_socket(ls[i].sockaddr->sa_family, ls[i].type, 0); 71 72 if (s == (ngx_socket_t) -1) { 73 ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, 74 ngx_socket_n " %V failed", &ls[i].addr_text); 75 return NGX_ERROR; 76 } 77 78 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, 79 (const void *) &reuseaddr, sizeof(int)) 80 == -1) 81 { 82 ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, 83 "setsockopt(SO_REUSEADDR) %V failed", 84 &ls[i].addr_text); 85 86 if (ngx_close_socket(s) == -1) { 87 ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, 88 ngx_close_socket_n " %V failed", 89 &ls[i].addr_text); 90 } 91 92 return NGX_ERROR; 93 } 94 95#if (NGX_HAVE_REUSEPORT) 96 97 if (ls[i].reuseport && !ngx_test_config) { 98 int reuseport; 99 100 reuseport = 1; 101 102 if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, 103 (const void *) &reuseport, sizeof(int)) 104 == -1) 105 { 106 ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, 107 "setsockopt(SO_REUSEPORT) %V failed", 108 &ls[i].addr_text); 109 110 if (ngx_close_socket(s) == -1) { 111 ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, 112 ngx_close_socket_n " %V failed", 113 &ls[i].addr_text); 114 } 115 116 return NGX_ERROR; 117 } 118 } 119#endif 120 121#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) 122 123 if (ls[i].sockaddr->sa_family == AF_INET6) { 124 int ipv6only; 125 126 ipv6only = ls[i].ipv6only; 127 128 if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, 129 (const void *) &ipv6only, sizeof(int)) 130 == -1) 131 { 132 ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, 133 "setsockopt(IPV6_V6ONLY) %V failed, ignored", 134 &ls[i].addr_text); 135 } 136 } 137#endif 138 /* TODO: close on exit */ 139 140 if (!(ngx_event_flags & NGX_USE_IOCP_EVENT)) { 141 if (ngx_nonblocking(s) == -1) { 142 ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, 143 ngx_nonblocking_n " %V failed", 144 &ls[i].addr_text); 145 146 if (ngx_close_socket(s) == -1) { 147 ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, 148 ngx_close_socket_n " %V failed", 149 &ls[i].addr_text); 150 } 151 152 return NGX_ERROR; 153 } 154 } 155 156 ngx_log_debug2(NGX_LOG_DEBUG_CORE, log, 0, 157 "bind() %V #%d ", &ls[i].addr_text, s); 158 159 if (bind(s, ls[i].sockaddr, ls[i].socklen) == -1) { 160 err = ngx_socket_errno; 161 162 if (err != NGX_EADDRINUSE || !ngx_test_config) { 163 ngx_log_error(NGX_LOG_EMERG, log, err, 164 "bind() to %V failed", &ls[i].addr_text); 165 } 166 167 if (ngx_close_socket(s) == -1) { 168 ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, 169 ngx_close_socket_n " %V failed", 170 &ls[i].addr_text); 171 } 172 173 if (err != NGX_EADDRINUSE) { 174 return NGX_ERROR; 175 } 176 177 if (!ngx_test_config) { 178 failed = 1; 179 } 180 181 continue; 182 } 183 184#if (NGX_HAVE_UNIX_DOMAIN) 185 186 if (ls[i].sockaddr->sa_family == AF_UNIX) { 187 mode_t mode; 188 u_char *name; 189 190 name = ls[i].addr_text.data + sizeof("unix:") - 1; 191 mode = (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); 192 193 if (chmod((char *) name, mode) == -1) { 194 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, 195 "chmod() \"%s\" failed", name); 196 } 197 198 if (ngx_test_config) { 199 if (ngx_delete_file(name) == NGX_FILE_ERROR) { 200 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, 201 ngx_delete_file_n " %s failed", name); 202 } 203 } 204 } 205#endif 206 207 if (ls[i].type != SOCK_STREAM) { 208 ls[i].fd = s; 209 continue; 210 } 211 212 if (listen(s, ls[i].backlog) == -1) { 213 err = ngx_socket_errno; 214 215 /* 216 * on OpenVZ after suspend/resume EADDRINUSE 217 * may be returned by listen() instead of bind(), see 218 * https://bugzilla.openvz.org/show_bug.cgi?id=2470 219 */ 220 221 if (err != NGX_EADDRINUSE || !ngx_test_config) { 222 ngx_log_error(NGX_LOG_EMERG, log, err, 223 "listen() to %V, backlog %d failed", 224 &ls[i].addr_text, ls[i].backlog); 225 } 226 227 if (ngx_close_socket(s) == -1) { 228 ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, 229 ngx_close_socket_n " %V failed", 230 &ls[i].addr_text); 231 } 232 233 if (err != NGX_EADDRINUSE) { 234 return NGX_ERROR; 235 } 236 237 if (!ngx_test_config) { 238 failed = 1; 239 } 240 241 continue; 242 } 243 244 ls[i].listen = 1; 245 246 ls[i].fd = s; 247 } 248 249 if (!failed) { 250 break; 251 } 252 253 /* TODO: delay configurable */ 254 255 ngx_log_error(NGX_LOG_NOTICE, log, 0, 256 "try again to bind() after 500ms"); 257 258 ngx_msleep(500); 259 } 260 261 if (failed) { 262 ngx_log_error(NGX_LOG_EMERG, log, 0, "still could not bind()"); 263 return NGX_ERROR; 264 } 265 266 return NGX_OK; 267}
這個函式的功能很簡單,就是開啟socket,然後bind,然後listen,僅此而已,通過這個函式,我麼已經對這個埠和IP地址進行了listen,當有新的連線的時候,就會accept新的連線。
記憶體佈局
記憶體佈局如下:
喜歡本文的朋友們,歡迎長按下圖關注訂閱號鄭爾多斯,更多精彩內容第一時間送達
鄭爾多斯