RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 706832
Accepted
Mcile
Mcile
Asked:2020-08-16 23:30:23 +0000 UTC2020-08-16 23:30:23 +0000 UTC 2020-08-16 23:30:23 +0000 UTC

网络套接字连接

  • 772

等待 10 秒后,我无法通过 websocket 连接到我自己的端口http://localhost:1100上的服务器 ,它在浏览器控制台中出现错误

'wss://tel.buy-tires.ru:1100/' failed: Error in connection establishment: net::ERR_CONNECTION_TIMED_OUT

javascript代码

<script>
            var socket= new WebSocket('ws://tel.buy-tires.ru:1100/');
            socket.onopen = function() {
              console.log("Соединение установлено.");
            };
        </script>

服务器在端口 1100 上有一个服务器套接字。如果您使用 sudo lsof -i 命令监听所有端口,它会给出

TCP localhost:1100 (LISTEN)

尝试配置nginx

location /ws/ {
    proxy_pass http://localhost:1100;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";

}

在此服务器上运行的套接字客户端可以与 ip localhost 端口 1100 上的套接字服务器正常通信

我要求管理员在 pfsense 上打开端口 1100 - 他们打开了它。

在以管理员身份通过 telnet 启动的 Windows 命令行中,我在端口 80 上进行了监听 - 连接已建立,但无法爬升至 1100。这是我第一次遇到这种设置,我阅读了很多文章-实际上,我所做的所有操作都是从那里采取的。我不知道该怎么做。

17.08.2017

感谢@D-side,我明白了为什么不能监听来自外部的传入连接,因为我没有地址因为地址,但是按照nginx的设置,我不得不联系

 var socket= new WebSocket('ws://tel.buy-tires.ru/ws/');

现在服务器看到有一个到套接字的连接,但由于某种原因,浏览器 websocket 没有看到我放入套接字缓冲区的消息 - 服务器以 http 标头形式的响应 - 经过长时间的等待,nginx代码生成的header 502来了,虽然我发的是101

我也不需要 nginx 欺骗的 INCOMING 标头,所以我将设置简化为

location /ws/ {
    proxy_pass http://localhost:1100;
}

当我切断套接字服务器时,网络套接字等待响应 - 它立即反应连接断开

php
  • 2 2 个回答
  • 10 Views

2 个回答

  • Voted
  1. Best Answer
    Mcile
    2020-08-18T15:32:32Z2020-08-18T15:32:32Z

    我花了一周的时间每天 8 小时与 web-socket-server 建立浏览器连接,因为我从来没有遇到过这种情况。为了帮助像我这样的人,我会将那些对初学者并不明显的发现提供给那些第一次遇到它们的人以寻求帮助和理解。

    1 不要打扰服务器端口,尤其是防火墙。套接字服务器指定要在环回上打开哪个端口就足够了,又名 localhos,又名 127.0.0.1。

    重要提示:端口 1 到 1024 由操作系统保留 - 最好不要触摸它们。分别从 1025 到 65500 个端口供您使用

    2 Nginx 设置应该是最小的

    #обязательно пробел между словом и скобкой
    server {
       # череда настроек вашего сервера
       # ---------------------------
       # вписываем настройки для работы с сокет-сервером с поддержкой web-sockets
       # вы можете написать вместо /ws/ все что пожелаете, лишь бы обратиться
       # по java-script у
       location /ws/ {
          # соединяем порт, открытый по localhos(доступный только внутри) 
          # с внешним миром (я использовал в данном примере порт 1100)
          # если у вас вырублен сокет сервер и процесс на порту не висит
          # то никто не подключится к этому порту
          proxy_pass http://localhost:1100;
          # если вы хотите чтобы соединение не разрывалось - выставите время 
          # в секундах - у меня 10 часовой рабочий день 60*60*10
          proxy_read_timeout 36000;
       }
       # -------------------------------------------------------------------------
    }
    

    基本上3条主线。

    location /ws/ {
       proxy_pass http://localhost:1100;
    }
    

    重要规则:

    保存配置后,确保您没有弄乱 nginx 配置的语法 - 在控制台中运行命令

    sudo nginx -t
    

    如果它说好的然后重新启动nginx

    sudo nginx -s reload
    

    实际上,这足以接收来自 Internet 的传入信号。

    如果你在控制台中的浏览器出现500错误,那么你就是在网上敲错了地址。我敢说,如果您的浏览器出现错误 502、301、302、200,那么这是套接字服务器中的错误代码,它也是 web-socket-server。在这种情况下,从小处着手 - 将标头发送到浏览器并检查编码 - 只有 UTF-8 才可能没有 BOM

    //$command = 'HTTP/1.1 101 Switching Protocols' . PHP_EOL;
    //это неправильная команда - потому что для HTTP обязателен символ 
    //переноса карретки
    //$command = 'HTTP/1.1 101 Switching Protocols\n\r';
    //это тоже неправильно! из за этого я убил пару дней, а все почему?
    // \n\r в одинарных ковычках читаются как текст!!!, а нужно как спецсимволы
    //вот теперь правильно и у вас все получиться
    $command = "HTTP/1.1 101 Switching Protocols\n\r";
    socket_write( $client, $command);
    

    如果在那之后浏览器会发誓其他事情,那么你就在正确的轨道上并且已经向浏览器发送了 101 响应代码!我还建议查看您的套接字服务器发送的标头。在此处写下您的观察... 在此处输入图像描述 这是来自网络部分的 Google-Chrome 浏览器(启用 - 按 F12 并转到网络选项卡并刷新页面)

    碰巧您错误地关闭了端口,即 您想再次启动套接字服务器,控制台会告诉您该端口已在使用中。要查看哪个进程正在使用此端口,请运行命令

    lsof -i tcp:1100
    

    就我而言,我正在侦听端口 1100 在此处输入图像描述 并在命令中释放我们驱动的端口

    sudo kill -9 13905
    

    在我的例子中,13905 是挂在服务器处理器上并使用端口的服务器进程的 PID,在我的例子中是端口 1100,-9 参数意味着我们正在向处理器发送命令以终止进程

    为了方便关闭服务器,我使用了一个带有shutdown server socket 命令的socket 客户端。

    为了通过 web-socket 与浏览器完全建立连接,您需要向浏览器的请求发送一个 http 标头,其中包含浏览器的全面信息,即

    $command = 'HTTP/1.1 101 Switching Protocols' . PHP_EOL
     .'Upgrade: websocket' . PHP_EOL
     .'Connection: Upgrade' . PHP_EOL
     .'Sec-WebSocket-Accept: '.$responce_key . PHP_EOL
     .'Sec-WebSocket-Version: 13' . PHP_EOL . PHP_EOL;
    socket_write( $client, $command);
    

    如何生成加密的$responce_key?

    答: 要做到这一点,您需要从标头“Sec-WebSocket-Key: \n\r” http 请求中获取 - web-socket 发送给您的密钥并使用函数对其进行处理

    function getWebSocketAccept( $key )
    {
        $guid = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
        $sec_websocket_accept = $key . $guid;
        $sec_websocket_accept = sha1($sec_websocket_accept, true);
        return base64_encode($sec_websocket_accept);
    }
    

    然后,当然,“云”会突然跳舞:)

    为了让 web-socket-server 能够理解浏览器发送给它的任何信息,在成功的“握手”之后,web socket 服务器将需要对消息进行解码,并且为了让浏览器能够理解web-socket-server 发送了什么,数据必须以编码形式到达。功能(需要验证)

    /**
         * Декодирование строки
         * 
         * @param string $str
         * @param boolean $message_only
         * @return array | string
         */
        function decode($str, $message_only = false)
        {
            /* Разбираем заголовок */
            $header = unpack("n", $str)[1];         /* Рапаковываем первые 16 бит, порядок байт «big endian», т.к. сетевой протокол */
            $data = [];
            $data['fin']            = (bool) (($header >> (16 - 1))  & 0b1);        /* Финальный фрейм. Если сообщение нефрагмантированное, то всегда 1, если фрагмантированно, то у последнего 1 у остальных 0 */
            $data['rsv1']           = (bool) (($header >> (16 - 2))  & 0b1);        /* Флаги RSV1, RSV2, RSV3 служат для расширений протокола, почти всегда в false */
            $data['rsv2']           = (bool) (($header >> (16 - 3))  & 0b1);
            $data['rsv3']           = (bool) (($header >> (16 - 4))  & 0b1);
            $data['opcode']         = (int)  (($header >> (16 - 8))  & 0b1111);     /* Тип фрейма */
            $data['is_mask']        = (bool) (($header >> (16 - 9))  & 0b1);        /* Замаскированы ли фреймы */
            $data['length_prev']    = (int)  (($header >> (16 - 16)) & 0b1111111);  /* Предварительная длина фрейма */
    
            /* Определяем тип фрейма */
            $data['type'] = $this->_get_type_frame($data['opcode']);
    
            /* Определяем длину фрейма */
            if ($data['length_prev'] < 126)
            {
                $data['length'] = $data['length_prev'];
            }
            elseif ($data['length_prev'] === 126)
            {
                $data['length'] = unpack("x2/n", $str)[1];
            }
            elseif ($data['length_prev'] > 126)
            {
    //          $data['length'] = unpack("x2/J", $str)[1];
                $data['length'] = unpack("x2/x4/N", $str)[1];
            }
    
            /* Маска */
            if ($data['is_mask'])
            {
                if ($data['length_prev'] < 126)
                {
                    $mask = substr($str, 2, 4);
                }
                elseif ($data['length_prev'] === 126)
                {
                    $mask = substr($str, 2 + 2, 4);
                }
                elseif ($data['length_prev'] > 126)
                {
                    $mask = substr($str, 2 + 8, 4);
                }
            }
    
            /* Тело запроса */
            $message_start = 2;
            if ($data['length_prev'] < 126)
            {
    
            }
            elseif ($data['length_prev'] === 126)
            {
                $message_start += 2;
            }
            elseif ($data['length_prev'] > 126)
            {
                $message_start += 8;
            }
    
            if ($data['is_mask'])
            {
                $message_start += 4;
            }
            $data['message_start'] = $message_start;
    
            $message = substr($str, $message_start, $data['length']);
    
            /* Размаскируем сообщение */
            if ($data['is_mask'])
            {
                $length = strlen($message);
    
                for ($i = 0; $i < $length; $i++) 
                {
                    $message[$i] = $message[$i] ^ $mask[$i % 4];
                }
            }
    
            $data['message'] = $message;
    
            /* Возвращаем сообщение */
            if ($message_only === false)
            {
                return $data;
            }
            else
            {
                return $data['message'];
            }
        }
    
        /**
         * Закодировать строку
         * 
         * @param string $str
         * @param boolean $is_mask
         * @return string
         */
        function encode($str, $is_mask = false)
        {
            $bin = "";
    
            /* Основные флаги */
            $data = 
            [
                "fin" => 0b1,
                "rsv1" => 0b0,
                "rsv2" => 0b0,
                "rsv3" => 0b0,
                "opcode" => 0x1,
                "is_mask" => $is_mask === true ? 0b1 : 0b0,
                "length" => strlen($str)
            ];
    
            /* Предварительная длина */
            if ($data['length'] < 126)
            {
                $data['length_prev'] = $data['length'];
            }
            elseif ($data['length'] < 65536)
            {
                $data['length_prev'] = 126;
            }
            else
            {
                $data['length_prev'] = 127;
            }
    
            /* Заголовок */
            $header = $data['fin'];
            $header = $header << 1 | $data['rsv1'];
            $header = $header << 1 | $data['rsv2'];
            $header = $header << 1 | $data['rsv3'];
            $header = $header << 4 | $data['opcode'];
            $header = $header << 1 | $data['is_mask'];
            $header = $header << 7 | $data['length_prev'];
            $bin .= pack("n", $header);
    
            /* Расширенная длина тела */
            if ($data['length_prev'] === 126)
            {
                $bin .= pack("n", $data['length']);
            }
            elseif ($data['length_prev'] > 126)
            {
                $bin .= pack("x4N", $data['length']);
            }
    
            /* Маскировать сообщение */
            if ($is_mask)
            {
                $mask = substr(md5(microtime()), 0, 4);
                $bin .= $mask;
    
                $length = strlen($str);
                for ($i = 0; $i < $length; $i++) 
                {
                    $str[$i] = $str[$i] ^ $mask[$i % 4];
                }
            }
    
            $bin .= $str;
    
            return $bin;
        }
    
    • 1
  2. mr_makss
    2020-08-18T17:34:32Z2020-08-18T17:34:32Z

    尝试例如用于 nodejs 的 socket.io(https://socket.io/)或用于 php 的棘轮(http://socketo.me/)
    在我看来,你是在野外epoll c++。
    借助我介绍的工具,你可以在1-30分钟内轻松建立101个浏览器和服务器之间的连接

    当我切断套接字服务器时,网络套接字等待响应 - 它立即反应连接断开
    - 应该是这样的。
    可以将插座视为插入插座的插头。
    通过从电路中移除插头或插座,您将断开电路。

    在套接字编程中,类似地,如果您删除服务器部分,您将在客户端收到连接错误(即,客户端部分将查找节点)
    如果您删除客户端部分,则服务器会收到来自的断开连接事件客户端(客户端可以为此事件断开连接)

    • 0

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    Python 3.6 - 安装 MySQL (Windows)

    • 1 个回答
  • Marko Smith

    C++ 编写程序“计算单个岛屿”。填充一个二维数组 12x12 0 和 1

    • 2 个回答
  • Marko Smith

    返回指针的函数

    • 1 个回答
  • Marko Smith

    我使用 django 管理面板添加图像,但它没有显示

    • 1 个回答
  • Marko Smith

    这些条目是什么意思,它们的完整等效项是什么样的

    • 2 个回答
  • Marko Smith

    浏览器仍然缓存文件数据

    • 1 个回答
  • Marko Smith

    在 Excel VBA 中激活工作表的问题

    • 3 个回答
  • Marko Smith

    为什么内置类型中包含复数而小数不包含?

    • 2 个回答
  • Marko Smith

    获得唯一途径

    • 3 个回答
  • Marko Smith

    告诉我一个像幻灯片一样创建滚动的库

    • 1 个回答
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Алексей Шиманский 如何以及通过什么方式来查找 Javascript 代码中的错误? 2020-08-03 00:21:37 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    user207618 Codegolf——组合选择算法的实现 2020-10-23 18:46:29 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5