是否可以使用同一个端口同时启用TCP、HTTP和WebSocket?

21
我正在尝试在同一端口上启用tcp, httpwebsocket.io通信。我从tcp服务器(////行上面的部分)开始,它能够正常工作。然后我运行了在websocket.io上找到的echo服务器示例(////行下面的部分),它也能够正常工作。但是当我尝试将它们合并在一起时,tcp就无法工作了。
所以,是否有可能使用同一端口同时启用tcp、http和websockets?或者我必须在另一个端口上监听tcp连接?
var net = require('net');
var http = require('http');
var wsio = require('websocket.io');

var conn = [];

var server = net.createServer(function(client) {//'connection' listener
    var info = {
        remote : client.remoteAddress + ':' + client.remotePort
    };
    var i = conn.push(info) - 1;
    console.log('[conn] ' + conn[i].remote);

    client.on('end', function() {
        console.log('[disc] ' + conn[i].remote);
    });

    client.on('data', function(msg) {
        console.log('[data] ' + conn[i].remote + ' ' + msg.toString());
    });

    client.write('hello\r\n');
});

server.listen(8080);

///////////////////////////////////////////////////////////

var hs = http.createServer(function(req, res) {
    res.writeHead(200, {
        'Content-Type' : 'text/html'
    });
    res.end(['<script>', "var ws = new WebSocket('ws://127.0.0.1:8080');", 'ws.onmessage = function (data) { ws.send(data); };', '</script>'].join(''));
});

hs.listen(server);

var ws = wsio.attach(hs);
var i = 0, last;

ws.on('connection', function(client) {

    var id = ++i, last

    console.log('Client %d connected', id);

    function ping() {
        client.send('ping!');
        if (last)
            console.log('Latency for client %d: %d ', id, Date.now() - last);
        last = Date.now();
    };

    ping();
    client.on('message', ping);

});

1
HTTP通常运行在TCP之上。HTTP和TCP是什么意思? - John Dvorak
这就是我犹豫的原因。我的服务器需要通过浏览器与Websockets通信,也需要通过移动应用程序与TCP连接通信。因此,我需要同时支持这两种协议。 - Some Noob Student
也许你可以以原始TCP方式监听,如果检测到HTTP,则手动转发到另一个处理程序。同样,如果从HTTP服务器检测到WS(WS起始为HTTP),则再次委派。 - John Dvorak
通常情况下,您应该使用HTTP来区分所有内容,并通过URL进行区分,或在不同的端口上运行原始TCP。 - John Dvorak
请注意,HTTP流通常使用GZIP进行压缩,使用原始套接字并不能获得太多好处(使用一个双工TCP连接而不是两个单工连接并不是真正的优势)。您确实可以获得消息序列化(除非WS也是双工的)。 - John Dvorak
3个回答

35
您可以让同一个端口处理多种不同的协议,但是需要注意以下几点:
  • 服务器必须有某种方式来检测(或协商)客户端所希望使用的协议。您可以将独立端口视为检测客户端所希望使用的协议的常规方法。

  • 只能有一个服务器进程实际上在监听该端口。该服务器可能只用于检测协议类型,然后转发到多个其他服务器,但每个端口都由单个服务器进程拥有。

  • 不能支持服务器先发言的多个协议(因为没有办法检测客户端的协议)。您可以通过增加接受后的短暂延迟来支持单个服务器先发言的协议和多个客户端先发言的协议,但这有点奇怪。

WebSocket协议的明确设计目标是允许WebSocket和HTTP协议共享同一服务器端口。初始WebSocket握手是与HTTP兼容的升级请求。

Websockify服务器/桥接器是可以在同一端口上使用5种不同协议的服务器的示例:HTTP,HTTPS(加密的HTTP),WS(WebSockets),WSS(加密的WebSockets)和Flash策略响应。服务器会查看传入请求的第一个字符,以确定它是否是TLS加密的(HTTPS或WSS),或者是否以“<”开头(Flash策略请求)。如果是Flash策略请求,则读取请求,响应并关闭连接。否则,它将读取HTTP握手(加密或非加密),并根据Connection和Upgrade标头确定它是WebSocket请求还是纯HTTP请求。

免责声明:我制作了Websockify


@kanaka:一个单一端口可以连接多少客户端?我想知道Java Web应用程序同时可以处理多少个Web套接字连接?每个Web套接字请求从客户端发出时,服务器上是否需要不同的端口? - Dax Joshi
2
@DaxJoshi 可能最好是提出一个单独的问题。这也与Websockets无关。处理TCP连接被接受的服务器端口可以处理大量连接。您不需要为每个客户端使用单独的服务器端口。在websockify情况下,如果您想让不同的客户端通过websockify连接到不同的目标,则应查看websockify的TokenFile插件/目标配置功能。 - kanaka

0

简短回答 - 不行,你不能在同一个端口上运行不同的TCP/HTTP/Websocket服务器。

稍长回答 - Websockets和HTTP都是基于TCP协议工作的。因此,您可以将http服务器或websocket服务器视为自定义TCP服务器(具有一些状态管理和协议特定的编码/解码)。在同一台机器上无法绑定多个套接字到相同的端口/协议对,因此第一个套接字将获胜,后续的套接字将收到套接字绑定异常。


不,您不能将多个“服务器”或服务绑定到同一端口,但您肯定可以拥有一个单一的服务来处理HTTP和Websocket请求。 - curiouser

0
Nginx允许您在同一端口上运行http和websocket,并将其转发到正确的应用程序。请参见this article

1
虽然这个链接可能回答了问题,但最好在此处包含答案的基本部分并提供参考链接。仅有链接的答案如果链接页面发生更改可能会变得无效。 - Tyler2P
虽然这个链接可能回答了问题,但最好在此处包含答案的基本部分并提供参考链接。如果链接页面更改,仅有链接的答案可能会失效。-【来自审查】 - Aaron Meese

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接