https://github.com/joewalnes/websocketd

这个工具可以把普通命令行命令转成ws协议,web客户端可以通过websocket连接,互换数据;
当有连接过来的时候,会启动进程执行指定的命令,如果命令结束或者连接断开,则连接关闭,进程结束;
连接后,将客户端send过来的数据,作为STDIN标准输入,传入进程,进程的标准输出STDOUT会作为message消息发送给客户端(\n结束作为一条消息);
启动服务:

cat startNotify.sh

#!/usr/bin/env bash
websocketd --port=1234 ./demp.sh

./startNotify.sh
#或者后台运行
nohup ./startNotify.sh > /dev/null 2>&1 &

一个发什么回什么的服务端脚本代码大概这样子:demp.sh

#! /pathto/php
<?hp

while (!feof(STDIN)) {
    $line = fgets(STDIN);
    echo $line;
}

?>

建立websocket连接,web网页

<script>
        var ws = new WebSocket('ws://127.0.0.1:1234')
        ws.onopen = function () {
            console.log('ws connected')
            ws.onclose = function () {
                console.log('ws closed');
            }
            ws.onmessage = function (res) { console.log(res.data) }

            var count = 0;
            
            setInterval(function () {
                ws.send(count++)
            }, 2000)
        }
        ws.onerror = function (e) {console.log(e)}
</script>

ssl网页,要用wss协议连接,通过nginx反代吧

map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

upstream notify_ws {
    server 127.0.0.1:1234; # appserver_ip:ws_port
}

server
{

location / {

         proxy_pass http://notify_ws;
         proxy_read_timeout 300s;
         proxy_send_timeout 300s;
         
         proxy_set_header Host $host;
         proxy_set_header X-Real-IP $remote_addr;
         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
         
         proxy_http_version 1.1;
         proxy_set_header Upgrade $http_upgrade;
         proxy_set_header Connection $connection_upgrade;
         
}

}

关键在于这两行:
最重要的就是在反向代理的配置中增加了如下两行,其它的部分和普通的HTTP反向代理没有任何差别。

proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;

这里面的关键部分在于HTTP的请求中多了如下头部:

Upgrade: websocket
Connection: Upgrade

这两个字段表示请求服务器升级协议为WebSocket。服务器处理完请求后,响应如下报文:

# 状态码为101
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: upgrade

告诉客户端已成功切换协议,升级为Websocket协议。握手成功之后,服务器端和客户端便角色对等,就像普通的Socket一样,能够双向通信。 不再进行HTTP的交互,而是开始WebSocket的数据帧协议实现数据交换。

这里使用map指令可以将变量组合成为新的变量,会根据客户端传来的连接中是否带有Upgrade头来决定是否给源站传递Connection头, 这样做的方法比直接全部传递upgrade更加优雅。

默认情况下,连接将会在无数据传输60秒后关闭,proxy_read_timeout参数可以延长这个时间。源站通过定期发送ping帧以保持连接并确认连接是否还在使用。

两个超时参数

proxy_read_timeout

语法 proxy_read_timeout time 默认值 60s 上下文 http server location 说明 该指令设置与代理服务器的读超时时间。它决定了nginx会等待多长时间来获得请求的响应。 这个时间不是获得整个response的时间,而是两次reading操作的时间。

proxy_send_timeout

语法 proxy_send_timeout time 默认值 60s 上下文 http server location 说明 这个指定设置了发送请求给upstream服务器的超时时间。超时设置不是为了整个发送期间,而是在两次write操作期间。 如果超时后,upstream没有收到新的数据,nginx会关闭连接

多次代理转发
工作中遇见过一种情况,就是某个域名在移动网络下面访问不了,这样的话我需要通过一个前段代理服务器做转发,这样就涉及到两次代理。

比如访问的websocket服务URL为:

wss://test.enzhico.net

这个在腾讯云公网IP上面,所有网络都能访问。另外一个域名board.xncoding.com解析到电信网络,部署在网关中心,这个域名腾讯云可以访问到。

在腾讯云主机上面:

map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

server {
     server_name test.enzhico.net;
     location / {
         proxy_pass http://board.xncoding.com;
         proxy_read_timeout 300s;
         proxy_send_timeout 300s;
         #proxy_set_header Host $host;
         proxy_set_header X-Real-IP $remote_addr;
         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
         proxy_http_version 1.1;
         proxy_set_header Upgrade $http_upgrade;
         proxy_set_header Connection $connection_upgrade;
    }
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/test.enzhico.net/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/test.enzhico.net/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}

上面唯一要注意的是忙,把proxy_set_header Host $host;这一行注释掉了。

而在网关中心主机上面:

map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

upstream websocket {
    server localhost:8282; # appserver_ip:ws_port
}

server {
    listen 80;
    server_name board.xncoding.com;
    location / {
        proxy_pass http://websocket;
        proxy_read_timeout 300s;
        proxy_send_timeout 300s;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
    }
}

只需要最外层使用wss协议,里面的交互都使用ws协议,所以监听80端口即可。

参考文章:
https://www.xncoding.com/2018/03/12/fullstack/nginx-websocket.html
https://www.hi-linux.com/posts/42176.html

标签: none

添加新评论