如何从不同的服务器连接到 websocket?

Posted

技术标签:

【中文标题】如何从不同的服务器连接到 websocket?【英文标题】:How to connect to a websocket from a different server? 【发布时间】:2015-08-14 18:24:15 【问题描述】:

我有 server A “windows 7 Pro”,我在其中安装了 node.js 并使用此命令运行它 node ws_server.js following the instructions here

从运行 Apache 2.4/php 5.6.13 的 服务器 B“Windows Server 2008 R2”我想连接到 服务器 A 上的 ws_server

在 **Server B* 上,我有一个名为 websocket.php 的脚本,代码如下

<script>

        $(function() 

            var WebSocketClient = require('websocket').client;

            var client = new WebSocketClient();

            client.on('connectFailed', function(error) 
                console.log('Connect Error: ' + error.toString());
            );

            client.on('connect', function(connection) 
                console.log('WebSocket Client Connected');
                connection.on('error', function(error) 
                    console.log("Connection Error: " + error.toString());
                );
                connection.on('close', function() 
                    console.log('echo-protocol Connection Closed');
                );
                connection.on('message', function(message) 
                    if (message.type === 'utf8') 
                        console.log("Received: '" + message.utf8Data + "'");
                    
                );

                function sendNumber() 
                    if (connection.connected) 
                        var number = Math.round(Math.random() * 0xFFFFFF);
                        connection.sendUTF(number.toString());
                        setTimeout(sendNumber, 1000);
                    
                
                sendNumber();
            );

            client.connect('ws://ServerA:8080/', 'echo-protocol');
        );

    </script>

但由于某种原因,我在控制台中收到此错误。

ReferenceError: 要求未定义

我是否需要从服务器 A 的 nodejs 文件夹中获取文件并将其包含在客户端脚本中?如果需要,我需要包含哪些文件?

注意:我也包含了 jQuery 文件

已编辑

这是我的客户代码

       <script>
            "use strict";
            // Initialize everything when the window finishes loading
            window.addEventListener("load", function(event) 
              var status = document.getElementById("status");
              var url = document.getElementById("url");
              var open = document.getElementById("open");
              var close = document.getElementById("close");
              var send = document.getElementById("send");
              var text = document.getElementById("text");
              var message = document.getElementById("message");
              var socket;

              status.textContent = "Not Connected";
              url.value = "ws://serverB:8080";
              close.disabled = true;
              send.disabled = true;

              // Create a new connection when the Connect button is clicked
              open.addEventListener("click", function(event) 
                open.disabled = true;
                socket = new WebSocket(url.value, "echo-protocol");

                socket.addEventListener("open", function(event) 
                  close.disabled = false;
                  send.disabled = false;
                  status.textContent = "Connected";
                );

                // Display messages received from the server
                socket.addEventListener("message", function(event) 
                  message.textContent = "Server Says: " + event.data;
                );

                // Display any errors that occur
                socket.addEventListener("error", function(event) 
                  message.textContent = "Error: " + event;
                );

                socket.addEventListener("close", function(event) 
                  open.disabled = false;
                  status.textContent = "Not Connected";
                );
              );

              // Close the connection when the Disconnect button is clicked
              close.addEventListener("click", function(event) 
                close.disabled = true;
                send.disabled = true;
                message.textContent = "";
                socket.close();
              );

              // Send text to the server when the Send button is clicked
              send.addEventListener("click", function(event) 
                socket.send(text.value);
                text.value = "";
              );
            );
  </script>

【问题讨论】:

你为什么不简单地使用 socket.io ? 我不知道。根据我的阅读,我同时需要 node.js 和 socket.io 【参考方案1】:

Taxicala 答案是正确的,你不需要 require。 我认为您可以尝试这段代码以查看套接字是否正常工作

 var ws = new WebSocket('wss://ServerA:8080/', 'echo-protocol');
 ws.onopen = function () 
     console.log('socket connection opened properly');
     ws.send("Hello World"); // send a message
     console.log('message sent');
 ;

 ws.onmessage = function (evt) 
     console.log("Message received = " + evt.data);
 ;

 ws.onclose = function () 
     // websocket is closed.
     console.log("Connection closed...");
 ;

为了避免安全错误,您应该将 Web 套接字服务器创建为 https 而不是 http,这是您在相关链接中提供的代码,它适用于生成一个安全服务器,允许所有站点的 CORS 和方法,仅用于测试建议。

请注意,您需要生成证书,并将其存储在名为 certs2 的文件夹中,如果您需要创建证书的说明,只需 google 一下,有很多很好的答案。

//CUSTOM
var WebSocketServer = require('websocket').server;
var https = require('https');
var fs = require('fs');

var options = 
    key: fs.readFileSync('./certs2/key.pem'),
    cert: fs.readFileSync('./certs2/key-cert.pem')
;

var server = https.createServer(options, function (req, res) 
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
    res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
    res.writeHead(404);
    res.end();
);
// END CUSTOM
// START YOUR CODE....
server.listen(8080, function() 
    console.log((new Date()) + ' Server is listening on port 8080');
);

wsServer = new WebSocketServer(
    httpServer: server,
    // You should not use autoAcceptConnections for production
    // applications, as it defeats all standard cross-origin protection
    // facilities built into the protocol and the browser.  You should
    // *always* verify the connection's origin and decide whether or not
    // to accept it.
    autoAcceptConnections: false
);

function originIsAllowed(origin) 
    // put logic here to detect whether the specified origin is allowed.
    return true;


wsServer.on('request', function(request) 
    if (!originIsAllowed(request.origin)) 
        // Make sure we only accept requests from an allowed origin
        request.reject();
        console.log((new Date()) + ' Connection from origin ' + request.origin + ' rejected.');
        return;
    

    var connection = request.accept('echo-protocol', request.origin);
    console.log((new Date()) + ' Connection accepted.');
    connection.on('message', function(message) 
        if (message.type === 'utf8') 
            console.log('Received Message: ' + message.utf8Data);
            connection.sendUTF(message.utf8Data);
        
        else if (message.type === 'binary') 
            console.log('Received Binary Message of ' + message.binaryData.length + ' bytes');
            connection.sendBytes(message.binaryData);
        
    );
    connection.on('close', function(reasonCode, description) 
        console.log((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.');
    );
);

【讨论】:

我刚刚测试了你的代码。我明白了SecurityError: The operation is insecure. 您需要在您的服务器中启用 CORS 标头。另外,请注意混合内容是这里的另一个问题,您正在尝试在 http 和 https 之间创建通信。 是的,您不能对安全环境执行不安全的请求,反之亦然,(HTTP 到 HTTPS 或 HTTPS 到 HTTP)是添加到较新浏览器版本的浏览器限制。 @MikeA 我已经编辑了答案。考虑到如果证书不受信任,您可能需要手动访问 https:// server:8080 至少一次。 尝试像openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem 这样创建证书,然后重新启动脚本。 (使用您提供的行,我可以重现该问题,这样就可以了)【参考方案2】:

require 是 nodejs 使用的库,它自然不存在于window 中。我相信您正在尝试使用您在 nodejs 环境中使用的代码。

要在基于 Web 的环境中创建套接字,请查看 WebSocket 参考。

WebSockets 在最新的浏览器版本中实现,您可以按如下方式创建它们:

var exampleSocket = new WebSocket("ws://www.example.com/socketserver", "protocolOne");

【讨论】:

我在服务器上安装了 websocket,我试图从客户端连接到它,这给了我错误。如何在我的客户端代码中包含 require 库? 你可以使用 requirejs 但它与 nodejs 库不同。我认为这里不需要包含任何内容,浏览器为您提供了开箱即用的 WebSocket 接口。您在这里混合了服务器端 js 和客户端 js。 您应该阅读和调查 CORS 和同源政策。【参考方案3】:

我遇到了套接字挂断错误。

const WebSocket = require('ws');
const ws = new WebSocket('wss://127.0.0.1:8080');

events.js:183
      throw er; // Unhandled 'error' event
      ^

Error: socket hang up
    at TLSSocket.onHangUp (_tls_wrap.js:1137:19)
    at Object.onceWrapper (events.js:313:30)
    at emitNone (events.js:111:20)
    at TLSSocket.emit (events.js:208:7)
    at endReadableNT (_stream_readable.js:1064:12)
    at _combinedTickCallback (internal/process/next_tick.js:138:11)
    at process._tickCallback (internal/process/next_tick.js:180:9)

我可以通过修改 websocket 连接代码来解决这个问题。

const ws = new WebSocket('ws://127.0.0.1:8080/ws');

【讨论】:

以上是关于如何从不同的服务器连接到 websocket?的主要内容,如果未能解决你的问题,请参考以下文章

如何在NodeJS中代理websocket连接到其他websockets

Spring WebSocket 使用 SockJS 连接到不同的域

使用 Echo 客户端示例从 Qt UI 连接到 WebSocket 服务器

从python代码连接到Flask websocket [重复]

连接到 WebSocket 时如何覆盖 Chrome 中的 Origin 标头?

从 websockets 更新数据时,如何在不连接到每个子组件的情况下更新单个子组件?