Nginx-HTTP之listen指令解析

时间:2022-09-26 23:22:03

1. ngx_http_core_listen

static char *
ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
/* conf 即为该 listen 所在的配置信息结构体 */
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; /* 假设当前 listen 指令为: "listen 80;" */ /* value = "listen" */
value = cf->args->elts; ngx_memzero(&u, sizeof(ngx_url_t)); /* u.url = "80" */
u.url = value[1];
/* 标志位,为 1 表示当前端口有效 */
u.listen = 1;
/* 若 listen 没有指定端口,则会使用默认端口 */
u.default_port = 80; /* 解析 listen 的参数 */
if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
if (u.err) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"%s in \"%V\" of the \"listen\" directive",
u.err, &u.url);
} 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;
/* TCP 实现监听时的 backlog 队列,它表示允许正在通过三次握手建立 TCP
* 连接但没有任何进程开始处理的连接最大个数,linux 下设为 511 */
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); /* 若当前 listen 指令不止一个参数 */
for (n = 2; n < cf->args->nelts; n++) { /* 若第二个参数为 "default_server" */
if (ngx_strcmp(value[n].data, "default_server") == 0
|| ngx_strcmp(value[n].data, "default") == 0)
{
/* 表示使用默认的服务器 */
lsopt.default_server = 1;
continue;
} /* 若listen指定有 bind 参数,则表示需要绑定该端口 */
if (ngx_strcmp(value[n].data, "bind") == 0) {
lsopt.set = 1;
lsopt.bind = 1;
continue;
} #if (NGX_HAVE_SETFIB)
if (ngx_strncmp(value[n].data, "setfib=", 7) == 0) {
lsopt.setfib = ngx_atoi(value[n].data + 7, value[n].len - 7);
lsopt.set = 1;
lsopt.bind = 1; if (lsopt.setfib == NGX_ERROR) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid setfib \"%V\"", &value[n]);
return NGX_CONF_ERROR;
} continue;
}
#endif #if (NGX_HAVE_TCP_FASTOPEN)
if (ngx_strncmp(value[n].data, "fastopen=", 9) == 0) {
lsopt.fastopen = ngx_atoi(value[n].data + 9, value[n].len - 9);
lsopt.set = 1;
lsopt.bind = 1; if (lsopt.fastopen == NGX_ERROR) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid fastopen \"%V\"", &value[n]);
return NGX_CONF_ERROR;
} continue;
}
#endif if (ngx_strncmp(value[n].data, "backlog=", 8) == 0) {
lsopt.backlog = ngx_atoi(value[n].data + 8, value[n].len - 8);
lsopt.set = 1;
lsopt.bind = 1; if (lsopt.backlog == NGX_ERROR || lsopt.backlog == 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid backlog \"%V\"", &value[n]);
return NGX_CONF_ERROR;
} continue;
} if (ngx_strncmp(value[n].data, "rcvbuf=", 7) == 0) {
size.len = value[n].len - 7;
size.data = value[n].data + 7; lsopt.rcvbuf = ngx_parse_size(&size);
lsopt.set = 1;
lsopt.bind = 1; if (lsopt.rcvbuf == NGX_ERROR) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid rcvbuf \"%V\"", &value[n]);
return NGX_CONF_ERROR;
} continue;
} if (ngx_strncmp(value[n].data, "sndbuf=", 7) == 0) {
size.len = value[n].len - 7;
size.data = value[n].data + 7; lsopt.sndbuf = ngx_parse_size(&size);
lsopt.set = 1;
lsopt.bind = 1; if (lsopt.sndbuf == NGX_ERROR) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid sndbuf \"%V\"", &value[n]);
return NGX_CONF_ERROR;
} continue;
} if (ngx_strncmp(value[n].data, "accept_filter=", 14) == 0) {
#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
lsopt.accept_filter = (char *) &value[n].data[14];
lsopt.set = 1;
lsopt.bind = 1;
#else
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"accept filters \"%V\" are not supported "
"on this platform, ignored",
&value[n]);
#endif
continue;
} if (ngx_strcmp(value[n].data, "deferred") == 0) {
#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
lsopt.deferred_accept = 1;
lsopt.set = 1;
lsopt.bind = 1;
#else
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"the deferred accept is not supported "
"on this platform, ignored");
#endif
continue;
} if (ngx_strncmp(value[n].data, "ipv6only=o", 10) == 0) {
#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
struct sockaddr *sa; sa = &lsopt.sockaddr.sockaddr; if (sa->sa_family == AF_INET6) { if (ngx_strcmp(&value[n].data[10], "n") == 0) {
lsopt.ipv6only = 1; } else if (ngx_strcmp(&value[n].data[10], "ff") == 0) {
lsopt.ipv6only = 0; } else {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid ipv6only flags \"%s\"",
&value[n].data[9]);
return NGX_CONF_ERROR;
} lsopt.set = 1;
lsopt.bind = 1; } else {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"ipv6only is not supported "
"on addr \"%s\", ignored", lsopt.addr);
} continue;
#else
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"ipv6only is not supported "
"on this platform");
return NGX_CONF_ERROR;
#endif
} if (ngx_strcmp(value[n].data, "reuseport") == 0) {
#if (NGX_HAVE_REUSEPORT)
lsopt.reuseport = 1;
lsopt.set = 1;
lsopt.bind = 1;
#else
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"reuseport is not supported "
"on this platform, ignored");
#endif
continue;
} if (ngx_strcmp(value[n].data, "ssl") == 0) {
#if (NGX_HTTP_SSL)
lsopt.ssl = 1;
continue;
#else
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"the \"ssl\" parameter requires "
"ngx_http_ssl_module");
return NGX_CONF_ERROR;
#endif
} if (ngx_strcmp(value[n].data, "http2") == 0) {
#if (NGX_HTTP_V2)
lsopt.http2 = 1;
continue;
#else
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"the \"http2\" parameter requires "
"ngx_http_v2_module");
return NGX_CONF_ERROR;
#endif
} if (ngx_strcmp(value[n].data, "spdy") == 0) {
ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
"invalid parameter \"spdy\": "
"ngx_http_spdy_module was superseded "
"by ngx_http_v2_module");
continue;
} if (ngx_strncmp(value[n].data, "so_keepalive=", 13) == 0) { if (ngx_strcmp(&value[n].data[13], "on") == 0) {
lsopt.so_keepalive = 1; } else if (ngx_strcmp(&value[n].data[13], "off") == 0) {
lsopt.so_keepalive = 2; } else { #if (NGX_HAVE_KEEPALIVE_TUNABLE)
u_char *p, *end;
ngx_str_t s; end = value[n].data + value[n].len;
s.data = value[n].data + 13; p = ngx_strlchr(s.data, end, ':');
if (p == NULL) {
p = end;
} if (p > s.data) {
s.len = p - s.data; lsopt.tcp_keepidle = ngx_parse_time(&s, 1);
if (lsopt.tcp_keepidle == (time_t) NGX_ERROR) {
goto invalid_so_keepalive;
}
} s.data = (p < end) ? (p + 1) : end; p = ngx_strlchr(s.data, end, ':');
if (p == NULL) {
p = end;
} if (p > s.data) {
s.len = p - s.data; lsopt.tcp_keepintvl = ngx_parse_time(&s, 1);
if (lsopt.tcp_keepintvl == (time_t) NGX_ERROR) {
goto invalid_so_keepalive;
}
} s.data = (p < end) ? (p + 1) : end; if (s.data < end) {
s.len = end - s.data; lsopt.tcp_keepcnt = ngx_atoi(s.data, s.len);
if (lsopt.tcp_keepcnt == NGX_ERROR) {
goto invalid_so_keepalive;
}
} if (lsopt.tcp_keepidle == 0 && lsopt.tcp_keepintvl == 0
&& lsopt.tcp_keepcnt == 0)
{
goto invalid_so_keepalive;
} lsopt.so_keepalive = 1; #else ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"the \"so_keepalive\" parameter accepts "
"only \"on\" or \"off\" on this platform");
return NGX_CONF_ERROR; #endif
} lsopt.set = 1;
lsopt.bind = 1; continue; #if (NGX_HAVE_KEEPALIVE_TUNABLE)
invalid_so_keepalive: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid so_keepalive value: \"%s\"",
&value[n].data[13]);
return NGX_CONF_ERROR;
#endif
} if (ngx_strcmp(value[n].data, "proxy_protocol") == 0) {
lsopt.proxy_protocol = 1;
continue;
} ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid parameter \"%V\"", &value[n]);
return NGX_CONF_ERROR;
} /* 将已经初始化好的 lsopt 结构体添加到 */
if (ngx_http_add_listen(cf, cscf, &lsopt) == NGX_OK) {
return NGX_CONF_OK;
} return NGX_CONF_ERROR;
}

2. ngx_parse_url

解析 lisetn 指令的参数。

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 域 */
if (len >= 5 && ngx_strncasecmp(p, (u_char *) "unix:", 5) == 0) {
return ngx_parse_unix_domain_url(pool, u);
} /* 检测是否为 ip6 */
if (len && p[0] == '[') {
return ngx_parse_inet6_url(pool, u);
} /* 否则调用该函数 */
return ngx_parse_inet_url(pool, u);
}

2.1 ngx_parse_inet_url

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;
/* 初始化地址组为 AF_INET,即为 ipv4 类型的 */
sin->sin_family = AF_INET; u->family = AF_INET; /* 若当前 listen 指令的配置为: listen 80; */ host = u->url.data; last = host + u->url.len; port = ngx_strlchr(host, last, ':'); uri = ngx_strlchr(host, last, '/'); args = ngx_strlchr(host, last, '?'); 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;
} /* 当前 listen 指令的参数仅为要监听的端口 */
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;
}
}
} /* no_port 标志位,为 1 表示当前 listen 的参数中没有指定端口 */
u->no_port = 1;
/* 因此使用默认端口 80 */
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 == '*') {
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;
}

3. ngx_http_add_listen

/* 每监听一个TCP端口,都将使用一个独立的ngx_http_conf_port_t结构体表示。
* 这个保存着监听端口的ngx_http_conf_port_t将由全局的ngx_http_core_main_conf_t
* 结构体保存 */
typedef struct {
/* socket地址家族 */
ngx_int_t family;
/* 监听端口 */
in_port_t port;
/* 监听端口下对应着的所有ngx_http_conf_addr_t地址 */
ngx_array_t addrs; /* array of ngx_http_conf_addr_t */
}ngx_http_conf_port_t; 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; cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); /* 若 ports 数组为空 */
if (cmcf->ports == NULL) {
/* posts 存放着该http{}配置块下监听的所有ngx_http_conf_port_t端口 */
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;
/* 检测当前所要监听的端口是否已经存在 ports 数组中 */
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 */ /* 若当前所要监听的端口不存在 ports 数组中,则
* 将该端口添加到 ports 数组中 */
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_conf_port_t的addrs动态数组的理解:

  • 在nginx.conf配置文件中,对于同一个端口8000,我们可以同时监听127.0.0.1:8000、192.168.1.82:8000这两个地址,当一台物理主机具备多个IP地址时这是很有用的。具体到HTTP框架的实现上,Nginx是使用ngx_http_conf_addr_t结构体来表示一个对应着具体地址的监听端口的,因此,一个ngx_http_conf_port_t将会对应多个ngx_http_conf_addr_t,而ngx_http_conf_addr_t就是以动态数组的形式保存在addrs成员中的.

3.1 ngx_http_add_address

typedef struct {
/* 监听套接字的各种属性 */
ngx_http_listen_opt_t opt; /* 以下3个散列表用于加速寻找对应监听端口上的新连接,确定到底使用哪个server{}
* 虚拟主机下的配置来处理它。所以,散列表的值就是ngx_http_core_srv_conf_t
* 结构体的地址 */ /* 完全匹配server name的散列表 */
ngx_hash_t hash;
/* 通配符前置的散列表 */
ngx_hash_wildcard_t *wc_head;
/* 通配符后置的散列表 */
ngx_hash_wildcard_t *wc_tail; #if (NGX_PCRE)
/* 下面的regex数组中元素的个数 */
ngx_uint_t nregex;
/* regex指向静态数组,其数组成员就是ngx_http_server_name_t结构体,
* 表示正则表达式及其匹配的server{}虚拟主机 */
ngx_http_server_name_t *regex;
#endif /* 该监听端口下对应的默认server{}虚拟主机 */
/* the default server configuration for this address:port */
ngx_http_core_srv_conf_t *default_server;
/* servers动态数组中的成员将指向ngx_http_core_srv_conf_t结构体 */
ngx_array_t servers; /* array of ngx_http_core_srv_conf_t */
}ngx_http_conf_addr_t; /*
* add the server address, the server names and the server core module
* configurations to the port list.
*/
static ngx_int_t
ngx_http_add_address(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
ngx_http_conf_port_t *port, ngx_http_listen_opt_t *lsopt)
{
ngx_http_conf_addr_t *addr; /* 一个端口可能对应几个主机地址,具体看当前主机有多少个 ip 地址 */
if (port->addrs.elts == NULL) {
if (ngx_array_init(&port->addrs, cf->temp_pool, 4,
sizeof(ngx_http_conf_addr_t))
!= NGX_OK)
{
return NGX_ERROR;
}
} #if (NGX_HTTP_V2 && NGX_HTTP_SSL \
&& !defined TLSEXT_TYPE_application_layer_protocol_negotiation \
&& !defined TLSEXT_TYPE_next_proto_neg) if (lsopt->http2 && lsopt->ssl) {
ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
"nginx was built with OpenSSL that lacks ALPN "
"and NPN support, HTTP/2 is not enabled for %s",
lsopt->addr);
} #endif /* 向该 port->addrs 数组中添加一个地址 */
addr = ngx_array_push(&port->addrs);
if (addr == NULL) {
return NGX_ERROR;
} addr->opt = *lsopt;
addr->hash.buckets = NULL;
addr->hash.size = 0;
addr->wc_head = NULL;
addr->wc_tail = NULL;
#if (NGX_PCRE)
addr->nregex = 0;
addr->regex = NULL;
#endif
addr->default_server = cscf;
addr->servers.elts = NULL; return ngx_http_add_server(cf, cscf, addr);
}

3.2 ngx_http_add_server

/*
* add the server core module configuration to the address:port
*/
static ngx_int_t
ngx_http_add_server(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
ngx_http_conf_addr_t *addr)
{
ngx_uint_t i;
ngx_http_core_srv_conf_t **server; /* servers动态数组中的成员将指向ngx_http_core_srv_conf_t结构体 */
if (addr->servers.elts == NULL) {
if (ngx_array_init(&addr->servers, cf->temp_pool, 4,
sizeof(ngx_http_core_srv_conf_t *))
!= NGX_OK)
{
return NGX_ERROR;
} } else {
server = addr->servers.elts;
for (i = 0; i < addr->servers.nelts; i++) {
if (server[i] == cscf) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"a duplicate listen %s", addr->opt.addr);
return NGX_ERROR;
}
}
} /* 向该数组中添加一个 ngx_http_core_srv_conf_t 结构体 */
server = ngx_array_push(&addr->servers);
if (server == NULL) {
return NGX_ERROR;
} /* 将当前 listen 指令所在的 server{} 下 srv 相关配置项的
* ngx_http_core_srv_conf_t 添加到 servers 数组中 */
*server = cscf; return NGX_OK;
}

Nginx-HTTP之listen指令解析的更多相关文章

  1. Nginx安装部署以及配置文件解析

    Nginx 中的 Location 指令 是NginxHttpCoreModule中重要指令.Location 指令,是用来为匹配的 URI 进行配置,URI 即语法中的”/uri/”,可以是字符串或 ...

  2. Nginx RTMP 模块 nginx-rtmp-module 指令详解

    译序:截至 Jul 8th,2013 官方公布的最新 Nginx RTMP 模块 nginx-rtmp-module 指令详解.指令Corertmp语法:rtmp { ... }上下文:根描述:保存所 ...

  3. 2&period;4 Nginx服务器基础配置指令

    2.4.1 nginx.conf文件的结构 2.4.2配置运行Nginx服务器用户(组) 2.4.3配置允许生成的worker process数 2.4.4 配置Nginx进程PID存放路径 2.4. ...

  4. Nginx主要模块常用指令说明

    核心模块(Core Modules): 主模块(Main Module):配置和服务器全局有关的一些参数,比如错误日志.进程.权限等 user worker_processes error_logsy ...

  5. nginx fastcgi模块ngx&lowbar;http&lowbar;fastcgi&lowbar;module详细解析、使用手册、完整翻译

    ngx_http_fastcgi_module 模块允许将请求传递给 FastCGI 服务器. 示例配置 location / { fastcgi_pass localhost:9000; fastc ...

  6. CentOS &plus; Nginx 的常用操作指令总结

    CentOS + Nginx 的常用操作指令总结 一. 关于CentOS 查看 yum 源是否存在 yum list | grep nginx 如果不存在 或者 不是自己想要的版本 可以自己设置Ngi ...

  7. AngularJS 指令解析(二)

    AngularJS 指令解析(二) 第一篇我们讲过了作用域(scope)这块内容,现在我们进入正题,讲AngularJS的指令. 什么是指令? 这里我们引用官方的一句话: Custom directi ...

  8. AngularJS 指令解析(一)

    AngularJS 指令解析(一) 前言 笔者AngularJS接触时间差不多是两年多,虽然这两年多AngularJS版本日新月异,但是笔者的版本是比较老的1.4.3,一方面是自己对这个版本比较熟悉, ...

  9. Nginx user&lowbar;agent、if指令及全局变量

    Nginx user_agent.if指令及全局变量 1.User_agent User Agent中文名为用户代理,简称 UA,它是一个特殊字符串头,使得服务器能够识别客户使用的操作系统及版本.CP ...

随机推荐

  1. hdu3007Buried memory(最小圆覆盖)

    链接 普通的暴力复杂度达到O(n^4),对于这题肯定是不行的. 解法:随机增量算法 参考http://www.2cto.com/kf/201208/149602.html algorithm:A.令C ...

  2. C&plus;&plus;仿函数&lpar;functor&rpar;详解

    C++仿函数(functor)详解 所谓的仿函数(functor),是通过重载()运算符模拟函数形为的类. 因此,这里需要明确两点: 1 仿函数不是函数,它是个类: 2 仿函数重载了()运算符,使得它 ...

  3. Windows 8&period;1 Hyper-V安装的虚拟机

    一.安装Hyper-v Hyper-V内置于Windows 8中,用户无需格外的下载安装文件,只需要到Windows 8的程序管理中将其选中开启功能即可. 具体步骤:控制面板→程序→启用或关闭Wind ...

  4. MAC 中安装 Homebrew

    Homebrew可以很方便的进行软件包管理,用官网的一句话来形容就是 Homebrew 使 OS X 更完整.用 gem 来安装您的 gems.用 brew 来搞定它们的依赖包. 安装Homebrew ...

  5. AndroidStaggeredGrid

    https://github.com/etsy/AndroidStaggeredGrid

  6. Java使用poi对Execl简单&lowbar;读和写&lowbar;操作

    1 /** 一.简单读取Execl的步骤: * 1.通过流来读取Execl并存放到内存中: * 2.通过WorkbookFactory工作簿工厂来读取内存中存放的execl文档流并创建出一个工作簿 * ...

  7. 浅谈数据库系统中的cache

    Cache和Buffer是两个不同的概念,简单的说,Cache是加速“读”,而buffer是缓冲“写”,前者解决读的问题,保存从磁盘上读出的数据,后者是解决写的问题,保存即将要写入到磁盘上的数据.在很 ...

  8. POJ 2250 Compromise (UVA 531)

    LCS问题.基金会DP. 我很伤心WA非常多.就在LCS问题,需要记录什么路. 反正自己的纪录path错误,最后,就容易上当. 没有优化,二维阵列,递归打印,cin.eof() 来识别 end of ...

  9. Python 爬虫二 requests模块

    requests模块 Requests模块 get方法请求 整体演示一下: import requests response = requests.get("https://www.baid ...

  10. linux下如何批量杀JAVA进程或某个进程方法

    linux下如何批量杀JAVA进程或某个进程方法 在工作中经常需要停止JAVA进程,停止时间也比较长,那么有时候因为一些情况,需要把 linux 下JAVA所有进程 kill 掉,又不能用killal ...