搜尋
首頁運維Nginxnginx中的listen指令怎麼用

listen指令

nginx作為一個高效能的http伺服器,網路的處理是其核心,了解網路的初始化有助於加深對nginx網路處理的了解。與網路有關的設定指令主要有兩個:listen和sever_name。 listen指令設定nginx監聽位址,對於ip協議,這個位址就是address和port,對於unix域套接字協議,這個位址就是path,一條listen指令只能指定一個address或port,address也可以是主機名稱

從這篇文章開始,我們分析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]];

一個listen指令攜帶的參數是很複雜的。不過,我們一般很少關注那些不太常用的參數,以下是一些常用的配置方式:

listen 127.0.0.1:8000;
listen 127.0.0.1 不加端口,默认监听80端口;
listen 8000
listen *:8000
listen localhost:8000

解析listen指令中的uri和端口

##從上面的內容知道,listen有多種用法,我們在解析的時候需要取得到listen指令的連接埠號碼和uri部分,nginx提供了ngx_parse_url()方法來解析uri和port,該函數在解析listen指令的時候會被呼叫。


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;
}

這個函數就是解析了我們listen的位址和連接埠號,我們的設定檔中,端口號為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只能出現在server 模組中,可以帶有多個參數。


對應的處理函數為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,顧名思義,這個結構體就是保存一些監聽埠的選項(listening port option)。這裡呼叫了一個函數ngx_parse_url(),我們上面已經分析過了,這個函數的作用就是解析url中的address和port。


然後最重要的部分就要到了,ngx_http_core_listen()函數在最後面呼叫了ngx_http_add_listen()函數,該函數是將listen的連接埠資訊保存到ngx_http_core_main_conf_t結構體的ports動態數組中。


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結構體的port欄位中。


nginx中的listen指令怎麼用#

以上是nginx中的listen指令怎麼用的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:亿速云。如有侵權,請聯絡admin@php.cn刪除
雷軍分享新年願望:交付30萬輛車、健身房打卡100次雷軍分享新年願望:交付30萬輛車、健身房打卡100次Apr 13, 2025 pm 11:54 PM

新年伊始,雷軍抖音跨年直播分享了2025年的三個新年願望,這場長達四個半小時的直播吸引了眾多關注。雷軍的三大願望分別是:第一,實現30萬輛汽車交付目標,緩解壓力,不再被進度追趕。第二,擁有更多旅行時間,欣賞各地美景、品嚐特色美食,並結合工作進行汽車測試。第三,堅持健身,計劃在健身房打卡100次,強身健體。雷軍在直播中坦言,2024年奔波於各地,行程安排緊湊,往往只能短暫停留,難以深入體驗當地文化。例如,在德國紐北賽道,他僅停留了8個小時。因此,在新的一年裡,他希望能夠更好地平衡工作與生活,在旅行

年度口碑佳作!九號公司微電影《記憶奇旅》榮膺多項權威大獎年度口碑佳作!九號公司微電影《記憶奇旅》榮膺多項權威大獎Apr 13, 2025 pm 11:51 PM

九號公司攜手品牌代言人易烊千璽打造的微電影《記憶奇旅》,在2024年榮獲多項權威媒體大獎,成為年度口碑佳作。這部作品以獨特的敘事風格、精湛的製作和真摯的情感,贏得了業界的高度讚譽。 2024年度獲獎榮譽:2024金觸點全球商業創新大獎-年度影視廣告2024中國廣告營銷大獎-娛樂營銷組銀獎2024TopDigital創新營銷獎-影視製作類金獎2024上海國際廣告節-微電影銀獎2024第十一屆中國創新傳播大獎-整合營銷類銀獎WISE2024商業之王-年度案例第31屆中國國際廣告節2024數字營銷實戰大

創新引領,再獲殊榮! AGON斬獲PConline2024智臻科技獎創新引領,再獲殊榮! AGON斬獲PConline2024智臻科技獎Apr 13, 2025 pm 11:48 PM

近日,PConline2024智臻科技獎正式揭曉,AGON愛攻QD-OLED電競顯示器AG326UD榮獲“年度技術創新”獎項。此項殊榮不僅代表了業界對其技術優勢與市場表現的高度認可,更充分體現了AGON愛攻在電競顯示器技術領域的創新能力和卓越成就。 01.瞰科技未來,品技術革命PConline智臻科技獎的權威含金量作為科技行業的風向標,PConline智臻科技獎憑藉其嚴謹的評審體系和深度的行業分析,成功贏得廣泛的行業認可。該獎項始終致力於表彰推動科技行業發展的優秀產品和品牌,涵蓋從技

索尼證實PS5 Pro使用特製GPU 與AMD合作研發AI可能性索尼證實PS5 Pro使用特製GPU 與AMD合作研發AI可能性Apr 13, 2025 pm 11:45 PM

SonyInteractiveEntertainment(SIE,索尼互动娱乐)首席架构师MarkCerny公开更多次世代主机PlayStation5Pro(PS5Pro)硬体细节,包括性能升级的AMDRDNA2.x架构GPU,以及与AMD合作代号「Amethyst」的机器学习/人工智慧计划。PS5Pro性能提升的重点仍集中在更强大的GPU、先进的光线追踪与AI驱动的PSSR超解析度功能等3大支柱上。GPU採用客制化的AMDRDNA2架构,索尼将其命名为RDNA2.x,它拥有部分RDNA3架构才

終於改了!微軟Windows搜索功能將迎來全新更新終於改了!微軟Windows搜索功能將迎來全新更新Apr 13, 2025 pm 11:42 PM

微軟針對Windows搜索功能的改進,目前已在歐盟地區部分WindowsInsider頻道展開測試。此前,整合後的Windows搜索功能飽受用戶詬病,體驗欠佳。此次更新將搜索功能拆分為本地搜索和基於Bing的網絡搜索兩部分,以提升用戶體驗。新版搜索界面默認進行本地文件搜索,如需進行網絡搜索,需點擊“MicrosoftBingWebSearch”標籤進行切換。切換後,搜索欄將顯示“MicrosoftBingWebSearch:”,用戶可在此輸入關鍵詞。此舉有效避免了本地搜索結果與Bing搜索結果混

熟練地烤好了!怪物獵人推出20週年烤肉計時器與暖水壺熟練地烤好了!怪物獵人推出20週年烤肉計時器與暖水壺Apr 13, 2025 pm 11:39 PM

為慶祝卡普空《怪物獵人》系列20週年,寶島社推出了一款別具匠心的雜誌套裝——《怪物獵人》主題燒烤計時器及隨行杯。該套裝將於12月27日在日本全國全家便利店發售,售價3498日元。這款雜誌套裝最大的亮點在於其互動式燒烤計時器,完美復刻了系列遊戲中的經典燒烤場景。計時器採用舊版烤肉工具的設計,配有LED火焰燈效和遊戲BGM,讓您在實際燒烤過程中也能體驗到狩獵的樂趣。旋轉手柄模擬翻轉烤肉,成功烤熟後更會播放“烤好了!”的語音提示。計時器尺寸約為9.5cm(高)x10.7cm(寬)x8cm(深),內置L

太懂用戶了!小米SU7車主可免費領Are U OK氣門芯帽太懂用戶了!小米SU7車主可免費領Are U OK氣門芯帽Apr 13, 2025 pm 11:36 PM

小米汽車一周年慶典,為車主送上新年大禮!繼去年交付量突破13萬輛後,小米汽車官方微博宣布,將為每位小米SU7車主及準車主贈送雷軍經典語錄“AreyouOK?”主題氣門芯帽,數量有限,免費領取!活動時間:2024年12月28日下午4點至2025年1月20日23:59:59。在2024年12月31日23:59:59前購車或完成訂單的用戶,即可免費獲得一套四件套“AreyouOK?”氣門芯帽。這款氣門芯帽於今年9月首發,採用亮黃色PVC和黃銅材質製成,黃銅芯直接嵌入,確保行駛安全,不易脫落。用途廣泛,

HDMI 2.2標準有望2025前夕公佈! 8K分辨率即將到來HDMI 2.2標準有望2025前夕公佈! 8K分辨率即將到來Apr 13, 2025 pm 11:33 PM

據報導,HDMI2.2標準有望在2025年CES展會前夕正式發布,HDMIForum計劃於1月6日公佈這一新一代視頻信號傳輸協議規範。 2017年發布的HDMI2.1標準,最大帶寬為48Gbps,支持4K144Hz和8K30Hz視頻傳輸,結合DSC技術最高可達10K120Hz。預計HDMI2.2將大幅提升帶寬,支持更高分辨率和刷新率,並採用新型線材。雖然具體規格尚未公開,但HDMI2.2勢必超越HDMI2.1的48Gbps帶寬和10240*4320分辨率限制。鑑於DisplayPort2.1在20

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
4 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

將Eclipse與SAP NetWeaver應用伺服器整合。

EditPlus 中文破解版

EditPlus 中文破解版

體積小,語法高亮,不支援程式碼提示功能