1. 程式人生 > >nginx對埠的處理 -- 第三篇

nginx對埠的處理 -- 第三篇

微信公眾號:鄭爾多斯
關注可瞭解更多的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新的連線。
記憶體佈局如下:

記憶體佈局

記憶體佈局

喜歡本文的朋友們,歡迎長按下圖關注訂閱號鄭爾多斯,更多精彩內容第一時間送達

鄭爾多斯

鄭爾多斯