2013-03-14 84 views
2

我想我需要一隻手在這裏。我的理解是,一旦我發送數據給我的客戶,onmessage()將被解僱。無法通過websocket將數據從服務器發送到客戶端

我已經在C#中創建了我的websocket服務器,並在HTML5中創建了我的客戶端。我可以成功建立websocket連接,但我無法將數據發送到我的客戶端。或者,也許,我已經發送,但沒有閱讀。那麼,它只是不會觸發我的onmessage()。請幫忙。

C#(.NET 4.0版本):

using System; 
using System.Collections.Generic; 
using System.Net.Sockets; 
using System.Net; 
using System.IO; 
using System.Security.Cryptography; 
using System.Threading; 




namespace WebSocketServer 
{ 
    public enum ServerLogLevel { Nothing, Subtle, Verbose }; 
    public delegate void ClientConnectedEventHandler(WebSocketConnection sender, EventArgs e); 

    public class WebSocketServer 
    { 
     #region private members 
     private string webSocketOrigin;  // location for the protocol handshake 
     private string webSocketLocation; // location for the protocol handshake 
     #endregion 
     static private string guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; 
     static IPEndPoint ipLocal; 

     public event ClientConnectedEventHandler ClientConnected; 

     /// <summary> 
     /// TextWriter used for logging 
     /// </summary> 
     public TextWriter Logger { get; set; }  // stream used for logging 

     /// <summary> 
     /// How much information do you want, the server to post to the stream 
     /// </summary> 
     public ServerLogLevel LogLevel = ServerLogLevel.Subtle; 

     /// <summary> 
     /// Gets the connections of the server 
     /// </summary> 
     public List<WebSocketConnection> Connections { get; private set; } 

     /// <summary> 
     /// Gets the listener socket. This socket is used to listen for new client connections 
     /// </summary> 
     public Socket ListenerSocker { get; private set; } 

     /// <summary> 
     /// Get the port of the server 
     /// </summary> 
     public int Port { get; private set; } 


     public WebSocketServer(int port, string origin, string location) 
     { 
      Port = port; 
      Connections = new List<WebSocketConnection>(); 
      webSocketOrigin = origin; 
      webSocketLocation = location; 
     } 

     /// <summary> 
     /// Starts the server - making it listen for connections 
     /// </summary> 
     public void Start() 
     { 
      // create the main server socket, bind it to the local ip address and start listening for clients 
      ListenerSocker = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP); 
      ipLocal = new IPEndPoint(IPAddress.Loopback, Port); 
      ListenerSocker.Bind(ipLocal); 
      ListenerSocker.Listen(100); 



      LogLine(DateTime.Now + "> server stated on " + ListenerSocker.LocalEndPoint, ServerLogLevel.Subtle); 

      ListenForClients(); 
     } 

     // look for connecting clients 
     private void ListenForClients() 
     { 
      ListenerSocker.BeginAccept(new AsyncCallback(OnClientConnect), null); 
     } 

     private void OnClientConnect(IAsyncResult asyn) 
     { 

      byte[] buffer = new byte[1024]; 
      string headerResponse = ""; 

      // create a new socket for the connection 
      var clientSocket = ListenerSocker.EndAccept(asyn); 
      var i = clientSocket.Receive(buffer); 
      headerResponse = (System.Text.Encoding.UTF8.GetString(buffer)).Substring(0, i); 
      //Console.WriteLine(headerResponse); 


      if (clientSocket != null) 
      { 

       // Console.WriteLine("HEADER RESPONSE:"+headerResponse); 
       var key = headerResponse.Replace("ey:", "`") 
           .Split('`')[1]      // dGhlIHNhbXBsZSBub25jZQ== \r\n ....... 
           .Replace("\r", "").Split('\n')[0] // dGhlIHNhbXBsZSBub25jZQ== 
           .Trim(); 
       var test1 = AcceptKey(ref key); 
       var newLine = "\r\n"; 
       var name = "Charmaine"; 
       var response = "HTTP/1.1 101 Switching Protocols" + newLine 
         + "Upgrade: websocket" + newLine 
         + "Connection: Upgrade" + newLine 
         + "Sec-WebSocket-Accept: " + test1 + newLine + newLine 
         + "Testing lang naman po:" + name 
         ; 

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





      // keep track of the new guy 
      var clientConnection = new WebSocketConnection(clientSocket); 
      Connections.Add(clientConnection); 
      // clientConnection.Disconnected += new WebSocketDisconnectedEventHandler(ClientDisconnected); 
      Console.WriteLine("New user: " + ipLocal); 
      // invoke the connection event 
      if (ClientConnected != null) 
       ClientConnected(clientConnection, EventArgs.Empty); 

      if (LogLevel != ServerLogLevel.Nothing) 
       clientConnection.DataReceived += new DataReceivedEventHandler(DataReceivedFromClient); 



      // listen for more clients 
      ListenForClients(); 

     } 

     void ClientDisconnected(WebSocketConnection sender, EventArgs e) 
     { 
      Connections.Remove(sender); 
      LogLine(DateTime.Now + "> " + sender.ConnectionSocket.LocalEndPoint + " disconnected", ServerLogLevel.Subtle); 
     } 

     void DataReceivedFromClient(WebSocketConnection sender, DataReceivedEventArgs e) 
     { 
      Log(DateTime.Now + "> data from " + sender.ConnectionSocket.LocalEndPoint, ServerLogLevel.Subtle); 
      Log(": " + e.Data + "\n" + e.Size + " bytes", ServerLogLevel.Verbose); 
      LogLine("", ServerLogLevel.Subtle); 
     } 


     /// <summary> 
     /// send a string to all the clients (you spammer!) 
     /// </summary> 
     /// <param name="data">the string to send</param> 
     public void SendToAll(string data) 
     { 
      Connections.ForEach(a => a.Send(data)); 
     } 

     /// <summary> 
     /// send a string to all the clients except one 
     /// </summary> 
     /// <param name="data">the string to send</param> 
     /// <param name="indifferent">the client that doesn't care</param> 
     public void SendToAllExceptOne(string data, WebSocketConnection indifferent) 
     { 
      foreach (var client in Connections) 
      { 
       if (client != indifferent) 
        client.Send(data); 
      } 
     } 

     /// <summary> 
     /// Takes care of the initial handshaking between the the client and the server 
     /// </summary> 


     private void Log(string str, ServerLogLevel level) 
     { 
      if (Logger != null && (int)LogLevel >= (int)level) 
      { 
       Logger.Write(str); 
      } 
     } 

     private void LogLine(string str, ServerLogLevel level) 
     { 
      Log(str + "\r\n", level); 
     } 

     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)); 
     } 



     private void ShakeHands(Socket conn) 
     { 
      using (var stream = new NetworkStream(conn)) 
      using (var reader = new StreamReader(stream)) 
      using (var writer = new StreamWriter(stream)) 
      { 
       //read handshake from client (no need to actually read it, we know its there): 
       LogLine("Reading client handshake:", ServerLogLevel.Verbose); 
       string r = null; 
       while (r != "") 
       { 
        r = reader.ReadLine(); 
        LogLine(r, ServerLogLevel.Verbose); 
       } 

       // send handshake to the client 
       writer.WriteLine("HTTP/1.1 101 Web Socket Protocol Handshake"); 
       writer.WriteLine("Upgrade: WebSocket"); 
       writer.WriteLine("Connection: Upgrade"); 
       writer.WriteLine("WebSocket-Origin: " + webSocketOrigin); 
       writer.WriteLine("WebSocket-Location: " + webSocketLocation); 
       writer.WriteLine(""); 
      } 


      // tell the nerds whats going on 
      LogLine("Sending handshake:", ServerLogLevel.Verbose); 
      LogLine("HTTP/1.1 101 Web Socket Protocol Handshake", ServerLogLevel.Verbose); 
      LogLine("Upgrade: WebSocket", ServerLogLevel.Verbose); 
      LogLine("Connection: Upgrade", ServerLogLevel.Verbose); 
      LogLine("WebSocket-Origin: " + webSocketOrigin, ServerLogLevel.Verbose); 
      LogLine("WebSocket-Location: " + webSocketLocation, ServerLogLevel.Verbose); 
      LogLine("", ServerLogLevel.Verbose); 

      LogLine("Started listening to client", ServerLogLevel.Verbose); 
      //conn.Listen(); 
     } 


    } 
} 

HTML5:

<!HTML> 
    <head> 

     <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"> 
     </script> 

     <script language="javascript" type="text/javascript"> 

     jQuery(document).ready(function(){ 
      var socket = new WebSocket("ws://127.0.0.1:8080"); 
      socket.onopen = function(evt){ 
       alert("Socket has been opened!"); 

      } 
      socket.onmessage = function(evt) {  
       alert("On message fired up!"); 
      }; 
     }); 
     </script> 
    </head> 
</HTML> 

這是我在我的響應頭有:

Request-Response Headers

這是我的發送方法:

public void Send(string str) 
     { 
      if (ConnectionSocket.Connected) 
      { 
       try 
       { 

        // start with a 0x00 
        ConnectionSocket.Send(new byte[] { (byte)WrapperBytes.Start }, 1, 0); 
        // send the string 
        ConnectionSocket.Send(Encoding.UTF8.GetBytes(str)); 
        /* 
        writer.Write(str); 
        writer.Flush();*/ 

        // end with a 0xFF 
        ConnectionSocket.Send(new byte[] { (byte)WrapperBytes.End }, 1, 0); 
       } 
       catch 
       { 
        if (Disconnected != null) 

         Disconnected(this, EventArgs.Empty); 
       } 
      } 
     } 
+0

Websocket消息不作爲純文本發送。每條消息都必須如RFC6455的[數據組幀部分](http://tools.ietf.org/html/rfc6455#section-5.2)中所述進行組幀。你的'WebSocketConnection'類'Send'方法是否應用這個框架? – simonc 2013-03-14 09:04:42

+0

嗨..我更新了我的問題。我提供了我的發送方法的代碼 – Charmie 2013-03-14 09:26:54

+0

謝謝,看起來像我的第一個評論是在正確的線。我已經發布了一個更詳細的答案。 – simonc 2013-03-14 09:40:12

回答

3

websocket協議經歷了早期草稿之間的一些不兼容的變化。看起來你的代碼在支持最新版本和早期版本之間分開。握手似乎基於RFC6455(或其早期的Hybi草案);消息發送似乎基於較早的,不兼容的Hixie-76變體。

可以在您的服務器中支持多種協議變體。幾乎所有的瀏覽器(用於Windows的Safari都是可能的異常)現在支持更新的變體,儘管如此,我認爲這是您希望優先考慮的一個。

要支持最新的協議變體,您需要更改WebSocketConnection.Send以實現RFC6455的data framing section中所述的成幀。

用於接收WebSocketConnection消息的代碼可能需要類似的更改。

相關問題