新西兰服务器

nginx websocket有什么特点


nginx websocket有什么特点

发布时间:2021-11-30 11:59:26 来源:高防服务器网 阅读:69 作者:iii 栏目:网络管理

这篇文章主要介绍“nginx websocket有什么特点”,在日常操作中,相信很多人在nginx websocket有什么特点问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”nginx websocket有什么特点”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

websocket协议简介

websocket是基于TCP的应用层协议,用于在C/S架构的应用中实现双向通信,rfc文档说明rfc6455。
websocket在建立连接时会使用HTTP协议,所以websocket协议是基于HTTP协议实现的。

目前很多卡牌类的游戏选择使用websocket协议进行通信。

websocket具备如下特点:

1.可以进行双向通信,会话通信实时性强。

2.建立起websocket连接,可以一直保持连接,在此期间可以源源不断的发送消息,直到关闭请求。避免了HTTP的非状态性(连接时总开销减少)。和http相比连接创建后,客户端服务端进行数据交换时,协议控制的数据包头部较小(通信量减少)。

3.web服务器与客户端之间建立起连接后,所有的通信都依靠这个专用协议进行。通信过程中可互相发送JSON、XML、HTML或图片等任意格式的数据。不论服务器还是客户端,任意一方都可直接向对方发送数据。

4.更好的二进制支持,支持扩展。

websocket协议格式:

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; //超时设置           //启用支持websocket           proxy_set_header Upgrade $http_upgrade;           proxy_set_header Connection "upgrade";        }  }

如上配置它表明websocket请求连接的时候,升级连接将http连接变成websocket连接。

但这里会有一个问题,这样在server{}块中配置websocket,该server{}必须处理websocket流量,所有发往后端的流量都带上upgrade和connection头。

proxy_set_header  Upgrade $http_upgrade;

proxy_set_header  Connection $connection_upgrade;

nginx websocket源码优化

在server{}中配置websocket时,所有发往后端upstream的流量会添加websocket头。

假如发往后端upstream的请求,有的需要添加websocket头升级为websocket,有的请求不需要,如果继续使用原生的nginx配置,会导致该场景该配置,出现问题。

所以该场景下需改动和优化nginx源码,来区分client的流量是否是websocket。

ngx_http_proxy_websocket_headers:区别在于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标志    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,添加标志    } else if (ngx_strcasestrn(r->headers_in.upgrade->value.data, "websocket", 9 - 1)) {    r->is_websocket_request |= NGX_WEBSOCKET_HEADER_UPGRADE;    }    // 两种标志都有,r->websocket_request 标志位置位    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的标志位    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种使用该标志位    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给上下游设置读写事件    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;    ...    }    每个读写时间所用的函数都是一样的,入参不同: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的字节数,do_write置为1,continue进行写入    if (n > 0) {    do_write = 1;    b->last += n;          if (from_upstream) {    u->state->bytes_received += n;    }    continue;    }    // 加入三个计时器,upstream读写都加,downstream只加写入,相当于除了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);    }    ...    }

到此,关于“nginx websocket有什么特点”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注高防服务器网网站,小编会继续努力为大家带来更多实用的文章!

[微信提示:高防服务器能助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。

[图文来源于网络,不代表本站立场,如有侵权,请联系高防服务器网删除]
[