创建一个“Hello World"WebSocket 示例 [英] Creating a "Hello World" WebSocket example

查看:32
本文介绍了创建一个“Hello World"WebSocket 示例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不明白为什么我不能让下面的代码工作.我想用 JavaScript 连接到我的服务器控制台应用程序.然后向服务器发送数据.

I don't understand why I cannot make the following code work. I want to connect with JavaScript to my server console application. And then send data to the server.

这是服务器代码:

    static void Main(string[] args)
    {            
        TcpListener server = new TcpListener(IPAddress.Parse("127.0.0.1"), 9998);
        server.Start();
        var client = server.AcceptTcpClient();
        var stream = client.GetStream();

        while (true)
        {
            var buffer = new byte[1024]; 
            // wait for data to be received
            var bytesRead = stream.Read(buffer, 0, buffer.Length);                
            var r = System.Text.Encoding.UTF8.GetString(buffer);
            // write received data to the console
            Console.WriteLine(r.Substring(0, bytesRead));
        }
    }

这里是 JavaScript:

and here is the JavaScript:

        var ws = new WebSocket("ws://localhost:9998/service");
        ws.onopen = function () {
            ws.send("Hello World"); // I WANT TO SEND THIS MESSAGE TO THE SERVER!!!!!!!!
        };

        ws.onmessage = function (evt) {
            var received_msg = evt.data;
            alert("Message is received...");
        };
        ws.onclose = function () {
            // websocket is closed.
            alert("Connection is closed...");
        };

当我运行该代码时,会发生以下情况:

When I run that code this is what happens:

请注意,当我运行 JavaScript 时,服务器接受并成功建立连接.但是 JavaScript 无法发送数据.每当我放置发送方法时,即使建立了连接,它也不会发送.我怎样才能做到这一点?

Note that when I run the JavaScript the server accepts and successfully establishes a connection. JavaScript is not able to send data though. Whenever I place the send method it will not send even though a connection is established. How can I make this work?

推荐答案

WebSockets 是一种依赖于 TCP 流连接的协议.虽然 WebSockets 是基于消息的协议.

WebSockets is protocol that relies on TCP streamed connection. Although WebSockets is Message based protocol.

如果您想实现自己的协议,那么我建议使用最新且稳定的规范(适用于 18/04/12)RFC 6455.该规范包含有关握手和帧的所有必要信息.以及大部分关于浏览器端和服务器端行为场景的描述.强烈建议在实现代码期间遵循有关服务器端的建议.

If you want to implement your own protocol then I recommend to use latest and stable specification (for 18/04/12) RFC 6455. This specification contains all necessary information regarding handshake and framing. As well most of description on scenarios of behaving from browser side as well as from server side. It is highly recommended to follow what recommendations tells regarding server side during implementing of your code.

简而言之,我会像这样描述使用 WebSockets 的情况:

In few words, I would describe working with WebSockets like this:

  1. 创建服务器套接字 (System.Net.Sockets) 将其绑定到特定端口,并通过异步接受连接保持侦听.类似的东西:
  1. Create server Socket (System.Net.Sockets) bind it to specific port, and keep listening with asynchronous accepting of connections. Something like that:

Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
serverSocket.Bind(new IPEndPoint(IPAddress.Any, 8080));
serverSocket.Listen(128);
serverSocket.BeginAccept(null, 0, OnAccept, null);

  1. 您应该具有接受函数OnAccept";这将实现握手.如果系统要每秒处理大量连接,那么将来它必须在另一个线程中.
  1. You should have accepting function "OnAccept" that will implement handshake. In future it has to be in another thread if system is meant to handle huge amount of connections per second.

private void OnAccept(IAsyncResult result) {
    try {
        Socket client = null;
        if (serverSocket != null && serverSocket.IsBound) {
            client = serverSocket.EndAccept(result);
        }
        if (client != null) {
            /* Handshaking and managing ClientSocket */
        }
    } catch(SocketException exception) {

    } finally {
        if (serverSocket != null && serverSocket.IsBound) {
            serverSocket.BeginAccept(null, 0, OnAccept, null);
        }
    }
}

  1. 建立连接后,您必须进行握手.根据规范1.3 Opening Handshake,建立连接后,您将收到基本的带有一些信息的 HTTP 请求.示例:
  1. After connection established, you have to do handshake. Based on specification 1.3 Opening Handshake, after connection established you will receive basic HTTP request with some information. Example:

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13

此示例基于协议 13 的版本.请记住,旧版本有一些差异,但大多数最新版本是交叉兼容的.不同的浏览器可能会向您发送一些额外的数据.例如浏览器和操作系统详细信息、缓存等.

This example is based on version of protocol 13. Bear in mind that older versions have some differences but mostly latest versions are cross-compatible. Different browsers may send you some additional data. For example Browser and OS details, cache and others.

根据提供的握手详细信息,您必须生成答案行,它们大多相同,但会包含 Accept-Key,即基于提供的 Sec-WebSocket-Key.在规范 1.3 中清楚地描述了如何生成响应密钥.这是我用于 V13 的函数:

Based on provided handshake details, you have to generate answer lines, they are mostly same, but will contain Accept-Key, that is based on provided Sec-WebSocket-Key. In specification 1.3 it is described clearly how to generate response key. Here is my function I've been using for V13:

static private string guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
private string AcceptKey(ref string key) {
        string longKey = key + guid;
        SHA1 sha1 = SHA1CryptoServiceProvider.Create();
        byte[] hashBytes = sha1.ComputeHash(System.Text.Encoding.ASCII.GetBytes(longKey));
        return Convert.ToBase64String(hashBytes);
}

握手回答看起来像这样:

Handshake answer looks like that:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

但是接受密钥必须是基于客户端提供的密钥和我之前提供的 AcceptKey 方法生成的密钥.同样,确保在接受键的最后一个字符之后添加两行新行 ".

But accept key have to be the generated one based on provided key from client and method AcceptKey I provided before. As well, make sure after last character of accept key you put two new lines " ".

  1. 从服务器发送握手应答后,客户端应触发onopen";功能,这意味着您可以在之后发送消息.

  1. After handshake answer is sent from server, client should trigger "onopen" function, that means you can send messages after.

消息不是以原始格式发送,但具有数据框架.并且从客户端到服务器也根据消息头中提供的 4 个字节实现数据屏蔽.尽管从服务器到客户端,您不需要对数据应用屏蔽.阅读部分 5.规范中的数据框架.这是我自己实现的复制粘贴.它不是现成的代码,必须进行修改,我发布它只是为了提供使用 WebSocket 框架进行读/写的想法和整体逻辑.转到此链接.

Messages are not sent in raw format, but they have Data Framing. And from client to server as well implement masking for data based on provided 4 bytes in message header. Although from server to client you don't need to apply masking over data. Read section 5. Data Framing in specification. Here is copy-paste from my own implementation. It is not ready-to-use code, and have to be modified, I am posting it just to give an idea and overall logic of read/write with WebSocket framing. Go to this link.

实现成帧后,请确保您使用套接字以正确的方式接收数据.例如为了防止某些消息合并为一个,因为 TCP 仍然是基于流的协议.这意味着您必须仅读取特定数量的字节.消息的长度始终基于标头,并在标头本身中提供数据长度详细信息.因此,当您从 Socket 接收数据时,首先接收 2 个字节,根据帧规范从标头中获取详细信息,然后如果掩码提供另外 4 个字节,然后根据数据长度可能为 1、4 或 8 个字节的长度.在数据之后它自己.阅读后,应用去掩码,您的消息数据就可以使用了.

After framing is implemented, make sure that you receive data right way using sockets. For example to prevent that some messages get merged into one, because TCP is still stream based protocol. That means you have to read ONLY specific amount of bytes. Length of message is always based on header and provided data length details in header it self. So when you receiving data from Socket, first receive 2 bytes, get details from header based on Framing specification, then if mask provided another 4 bytes, and then length that might be 1, 4 or 8 bytes based on length of data. And after data it self. After you read it, apply demasking and your message data is ready to use.

您可能想要使用一些数据协议,我建议使用 JSON,因为流量经济且易于在 JavaScript 客户端使用.对于服务器端,您可能需要检查一些解析器.有很多,谷歌真的很有帮助.

You might want to use some Data Protocol, I recommend to use JSON due traffic economy and easy to use on client side in JavaScript. For server side you might want to check some of parsers. There is lots of them, google can be really helpful.

实现自己的 WebSockets 协议肯定会带来一些好处和丰富的经验,并且可以自行控制协议.但是你必须花一些时间去做,并确保实现是高度可靠的.

Implementing own WebSockets protocol definitely have some benefits and great experience you get as well as control over protocol it self. But you have to spend some time doing it, and make sure that implementation is highly reliable.

与此同时,您可能会查看谷歌(再次)拥有足够的现成可用的解决方案.

In same time you might have a look in ready to use solutions that google (again) have enough.

这篇关于创建一个“Hello World"WebSocket 示例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆