溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

nginx websocket有什么特點

發(fā)布時間:2021-11-30 11:59:26 來源:億速云 閱讀:180 作者:iii 欄目:網(wǎng)絡(luò)管理

這篇文章主要介紹“nginx websocket有什么特點”,在日常操作中,相信很多人在nginx websocket有什么特點問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”nginx websocket有什么特點”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

websocket協(xié)議簡介

websocket是基于TCP的應(yīng)用層協(xié)議,用于在C/S架構(gòu)的應(yīng)用中實現(xiàn)雙向通信,rfc文檔說明rfc6455。
websocket在建立連接時會使用HTTP協(xié)議,所以websocket協(xié)議是基于HTTP協(xié)議實現(xiàn)的。

目前很多卡牌類的游戲選擇使用websocket協(xié)議進(jìn)行通信。

websocket具備如下特點:

1.可以進(jìn)行雙向通信,會話通信實時性強(qiáng)。

2.建立起websocket連接,可以一直保持連接,在此期間可以源源不斷的發(fā)送消息,直到關(guān)閉請求。避免了HTTP的非狀態(tài)性(連接時總開銷減少)。和http相比連接創(chuàng)建后,客戶端服務(wù)端進(jìn)行數(shù)據(jù)交換時,協(xié)議控制的數(shù)據(jù)包頭部較小(通信量減少)。

3.web服務(wù)器與客戶端之間建立起連接后,所有的通信都依靠這個專用協(xié)議進(jìn)行。通信過程中可互相發(fā)送JSON、XML、HTML或圖片等任意格式的數(shù)據(jù)。不論服務(wù)器還是客戶端,任意一方都可直接向?qū)Ψ桨l(fā)送數(shù)據(jù)。

4.更好的二進(jìn)制支持,支持?jǐn)U展。

websocket協(xié)議格式:

0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len |    Extended payload length    |
|I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
|N|V|V|V|       |S|             |   (if payload len==126/127)   |
| |1|2|3|       |K|             |                               |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
|     Extended payload length continued, if payload len == 127  |
+ - - - - - - - - - - - - - - - +-------------------------------+
|                               |Masking-key, if MASK set to 1  |
+-------------------------------+-------------------------------+
| Masking-key (continued)       |          Payload Data         |
+-------------------------------- - - - - - - - - - - - - - - - +
:                     Payload Data continued ...                :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
|                     Payload Data continued ...                |
+---------------------------------------------------------------+

nginx支持websocket說明

在使用nginx開啟websocket配置時,可以通過在server{}塊中配置websocket配置。

server {
      listen   80;
      server_name www.domain.com;
      location / {
         proxy_pass   http://127.0.0.1:8080/; //回源地址
     proxy_http_version 1.1;
         proxy_read_timeout   600s; //超時設(shè)置
         //啟用支持websocket
         proxy_set_header Upgrade $http_upgrade;
         proxy_set_header Connection "upgrade";
      }
}

如上配置它表明websocket請求連接的時候,升級連接將http連接變成websocket連接。

但這里會有一個問題,這樣在server{}塊中配置websocket,該server{}必須處理websocket流量,所有發(fā)往后端的流量都帶上upgrade和connection頭。

proxy_set_header  Upgrade $http_upgrade;

proxy_set_header  Connection $connection_upgrade;

nginx websocket源碼優(yōu)化

在server{}中配置websocket時,所有發(fā)往后端upstream的流量會添加websocket頭。

假如發(fā)往后端upstream的請求,有的需要添加websocket頭升級為websocket,有的請求不需要,如果繼續(xù)使用原生的nginx配置,會導(dǎo)致該場景該配置,出現(xiàn)問題。

所以該場景下需改動和優(yōu)化nginx源碼,來區(qū)分client的流量是否是websocket。

ngx_http_proxy_websocket_headers:區(qū)別在于connection和upgrade

static ngx_keyval_t  ngx_http_proxy_websocket_headers[] = {

{ ngx_string("Host"), ngx_string("$proxy_host") },

{ ngx_string("Connection"), ngx_string("Upgrade") },

{ ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") },

{ ngx_string("Transfer-Encoding"), ngx_string("$proxy_internal_chunked") },

{ ngx_string("TE"), ngx_string("") },

{ ngx_string("Keep-Alive"), ngx_string("") },

{ ngx_string("Expect"), ngx_string("") },

{ ngx_string("Upgrade"), ngx_string("websocket") },

{ ngx_null_string, ngx_null_string }

};

#ifdef NGX_WEBSOCKET_INNER

// 通過headers來init

rc = ngx_http_proxy_init_headers(cf, conf, &conf->websocket_headers,

ngx_http_proxy_websocket_headers);

if (rc != NGX_OK) {

return NGX_CONF_ERROR;

}

#endif

static ngx_int_t

ngx_http_process_connection(ngx_http_request_t *r, ngx_table_elt_t *h,

ngx_uint_t offset)

{

...

// 獲取upgrade標(biāo)志

if (ngx_strcasestrn(h->value.data, "Upgrade", 7 - 1)) {

r->is_websocket_request |= NGX_WEBSOCKET_HEADER_CONNECTION;

}

...

}


if (r->headers_in.upgrade == NULL) {

goto not_websocket_request;

} else if ((r->is_websocket_request & NGX_WEBSOCKET_HEADER_CONNECTION) == 0) {

goto not_websocket_request;

// } else if (ngx_strncasecmp(r->headers_in.upgrade->value.data, (u_char *)"websocket", 9) == 0) {

// 判斷是否含有websocket,添加標(biāo)志

} else if (ngx_strcasestrn(r->headers_in.upgrade->value.data, "websocket", 9 - 1)) {

r->is_websocket_request |= NGX_WEBSOCKET_HEADER_UPGRADE;

}

// 兩種標(biāo)志都有,r->websocket_request 標(biāo)志位置位

if (r->is_websocket_request == (NGX_WEBSOCKET_HEADER_UPGRADE | NGX_WEBSOCKET_HEADER_CONNECTION)) {

r->websocket_request = 1;

r->http_version = NGX_HTTP_VERSION_11;

} else {

r->websocket_request = 0;

}

ngx_http_proxy_process_header配置upstream的標(biāo)志位

static ngx_int_t

ngx_http_proxy_process_header(ngx_http_request_t *r)

{

...

if (u->headers_in.status_n == NGX_HTTP_SWITCHING_PROTOCOLS) {

u->keepalive = 0;

if (r->headers_in.upgrade) {

u->upgrade = 1;

}

}

...

}

在ngx_http_upstream_send_response種使用該標(biāo)志位

static void

ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)

{

...

if (u->upgrade) {

ngx_http_upstream_upgrade(r, u);

return;

}

...

}

ngx_http_upstream_upgrade給上下游設(shè)置讀寫事件

static void

ngx_http_upstream_upgrade(ngx_http_request_t *r, ngx_http_upstream_t *u)

{

...

u->read_event_handler = ngx_http_upstream_upgraded_read_upstream;

u->write_event_handler = ngx_http_upstream_upgraded_write_upstream;

r->read_event_handler = ngx_http_upstream_upgraded_read_downstream;

r->write_event_handler = ngx_http_upstream_upgraded_write_downstream;

...

}

每個讀寫時間所用的函數(shù)都是一樣的,入?yún)⒉煌?from_upstream代表是否是后端,do_write代表是否是寫事件

下面以upstream的讀事件為例

static void

ngx_http_upstream_process_upgraded(ngx_http_request_t *r,

ngx_uint_t from_upstream, ngx_uint_t do_write)

{

...

// from_upstream為1,src為upstream(上游),dst為downstream(下游)

if (from_upstream) {

src = upstream;

dst = downstream;

b = &u->buffer;




}

for ( ;; ) {

// do_write為0忽略。

if (do_write) {}

if (size && src->read->ready) {

// src為upstream,用來讀

n = src->recv(src, b->last, size);

// n >0 接收大于0的字節(jié)數(shù),do_write置為1,continue進(jìn)行寫入

if (n > 0) {

do_write = 1;

b->last += n;




if (from_upstream) {

u->state->bytes_received += n;

}

continue;

}

// 加入三個計時器,upstream讀寫都加,downstream只加寫入,相當(dāng)于除了client的接收沒加計時器,都加了

if (upstream->write->active && !upstream->write->ready) {

ngx_add_timer(upstream->write, u->conf->send_timeout);

} else if (upstream->write->timer_set) {

ngx_del_timer(upstream->write);

}

if (upstream->read->active && !upstream->read->ready) {

ngx_add_timer(upstream->read, u->conf->read_timeout);

} else if (upstream->read->timer_set) {

ngx_del_timer(upstream->read);

}


if (downstream->write->active && !downstream->write->ready) {

ngx_add_timer(downstream->write, clcf->send_timeout);

} else if (downstream->write->timer_set) {

ngx_del_timer(downstream->write);

}

...

}

到此,關(guān)于“nginx websocket有什么特點”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI