2012-01-26 120 views
1

下面我已詳細分享了我的代碼。我閱讀文檔和關於握手的一切。我遵循了文檔中提供的所有步驟以及互聯網上的衆多示例,但仍然存在此問題。奇怪的事情id websocket.onclsose()在我關閉服務器時被觸發。從服務器發送響應握手後,websocket.onopen不會觸發


// 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> 

回答

2

我認爲你有一個錯誤在GetServerResponseKey()keyForHash應指定爲String.Concat(key, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11")

您附加到客戶端密鑰的值必須硬編碼,並且不能是動態生成的GUID。請參閱spec的第4.2.2節中的第5點。

另一點,你應該考慮檢查一個Sec-WebSocket協議頭的請求。如果這是由客戶端發送的,它會希望你在握手響應中回顯標題(當然假設你的服務器支持子協議當然)。這不會導致握手失敗,但稍後可能會導致客戶拒絕您的握手響應。

+0

so sorry simonc我有那些在握手結束時仍然存在問題。我在試驗時評論他們。我會更新來源。不管怎麼說,多謝拉。 –

+0

說明:客戶端握手中沒有任何Sec-WebSocket-Protocol頭。客戶握手是這樣的: GET /演示HTTP/1.1 升級:WebSocket的 連接:升級 主機:本地主機:8181 產地:HTTP://本地主機:64784 二段的WebSocket密鑰:Pa6n/e6GEVasIDbwIHvoMQ == 仲的WebSocket-版本:13 我的服務器響應是這樣的: HTTP/1.1 101交換協議 升級:WebSocket的 連接:升級 仲的WebSocket-接受:t5oQWBbjgYLIn7mF54q77iGCNq0 = –

+0

感謝您的澄清。我已經更新了我的答案,並提供了關於我發現的另一個問題的說明。希望這個會爲你覆蓋一些東西。 – simonc

相關問題