C# WebSocket-在服务器消息上断开连接

C# WebSocket-在服务器消息上断开连接,c#,websocket,handshake,C#,Websocket,Handshake,我是WebSocket新手,正在寻找使用WS和c#控制台应用程序的工作示例。 我遇到了,但我已经有问题了。当服务器向客户端发送消息时,连接似乎关闭了。我不确定,但我认为握手可以。下面是一个代码: 服务器: using System; using System.Net.Sockets; using System.Net; using System.Security.Cryptography; using System.Threading; namespace ConsoleApplication

我是WebSocket新手,正在寻找使用WS和c#控制台应用程序的工作示例。 我遇到了,但我已经有问题了。当服务器向客户端发送消息时,连接似乎关闭了。我不确定,但我认为握手可以。下面是一个代码:

服务器:

using System;
using System.Net.Sockets;
using System.Net;
using System.Security.Cryptography;
using System.Threading;

namespace ConsoleApplication1
{
    class Program
    {
        static Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
        static private string guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

        static void Main(string[] args)
        {
            serverSocket.Bind(new IPEndPoint(IPAddress.Any, 8080));
            serverSocket.Listen(128);
            serverSocket.BeginAccept(null, 0, OnAccept, null);
            Console.Read();
        }

        private static void OnAccept(IAsyncResult result)
        {
            byte[] buffer = new byte[1024];
            try
            {
                Socket client = null;
                string headerResponse = "";
                if (serverSocket != null && serverSocket.IsBound)
                {
                    client = serverSocket.EndAccept(result);
                    var i = client.Receive(buffer);
                    headerResponse = (System.Text.Encoding.UTF8.GetString(buffer)).Substring(0, i);
                    // write received data to the console
                    Console.WriteLine(headerResponse);
                    Console.WriteLine("=====================");
                }
                if (client != null)
                {
                    /* Handshaking and managing ClientSocket */

                    var key = headerResponse.Replace("ey:", "`")
                              .Split('`')[1]                     // dGhlIHNhbXBsZSBub25jZQ== \r\n .......
                              .Replace("\r", "").Split('\n')[0]  // dGhlIHNhbXBsZSBub25jZQ==
                              .Trim();

                    // key should now equal dGhlIHNhbXBsZSBub25jZQ==
                    var test1 = AcceptKey(ref key);

                    var newLine = "\r\n";

                    var response = "HTTP/1.1 101 Switching Protocols" + newLine
                         + "Upgrade: websocket" + newLine
                         + "Connection: Upgrade" + newLine
                         + "Sec-WebSocket-Accept: " + test1 + newLine + newLine
                         //+ "Sec-WebSocket-Protocol: chat, superchat" + newLine
                         //+ "Sec-WebSocket-Version: 13" + newLine
                         ;

                    // which one should I use? none of them fires the onopen method
                    client.Send(System.Text.Encoding.UTF8.GetBytes(response));

                    var i = client.Receive(buffer); // wait for client to send a message

                    // once the message is received decode it in different formats
                    Console.WriteLine(Convert.ToBase64String(buffer).Substring(0, i));
                    Console.WriteLine("=====================");

                    Console.WriteLine("\n\nPress enter to send data to client");
                    Console.Read();

                    var subA = SubArray<byte>(buffer, 0, i);
                    client.Send(subA);

                    Console.Read();                    
                    Thread.Sleep(10000);//wait for message to be send


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

        public static T[] SubArray<T>(T[] data, int index, int length)
        {
            T[] result = new T[length];
            Array.Copy(data, index, result, 0, length);
            return result;
        }

        private static string AcceptKey(ref string key)
        {
            string longKey = key + guid;
            byte[] hashBytes = ComputeHash(longKey);
            return Convert.ToBase64String(hashBytes);
        }

        static SHA1 sha1 = SHA1CryptoServiceProvider.Create();
        private static byte[] ComputeHash(string str)
        {
            return sha1.ComputeHash(System.Text.Encoding.ASCII.GetBytes(str));
        }
    }
}
使用系统;
使用System.Net.Sockets;
Net系统;
使用System.Security.Cryptography;
使用系统线程;
命名空间控制台应用程序1
{
班级计划
{
静态套接字服务器套接字=新套接字(AddressFamily.InterNetwork、SocketType.Stream、ProtocolType.IP);
静态专用字符串guid=“258EAFA5-E914-47DA-95CA-C5AB0DC85B11”;
静态void Main(字符串[]参数)
{
Bind(新的IPEndPoint(IPAddress.Any,8080));
serverSocket.Listen(128);
serverSocket.BeginAccept(null,0,OnAccept,null);
Console.Read();
}
接受时私有静态无效(IAsyncResult结果)
{
字节[]缓冲区=新字节[1024];
尝试
{
socketclient=null;
字符串headerResponse=“”;
if(serverSocket!=null&&serverSocket.IsBound)
{
client=serverSocket.EndAccept(结果);
var i=client.Receive(缓冲区);
headerResponse=(System.Text.Encoding.UTF8.GetString(buffer)).Substring(0,i);
//将接收到的数据写入控制台
控制台写入线(headerResponse);
Console.WriteLine(“===============================”);
}
如果(客户端!=null)
{
/*握手和管理ClientSocket*/
var key=headerResponse.Replace(“ey:”,“`”)
.Split('`')[1]//DGHLIHNHBXBSSBUB25JZQ==\r\n。。。。。。。
.Replace(“\r”和“).Split(“\n”)[0]//dGhlIHNhbXBsZSBub25jZQ==
.Trim();
//键现在应该等于DGHLIHNHBXBSZSUB25JZQ==
var test1=接受键(ref键);
var newLine=“\r\n”;
var response=“HTTP/1.1 101交换协议”+换行符
+“升级:websocket”+换行符
+“连接:升级”+换行
+“Sec WebSocket接受:”+test1+换行符+换行符
//+“Sec WebSocket协议:聊天,超级聊天”+换行符
//+“Sec WebSocket版本:13”+换行符
;
//我应该使用哪一个?它们都不会触发onopen方法
Send(System.Text.Encoding.UTF8.GetBytes(response));
var i=client.Receive(buffer);//等待客户端发送消息
//收到信息后,以不同格式对其进行解码
Console.WriteLine(Convert.ToBase64String(buffer.Substring)(0,i));
Console.WriteLine(“===============================”);
Console.WriteLine(“\n\n按enter键向客户端发送数据”);
Console.Read();
var subA=子阵列(缓冲区,0,i);
client.Send(subA);
Console.Read();
Thread.Sleep(10000);//等待消息发送
}
}
捕获(SocketException异常)
{
抛出异常;
}
最后
{
if(serverSocket!=null&&serverSocket.IsBound)
{
serverSocket.BeginAccept(null,0,OnAccept,null);
}
}
}
公共静态T[]子数组(T[]数据,整数索引,整数长度)
{
T[]结果=新的T[长度];
复制(数据、索引、结果、0、长度);
返回结果;
}
私有静态字符串接受键(参考字符串键)
{
字符串longKey=key+guid;
字节[]哈希字节=计算哈希(长键);
返回Convert.ToBase64String(hashBytes);
}
静态SHA1 SHA1=SHA1CryptoServiceProvider.Create();
私有静态字节[]计算哈希(字符串str)
{
返回sha1.ComputeHash(System.Text.Encoding.ASCII.GetBytes(str));
}
}
}
克莱恩特:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <script type="text/javascript">
        function connect() {
            var ws = new WebSocket("ws://localhost:8080/service");
            ws.onopen = function () {
                alert("About to send data");
                ws.send("Hello World"); // I WANT TO SEND THIS MESSAGE TO THE SERVER!!!!!!!!
                alert("Message sent!");
            };

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


    </script>
</head>
<body style="font-size:xx-large" >
    <div>
    <a href="#" onclick="connect()">Click here to start</a></div>
</body>
</html>

函数连接(){
var ws=newwebsocket(“ws://localhost:8080/service”);
ws.onopen=函数(){
警报(“即将发送数据”);
ws.send(“Hello World”);//我想将此消息发送到服务器!!!!!!!!
警报(“消息已发送!”);
};
ws.onmessage=函数(evt){
警报(“即将接收数据”);
收到的var_msg=evt.data;
警报(“消息已接收=“+received_msg”);
};
ws.onclose=函数(){
//websocket已关闭。
警报(“连接已关闭…”);
};
};
以下是来自客户端的连接请求和消息:

任何帮助都将不胜感激。

您不能只是“回显”收到的缓冲区。RFC说,从客户端到服务器的帧必须被屏蔽。它并没有说从服务器到客户端的消息不能发送,但至少对于Chrome来说不应该发送。 因此,如果要回显数据,必须解码(取消屏蔽)帧并构造一个新帧。有效负载需要使用掩码键逐字节异或

或者简单地发送如下数据:

byte[] send = new byte[3 + 2];
send[0] = 0x81; // last frame, text
send[1] = 3; // not masked, length 3
send[2] = 0x41;
send[3] = 0x42;
send[4] = 0x43;
nwStream.Write(send, 0, send.Length); // nwStream = client.GetStream(), client is a TcpClient

杰弗森是对的。但应注意的是,RFC 6455第5.1节确实提到

。。。服务器不得屏蔽发送给客户端的任何帧。客户