在我从服务器发送响应握手后,websocket.onopen没有触发

时间:2012-01-26 17:30:14

标签: websocket

下面我详细分享了我的代码。我阅读文档和握手的一切。我按照文档中提供的所有步骤和互联网上的大量示例,但仍然有这个问题。奇怪的事情id websocket.onclsose()在关闭服务器时被触发。


// Simple Websocket server
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.IO;
using System.Security.Cryptography;

using System.Threading;

namespace WebSocketServer
{
class Program
{
    //port 
    private static int _port = 8181;

    static void Main(string[] args)
    {
        TcpListener t = new TcpListener(IPAddress.Loopback, _port);
        t.Start();

        Console.WriteLine("Server is started and waiting for client\n\n");

        byte[] buff = new byte[255];
        NetworkStream stream;
        TcpClient client;
        while(true)
        {
            client = t.AcceptTcpClient();
            if (!client.Connected)
               return;

            // I need form a proper mechanism to get all the data out of network stream.
            // If I wait too long client get disconnected and we dont get stream and if
            // if we dont wait at all then data doesnt reach server port and hence cant
            // read the handshake.

            stream = client.GetStream();
            while ((stream.Read(buff, 0, buff.Length)) != 0)
            {
                break;
            }

            if (0 != buff.Length)
                break;
        }

        StreamWriter writer = new StreamWriter(stream);                  
        writer.AutoFlush = true;


        //while (stream.DataAvailable)
            //stream.Read(buff, 0, buff.Length);

        Console.WriteLine(System.Text.ASCIIEncoding.ASCII.GetString(buff));
        string clientHandshake = System.Text.ASCIIEncoding.ASCII.GetString(buff);

        char[] separators = new char[1];
        separators[0] = '\n';
        string[] temp = clientHandshake.Split(separators, 100);
        string keyword = "Sec-WebSocket-Key";
        string key = "";
        foreach (string s in temp)
        {
            if (s.Contains(keyword))
            {
                string keyTemp= s.Substring(keyword.Length + 2);
                key = keyTemp.Remove(keyTemp.Length - 1);


                break;
            }
        }

        string responseKey = GetServerResponseKey(key);

        // Send Server handshake
        string handshake =
            "HTTP/1.1 101 Switching Protocols\r\n" +
            "Upgrade: websocket\r\n" +
            "Connection: Upgrade\r\n" +
            "Sec-WebSocket-Accept: " + responseKey + "\r\n";

        writer.Write(handshake);
        writer.Flush();

        Console.WriteLine(handshake);

        while ((stream.Read(buff, 0, buff.Length)) != 0)
        {
            break;
        }

        Console.WriteLine(System.Text.ASCIIEncoding.ASCII.GetString(buff));


        // Keep Server alive
        while (true)
        { }
    }

    //Helper method to convert string into Byte[]
    private static byte[] GetByteArray(string str)
    {
        UTF8Encoding encoding = new UTF8Encoding();
        return encoding.GetBytes(str);
    }

    //This method is requuired because it combines key(got it from client)
    //with GUID. Then takes SHA1 hash of that string and then encode to base64.
    //This is all required because Handshake mechanism can be done by only this 
    //way according to Websocket Protocol(http://datatracker.ietf.org/doc/rfc6455/) 
    private static string GetServerResponseKey(string key)
    {
        Console.WriteLine("original key = " + key);

        string keyForHash = String.Concat(key, Guid.NewGuid());
        Console.WriteLine("text version of server response key = " + keyForHash);

        UTF8Encoding encoding = new UTF8Encoding();
        byte[] temp = encoding.GetBytes(keyForHash);

        SHA1 hashProvider = new SHA1CryptoServiceProvider();
        byte[] keyForBase64 = hashProvider.ComputeHash(temp);

        return Convert.ToBase64String(keyForBase64);

    }
}
}

// Simple WebSocket Client

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebSocketClient._Default" %>

<!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 runat="server">
<title></title>

<script language="javascript" type = "text/javascript">
    var ws;
    function btnConnectSend_onclick() {
        if ("WebSocket" in window) {
            ws = new WebSocket("ws://localhost:8181");
            ws.onopen = function() {
                alert("Connection Open");
                ws.send("Hello Server");
            };
            ws.onmessage = function(evt) {
                form1.txtMessage.value = evt.data;
                alert("Server says:" + evt.data);
            };
            ws.onclose = function() {
                alert("Socket Closed!!!");
            };

            ws.onerror = function() {
                alert("WTF!");
            };
        }
    }

    function btnClose_onclick() {
        ws.close();
    };
</script>
</head>

<body>
<form id="form1" runat="server">
<div style="height: 350px">
    <input id="btnConnectSend" type="button" value="Connect/Send" onclick ="return btnConnectSend_onclick ()"/>
    <br />
    <input id="txtMessage" type="text"/>
    <br />
    <input id="btnClose" type="button" value="Close" onclick="return btnClose_onclick()"/>
</div>
</form>
</body>
</html>

1 个答案:

答案 0 :(得分:2)

我认为你在GetServerResponseKey()中有一个错误。应将keyForHash分配给String.Concat(key, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11")

附加到客户端密钥的值必须是硬编码的,不能是动态生成的guid。见spec的第4.2.2节第5页。

另一点,您应该考虑检查Sec-WebSocket-Protocol标头的请求。如果这是由客户端发送的,它会期望您在握手响应中回显标头(当然假设您的服务器支持子协议)。这不会导致握手停止,但可能会导致客户端拒绝您的握手响应。