Nginx-HTTP之listen指令解析
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指令解析的更多相关文章
- Nginx安装部署以及配置文件解析
Nginx 中的 Location 指令 是NginxHttpCoreModule中重要指令.Location 指令,是用来为匹配的 URI 进行配置,URI 即语法中的”/uri/”,可以是字符串或 ...
- Nginx RTMP 模块 nginx-rtmp-module 指令详解
译序:截至 Jul 8th,2013 官方公布的最新 Nginx RTMP 模块 nginx-rtmp-module 指令详解.指令Corertmp语法:rtmp { ... }上下文:根描述:保存所 ...
- 2.4 Nginx服务器基础配置指令
2.4.1 nginx.conf文件的结构 2.4.2配置运行Nginx服务器用户(组) 2.4.3配置允许生成的worker process数 2.4.4 配置Nginx进程PID存放路径 2.4. ...
- Nginx主要模块常用指令说明
核心模块(Core Modules): 主模块(Main Module):配置和服务器全局有关的一些参数,比如错误日志.进程.权限等 user worker_processes error_logsy ...
- nginx fastcgi模块ngx_http_fastcgi_module详细解析、使用手册、完整翻译
ngx_http_fastcgi_module 模块允许将请求传递给 FastCGI 服务器. 示例配置 location / { fastcgi_pass localhost:9000; fastc ...
- CentOS + Nginx 的常用操作指令总结
CentOS + Nginx 的常用操作指令总结 一. 关于CentOS 查看 yum 源是否存在 yum list | grep nginx 如果不存在 或者 不是自己想要的版本 可以自己设置Ngi ...
- AngularJS 指令解析(二)
AngularJS 指令解析(二) 第一篇我们讲过了作用域(scope)这块内容,现在我们进入正题,讲AngularJS的指令. 什么是指令? 这里我们引用官方的一句话: Custom directi ...
- AngularJS 指令解析(一)
AngularJS 指令解析(一) 前言 笔者AngularJS接触时间差不多是两年多,虽然这两年多AngularJS版本日新月异,但是笔者的版本是比较老的1.4.3,一方面是自己对这个版本比较熟悉, ...
- Nginx user_agent、if指令及全局变量
Nginx user_agent.if指令及全局变量 1.User_agent User Agent中文名为用户代理,简称 UA,它是一个特殊字符串头,使得服务器能够识别客户使用的操作系统及版本.CP ...
随机推荐
- python+requests模拟登陆 学校选课系统
最近学校让我们选课,每天都有不同的课需要选....然后突发奇想试试用python爬学校选课系统的课程信息 先把自己的浏览器缓存清空,然后在登陆界面按f12 如图: 可以看到登陆时候是需要验证码的,验证 ...
- Oracle 如何查看当前的实例及切换实例
一.Oracle查看当前实例 1.打开终端,输入命令sqlpuls / as sysdba连接到数据库 2.输入命令show parameter name便可以查看当前登录数据库的参数配置,如下可以看 ...
- Spring @Scheduled执行原理解析
项目使用很多@Scheduled(cron=**) 注解来实现定时任务,既然要用就必须弄清楚的它的实现原理,于是乎翻了一下相关的源码. Spring 3.0之后增加了调度器功能,提供的@Schedul ...
- 80C51串行口
串行通信是指 使用一条数据线,将数据一位一位地依次传输,每一位数据占据一个固定的时间长度 单工.半双工.全双工 单工数据传输只支持数据在一个方向上传输 半双工数据传输允许数据在两个方向上传输,但是,在 ...
- 6.SpringMVC 配置式开发-处理器
处理器除了实现Controller 接口外,还可以继承自一些其他的类,来完成一些特殊的功能 1.继承自AbstractController类 若处理器继承自AbstractController类,那么 ...
- java EE,java Web中的400,404,405等各种错误介绍
4 请求失败4xx 4xx应答定义了特定服务器响应的请求失败的情况.客户端不应当在不更改请求的情况下重新尝试同一个请求.(例如,增加合适的认证信息).不过,同一个请求交给不同服务器也许就会成功. 4. ...
- 【loj#2133 && luoguP2178】[NOI2015]品酒大会
题目传送门:loj#2133 luoguP2178 简要题意:给定一个字符串\(s\),每个后缀都有权值,对于每个长度\(len\),求出所有最长公共前缀\(\geq len\)的后缀对的总数 ...
- web应用原理之——会话
会话是大家开发Java EE Web应用的常用技术,那么会话是什么,会话的用途还有工作原理又是什么,下面就简单说一说. 什么是会话,在web应用中,作为客户端的浏览器,通过请求/响应这种模式访问同一个 ...
- AJAX—AJAX基础
AJAX简介 什么是AJAX AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步Javascript和XML”.即使用Javascript语言与服务器进行异 ...
- 关于使用jquery评论插件...
.今天做项目,使用了一个评论插件 调用出来没事, 可是添加的时候报错 Uncaught TypeError: $(...).find(...).live is not a function 这个错误 ...