nginx에서 Listen 명령을 사용하는 방법

WBOY
풀어 주다: 2023-05-14 18:37:14
앞으로
2063명이 탐색했습니다.

listen command

nginx는 고성능 http 서버이며 네트워크 처리가 핵심입니다. 네트워크 초기화를 이해하면 nginx 네트워크 처리에 대한 이해가 깊어집니다. 두 가지 주요 네트워크 관련 구성 명령이 있습니다: Listen 및 sever_name. Listen 명령은 nginx 수신 주소를 설정합니다. IP 프로토콜의 경우 이 주소는 주소 및 포트입니다. Unix 도메인 소켓 프로토콜의 경우 이 주소는 경로입니다. 주소는 하나만 지정할 수 있습니다. 호스트 이름이 되세요

이번 글부터 Listen 명령어의 구문 분석 과정을 분석해 보겠습니다. Listen 명령어의 구성은 다음과 같습니다. nginx.org 매뉴얼에서 Listen 사용법을 확인할 수 있습니다.

listen address[:port] [default_server] [setfib=number] [backlog=number] [rcvbuf=size] [sndbuf=size] [accept_filter=filter] [deferred] [bind] [ipv6only=on|off] [ssl] [so_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt]];
로그인 후 복사

The 듣기 명령어가 전달하는 매개변수는 매우 복잡합니다. 그러나 일반적으로 덜 일반적으로 사용되는 매개변수에는 거의 주의를 기울이지 않습니다. 다음은 일반적으로 사용되는 몇 가지 구성 방법입니다.

listen 127.0.0.1:8000;
listen 127.0.0.1 不加端口,默认监听80端口;
listen 8000
listen *:8000
listen localhost:8000
로그인 후 복사

listen 명령에서 uri 및 포트 구문 분석

위 내용에서 알 수 있듯이 Listen에는 많은 용도가 있습니다. 구문 분석할 때 수신 명령의 포트 번호와 uri 부분을 가져와야 합니다. nginx는 수신 명령을 구문 분석할 때 ngx_parse_url() 메서드를 제공합니다.

ngx_int_t
ngx_parse_url(ngx_pool_t *pool, ngx_url_t *u)
{
 u_char *p;
 size_t len;

 p = u->url.data;
 len = u->url.len;
 // 这里是解析unix domain的协议
 if (len >= 5 && ngx_strncasecmp(p, (u_char *) "unix:", 5) == 0) {
 return ngx_parse_unix_domain_url(pool, u);
 }
 // 解析ipv6协议
 if (len && p[0] == '[') {
 return ngx_parse_inet6_url(pool, u);
 }
 // 解析ipv4协议
 return ngx_parse_inet_url(pool, u);
}
로그인 후 복사

우리는 ipv4 프로토콜을 사용하고 있습니다. 여기서는 ngx_parse_inet_url() 함수를 분석합니다.

// u.url = "80";
// u.listen = 1;
// u.default_port = 80;
static ngx_int_t
ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u)
{
 u_char *p, *host, *port, *last, *uri, *args;
 size_t len;
 ngx_int_t n;
 struct sockaddr_in *sin;
#if (ngx_have_inet6)
 struct sockaddr_in6 *sin6;
#endif

 u->socklen = sizeof(struct sockaddr_in);
 sin = (struct sockaddr_in *) &u->sockaddr;
 sin->sin_family = af_inet;// ipv4类型

 u->family = af_inet; 

 host = u->url.data; // "80"

 last = host + u->url.len; // host的最后字符的位置

 port = ngx_strlchr(host, last, ':'); // 找到port, 这里为 null

 uri = ngx_strlchr(host, last, '/'); // 找到uri,这里为 null

 args = ngx_strlchr(host, last, '?'); // 找到参数args,这里为 null

 if (args) {
 if (uri == null || args < uri) {
 uri = args;
 }
 }

 if (uri) {
 if (u->listen || !u->uri_part) {
 u->err = "invalid host";
 return ngx_error;
 }

 u->uri.len = last - uri;
 u->uri.data = uri;

 last = uri;

 if (uri < port) {
 port = null;
 }
 }

 if (port) {
 port++;

 len = last - port;

 n = ngx_atoi(port, len);

 if (n < 1 || n > 65535) {
 u->err = "invalid port";
 return ngx_error;
 }

 u->port = (in_port_t) n;
 sin->sin_port = htons((in_port_t) n);

 u->port_text.len = len;
 u->port_text.data = port;

 last = port - 1;

 } else {
 if (uri == null) {

 if (u->listen) {

 /* test value as port only */

 n = ngx_atoi(host, last - host);

 if (n != ngx_error) {

 if (n < 1 || n > 65535) {
 u->err = "invalid port";
 return ngx_error;
 }

 u->port = (in_port_t) n;
 sin->sin_port = htons((in_port_t) n);

 u->port_text.len = last - host;
 u->port_text.data = host;

 u->wildcard = 1;

 return ngx_ok;
 }
 }
 }

 u->no_port = 1;
 u->port = u->default_port;
 sin->sin_port = htons(u->default_port);
 }

 len = last - host;

 if (len == 0) {
 u->err = "no host";
 return ngx_error;
 }

 u->host.len = len;
 u->host.data = host;

 if (u->listen && len == 1 && *host == &#39;*&#39;) {
 sin->sin_addr.s_addr = inaddr_any;
 u->wildcard = 1;
 return ngx_ok;
 }

 sin->sin_addr.s_addr = ngx_inet_addr(host, len);

 if (sin->sin_addr.s_addr != inaddr_none) {

 if (sin->sin_addr.s_addr == inaddr_any) {
 u->wildcard = 1;
 }

 u->naddrs = 1;

 u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t));
 if (u->addrs == null) {
 return ngx_error;
 }

 sin = ngx_pcalloc(pool, sizeof(struct sockaddr_in));
 if (sin == null) {
 return ngx_error;
 }

 ngx_memcpy(sin, &u->sockaddr, sizeof(struct sockaddr_in));

 u->addrs[0].sockaddr = (struct sockaddr *) sin;
 u->addrs[0].socklen = sizeof(struct sockaddr_in);

 p = ngx_pnalloc(pool, u->host.len + sizeof(":65535") - 1);
 if (p == null) {
 return ngx_error;
 }

 u->addrs[0].name.len = ngx_sprintf(p, "%v:%d",
  &u->host, u->port) - p;
 u->addrs[0].name.data = p;

 return ngx_ok;
 }

 if (u->no_resolve) {
 return ngx_ok;
 }

 if (ngx_inet_resolve_host(pool, u) != ngx_ok) {
 return ngx_error;
 }

 u->family = u->addrs[0].sockaddr->sa_family;
 u->socklen = u->addrs[0].socklen;
 ngx_memcpy(&u->sockaddr, u->addrs[0].sockaddr, u->addrs[0].socklen);

 switch (u->family) {

#if (ngx_have_inet6)
 case af_inet6:
 sin6 = (struct sockaddr_in6 *) &u->sockaddr;

 if (in6_is_addr_unspecified(&sin6->sin6_addr)) {
 u->wildcard = 1;
 }

 break;
#endif

 default: /* af_inet */
 sin = (struct sockaddr_in *) &u->sockaddr;

 if (sin->sin_addr.s_addr == inaddr_any) {
 u->wildcard = 1;
 }

 break;
 }

 return ngx_ok;
}
로그인 후 복사

이 함수는 우리 구성 파일에서 포트 번호가 80이고 청취가 없습니다. 따라서 u->wildcard = 1은 이것이 와일드카드이고 서버의 모든 IP 주소 중 이 포트 번호를 수신하려는 것을 의미합니다.

listen 명령 구문 분석

소스 코드에서 Listen 구성을 살펴보겠습니다.

{ 
 ngx_string("listen"),
 ngx_http_srv_conf|ngx_conf_1more,
 ngx_http_core_listen,
 ngx_http_srv_conf_offset,
 0,
 null 
}
로그인 후 복사

구성 파일에서 Listen은 서버 모듈에만 나타날 수 있으며 여러 매개 변수를 가질 수 있음을 알 수 있습니다.

해당 처리 함수는 ngx_http_core_listen입니다. 아래에서 이 함수를 분석해 보겠습니다. 잘못된 판단을 내리는 일부 코드를 삭제했습니다.

static char *
ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
 ngx_http_core_srv_conf_t *cscf = conf;

 ngx_str_t *value, size;
 ngx_url_t u;
 ngx_uint_t n;
 ngx_http_listen_opt_t lsopt;

 cscf->listen = 1;

 value = cf->args->elts;

 ngx_memzero(&u, sizeof(ngx_url_t));

 u.url = value[1];
 u.listen = 1;
 u.default_port = 80;

 if (ngx_parse_url(cf->pool, &u) != ngx_ok) {
 return ngx_conf_error;
 }

 ngx_memzero(&lsopt, sizeof(ngx_http_listen_opt_t));

 ngx_memcpy(&lsopt.sockaddr.sockaddr, &u.sockaddr, u.socklen);

 lsopt.socklen = u.socklen;
 lsopt.backlog = ngx_listen_backlog;
 lsopt.rcvbuf = -1;
 lsopt.sndbuf = -1;
#if (ngx_have_setfib)
 lsopt.setfib = -1;
#endif
#if (ngx_have_tcp_fastopen)
 lsopt.fastopen = -1;
#endif
 lsopt.wildcard = u.wildcard;
#if (ngx_have_inet6)
 lsopt.ipv6only = 1;
#endif

 (void) ngx_sock_ntop(&lsopt.sockaddr.sockaddr, lsopt.socklen, lsopt.addr,
  ngx_sockaddr_strlen, 1);

 for (n = 2; n < cf->args->nelts; n++) {

 if (ngx_strcmp(value[n].data, "default_server") == 0
 || ngx_strcmp(value[n].data, "default") == 0)
 {
 lsopt.default_server = 1;
 continue;
 }
 // 这里面的其他代码都是处理listen的各种参数,对我们这里的分析没有用处
 }

 if (ngx_http_add_listen(cf, cscf, &lsopt) == ngx_ok) {
 return ngx_conf_ok;
 }

 return ngx_conf_error;
}
로그인 후 복사

이 함수의 전체 프로세스는 Listen 명령의 매개 변수를 구문 분석하고 ngx_http_listen_opt_t를 생성하는 것입니다. 이름에서 알 수 있듯이 이 구조는 일부 수신 포트 옵션(수신 포트 옵션)을 저장하는 것입니다. 여기서는 ngx_parse_url() 함수가 호출됩니다. 위에서 이를 분석했습니다. 이 함수의 기능은 URL의 주소와 포트를 구문 분석하는 것입니다.

그럼 가장 중요한 부분이 나옵니다. ngx_http_core_listen() 함수는 마지막에 ngx_http_add_listen() 함수를 호출합니다. 이 함수는 수신 포트 정보를 ngx_http_core_main_conf_t 구조의 포트 동적 배열에 저장합니다.

ngx_http_add_listen() 함수

// cf: 配置结构体
// cscf: listen指令所在的server的配置结构体
// lsopt : ngx_http_core_listen()生成的listen option
ngx_int_t
ngx_http_add_listen(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
 ngx_http_listen_opt_t *lsopt)
{
 in_port_t     p;
 ngx_uint_t     i;
 struct sockaddr   *sa;
 ngx_http_conf_port_t  *port;
 ngx_http_core_main_conf_t *cmcf;
 // 获取 ngx_http_core_module模块的main_conf结构体ngx_http_core_main_conf_t
 cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
 // ports字段是一个数组
 if (cmcf->ports == null) {
  cmcf->ports = ngx_array_create(cf->temp_pool, 2,
          sizeof(ngx_http_conf_port_t));
  if (cmcf->ports == null) {
   return ngx_error;
  }
 }

 sa = &lsopt->sockaddr.sockaddr;
 p = ngx_inet_get_port(sa);

 port = cmcf->ports->elts;
 for (i = 0; i < cmcf->ports->nelts; i++) {

  if (p != port[i].port || sa->sa_family != port[i].family) {
   continue;
  }

  /* a port is already in the port list */

  return ngx_http_add_addresses(cf, cscf, &port[i], lsopt);
 }

 /* add a port to the port list */

 port = ngx_array_push(cmcf->ports);
 if (port == null) {
  return ngx_error;
 }

 port->family = sa->sa_family;
 port->port = p;
 port->addrs.elts = null;

 return ngx_http_add_address(cf, cscf, port, lsopt);
}
로그인 후 복사

이 함수는 포트 번호 정보를 ngx_http_core_main_conf_t 구조의 포트 필드에 저장합니다.

nginx에서 Listen 명령을 사용하는 방법

위 내용은 nginx에서 Listen 명령을 사용하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:yisu.com
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿