2011-11-24 13 views
9

Sto cercando di creare un semplice server WebSockets con il seguente:semplici C# WebSockets Server

namespace ConsoleWebSocketServer 
{ 
    class Program 
    { 
     const string c_MagicKey = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; 

     static void Main(string[] args) 
     { 
      TcpListener l_Listener = new TcpListener(IPAddress.Loopback, 8181); 
      l_Listener.Start(); 
      while (true) 
      { 
       using (TcpClient l_Client = l_Listener.AcceptTcpClient()) 
       using (NetworkStream l_Stream = l_Client.GetStream()) 
       { 
        var l_headers = new Dictionary<string, string>(); 
        string l_line = string.Empty; 
        while ((l_line = ReadLine(l_Stream)) != string.Empty) 
        { 
         var tokens = l_line.Split(new char[] { ':' }, 2); 
         if (!string.IsNullOrWhiteSpace(l_line) && tokens.Length > 1) 
         { 
          l_headers[tokens[0]] = tokens[1].Trim(); 
         } 
        } 

        string l_secKey = l_headers["Sec-WebSocket-Key"]; 
        string l_responseSecKey = ComputeWebSocketHandshakeSecurityHash09(l_secKey); 

        string l_response = 
         "HTTP/1.1 101 Switching Protocols" + Environment.NewLine + 
         "Upgrade: websocket" + Environment.NewLine + 
         "Connection: Upgrade" + Environment.NewLine + 
         "Sec-WebSocket-Accept: " + l_responseSecKey + Environment.NewLine + Environment.NewLine; 

        var l_bufferedResponse = Encoding.UTF8.GetBytes(l_response); 
        l_Stream.Write(l_bufferedResponse, 0, l_bufferedResponse.Length); 
       } 
      } 
     } 

     public static string ComputeWebSocketHandshakeSecurityHash09(string secWebSocketKey) 
     { 
      string secWebSocketAccept = null; ; 
      string l_combinedKey = secWebSocketKey + c_MagicKey; 

      SHA1 l_Sha1Crypto = new SHA1CryptoServiceProvider(); 
      byte[] l_sha1Hash = l_Sha1Crypto.ComputeHash(Encoding.UTF8.GetBytes(l_combinedKey)); 
      secWebSocketAccept = Convert.ToBase64String(l_sha1Hash); 

      return secWebSocketAccept ?? String.Empty; 
     } 

     static string ReadLine(Stream stream) 
     { 
      var l_Sb = new StringBuilder(); 
      var l_buffer = new List<byte>(); 
      while (true) 
      { 
       l_buffer.Add((byte)stream.ReadByte()); 
       string l_line = Encoding.ASCII.GetString(l_buffer.ToArray()); 
       if (l_line.EndsWith(Environment.NewLine)) 
       { 
        return l_line.Substring(0, l_line.Length - 2); 
       } 
      } 
     } 
    } 
} 

E sto testando con una semplice pagina che effettua le seguenti operazioni:

function testWebSocket() { 
    if (!window.WebSocket) { 
     alert('WebSockets are NOT supported by your browser.'); 
     return; 
    } 

    var ws = new WebSocket('ws://localhost:8181/demo'); 
    ws.onopen = function() { 
     alert('Handshake successfully established. Ready for data...'); 
    }; 

    ws.onmessage = function (e) { 
     alert('Got WebSockets message: ' + e.data); 
    } 

    ws.onclose = function() { 
     alert('Connection closed.'); 
    }; 
} 

Sto vedendo solo l'avviso "Handshake" seguito immediatamente dal messaggio "Closed". Mi sto perdendo qualcosa?

+0

FYI: WebSockets saranno inclusi nel .NET 4.5 – dtb

+0

Io non ti vedo scrivere nulla diverso dall'intestazione del socket. – albertjan

+0

@the_ajp: se I l_Stream.Write (Encoding.UTF8.GetBytes ("Test"), 0, 5) dopo l'invio dell'handshake, non lo vedo sul client. – Bullines

risposta

8

Ok, c'è un po 'più di protocollo che devi fare prima di poter inviare "Test" al client. Ecco qui. Ho usato un elenco di byte perché è facile :)

List<byte> lb= new List<byte>(); 
// see http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17 
//  page 30 for this: 
// 0     1     2     3 
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 
// +-+-+-+-+-------+-+-------------+-------------------------------+ 
// |F|R|R|R| opcode|M| Payload len | Extended payload length | 
// |I|S|S|S| (4) |A|  (7)  |    (16/64)   | 
// |N|V|V|V|  |S|    | (if payload len==126/127) | 
// | |1|2|3|  |K|    |        | 
// +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + 
// |  Extended payload length continued, if payload len == 127 | 
// + - - - - - - - - - - - - - - - +-------------------------------+ 
// |        |Masking-key, if MASK set to 1 | 
// +-------------------------------+-------------------------------+ 
// | Masking-key (continued)  |   Payload Data   | 
// +-------------------------------- - - - - - - - - - - - - - - - + 
// :      Payload Data continued ...    : 
// + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + 
// |      Payload Data continued ...    | 
// +---------------------------------------------------------------+ 
// 
//0x81 = 10000001 which says according to the table above: 
//  1  it's the final message 
//  000  RSV1-3 are extensions which must be negotiated first 
//   0001 opcode %x1 denotes a text frame 
lb.Add(0x81); 
//0x04 = 00001000 
//  0  No mask 
//  0001000 Rest of the 7 bytes left is the length of the payload. 
lb.Add(0x04); 
// add the payload 
lb.AddRange(Encoding.UTF8.GetBytes("Test")); 
//write it! 
l_Stream.Write (lb.ToArray(), 0, 6); 

whoohoo qui !: risultato

Screenshost of alerts

+2

+1 funziona come pubblicizzato. – James

+1

+1 anche da me, esattamente quello di cui avevo bisogno. –