这篇文章主要介绍“nginx websocket有什么特点”,在日常操作中,相信很多人在nginx websocket有什么特点问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”nginx 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配置时,可以通过在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;
在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有什么特点”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。
原文链接:https://www.freebuf.com/articles/web/256109.html