nginx對埠的處理 -- 第三篇

鄭爾多斯發表於2018-12-08

微信公眾號:鄭爾多斯
關注可瞭解更多的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, log0,
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, log0,
256                      "try again to bind() after 500ms");
257
258        ngx_msleep(500);
259    }
260
261    if (failed) {
262        ngx_log_error(NGX_LOG_EMERG, log0"still could not bind()");
263        return NGX_ERROR;
264    }
265
266    return NGX_OK;
267}
複製程式碼

這個函式的功能很簡單,就是開啟socket,然後bind,然後listen,僅此而已,通過這個函式,我麼已經對這個埠和IP地址進行了listen,當有新的連線的時候,就會accept新的連線。
記憶體佈局如下:

記憶體佈局
記憶體佈局

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

鄭爾多斯
鄭爾多斯

相關文章