2011-11-07 37 views
2

所以我決定通過給自己一些有趣的任務開始學習它。作爲一個Web開發者,我想擁有自己的WebSocket服務器。 所以我寫了它,但它只接受第一個請求。之後有算術運算。
下面是一些代碼,讓你看看我做錯了什麼:S我真的沒有想法。在C中讀取套接字時算術運算溢出了#

using System; 
using System.Collections.Generic; 
using System.Text; 
using System.Net; 
using System.Net.Sockets; 
using System.Threading; 
using System.Text.RegularExpressions; 
using System.Security.Cryptography; 

using WebSocket.Utils; 

namespace WebSocket 
{ 
    class SocketReader 
    { 
     public EndPoint ipAddr { get; set; } 
     private Socket userSocket; 
     private byte[] buffer; 
     private string SOCKET_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; 

     public SocketReader(Socket socket) 
     { 
      userSocket = socket; 
      ipAddr = socket.RemoteEndPoint; 
      Read(); 
     } 

     private void Read() 
     { 
      //Read packet size 
      buffer = new byte[2]; 
      userSocket.BeginReceive(buffer, 0, 2, SocketFlags.None, ReadCallbackStatic, null); 
     } 

     private void ReadCallbackStatic(IAsyncResult ar) 
     { 
      try 
      { 
       if (userSocket.EndReceive(ar) >= 1) 
       { 
        int bufferSize = BitConverter.ToInt16(buffer, 0); 
        buffer = new byte[bufferSize - 2]; 
        //Read Packet 
        userSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReadCallback, null); 
       } 
      } 
      catch (Exception se) 
      { 
       Console.WriteLine("Something blew on ReadCallbackStatic"); 
       Console.WriteLine(se.Message); 
       Console.WriteLine(se.StackTrace); 
       Disconnect(); 
      } 
     } 

     private void ReadCallback(IAsyncResult ar) 
     { 
      try 
      { 
       //Copy the buffer so we can receive the next packet ASAP 
       byte[] buff = new byte[buffer.Length]; 
       Array.Copy(buffer, buff, buffer.Length); 
       Read(); 

       string handshakeStr = System.Text.Encoding.UTF8.GetString(buff); 
       string[] list = Regex.Split(handshakeStr, "\r\n"); 

       //Sec-WebSocket-Key: S5o6fCVLRMJhdXTF3H9w3Q== 
       //Sec-WebSocket-Version: 8 

       string key = ""; 
       string clientProtocol = "0"; 

       foreach (string str in list) 
       { 
        if (String.IsNullOrEmpty(str)) { continue; } 
        if (str.Length > 20 && str.Substring(0, 19) == "Sec-WebSocket-Key: ") 
        { 
         key = str.Substring(19); 
         continue; 
        } 

        if (str.Length > 20 && str.Substring(0, 23) == "Sec-WebSocket-Version: ") 
        { 
         clientProtocol = str.Substring(23); 
         continue; 
        } 
       } 

       if (String.IsNullOrEmpty(key)) 
       { 
        Disconnect(); 
       } 

       SHA1 shaEnc = new SHA1CryptoServiceProvider(); 

       byte[] byteString = ASCIIEncoding.ASCII.GetBytes(key + SOCKET_GUID); 
       byte[] hash = shaEnc.ComputeHash(byteString, 0, byteString.Length); 
       string acceptKey = Convert.ToBase64String(hash); 

       List<string> headers = new List<string>(); 
       headers.Add("HTTP/1.1 101 Switching Protocols"); 
       headers.Add("Upgrade: websocket"); 
       headers.Add("Connection: Upgrade"); 
       headers.Add("Sec-WebSocket-Accept: " + acceptKey); 

       foreach (string header in headers) 
       { 
        SendString(header + "\r\n"); 
       } 

       Console.WriteLine(acceptKey); 

       SendString("\r\n"); 

      } 
      catch (SocketException se) 
      { 
       Console.WriteLine("Something blew on ReadCallback"); 
       Console.WriteLine(se.Message); 
       Disconnect(); 
      } 
     } 

     private void SendString(string str) 
     { 
      userSocket.Send(Encoding.UTF8.GetBytes(str)); 
     } 

     private void Disconnect() 
     { 
      userSocket.Disconnect(false); 
      Console.WriteLine("Client with ip {0} Disconnected", ipAddr); 
     } 
    } 
} 

它縮短了我的課的版本,但被竊聽我的問題出現在「ReadCallbackStatic」在這條線:

buffer = new byte[bufferSize - 2]; 

我真的不知道我做錯了什麼:S。
的事情是,...其實我握手正常但後來當我發送來自客戶端的一些信息到我的服務器則拋出該異常

我做了一些調試,看來,在某種程度上緩衝變量變爲負數OO

+1

你確定你應該減2? – harold

+0

爲了迴應哈羅德的觀點 - 長度標記通常不包括長度標記的大小;意思是:如果標記(長度2)報告200字節,我期望讀取*附加* 2字節,因此總共202個字節。 –

回答

0

我相信問題可能是在情況下,當緩衝區包含零個的數字,所以:

int bufferSize = BitConverter.ToInt16(buffer, 0); // 0 
    buffer = new byte[bufferSize - 2]; // 0 - 2 == -2 

這會導致溢出異常,而執行new byte[-2]

我不知道你的代碼背後的邏輯,但我相信你應該分配一個新的緩衝區考慮buffer.Length

+0

沒有減法也是一樣的,是的,數據包長度是2個字節。有趣的是,緩衝區大小更像是「-3550」不只是0:/ 這裏是控制檯輸出 「17735 0pV0tDprwlXs6BqAshUb + 0MPobg = -30079」 第一個數字是握手字符串。第二個是別的:( 曼波jambo字符串是用於與客戶端握手的接受鍵(在本例中爲谷歌瀏覽器) – Sk1ppeR

+0

@ Sk1ppeR查看我的答案; -3550將映射到61​​986,如果它是MSB問題,並且-30079會映射到35457 –

+1

@ Sk1ppeR:任何以這種方式分配緩衝區都很危險的方式,你可能會在某天得到另一個緩衝區溢出異常,所以在執行'bufferSize-2'之前,檢查'bufferSize <= 2'或參考入站緩衝區。長度值 – sll

2

我的猜測是,當最高位,你吹起來,即可能的客戶端發送一個數字> = 32768和< 65536,它(通過您的ToInt16)正在成爲一個大的負16位數字(或者,或者,拋出算術溢出問題)。我會嘗試使用ToUInt16來代替。

說實話,你真的不需要BitConverter這裏;根據字節順序有兩種情況:

int bufferSize = (buffer[0] << 8) | buffer[1]; 

int bufferSize = buffer[0] | (buffer[1] << 8); 
+0

它與UInt轉換現在它不會拋出異常,但它會給相當巨大的緩衝區大小,所以當我登錄到控制檯時,我實際上看不到它,因爲有太多空白的新行。 我想我必須將它記錄在文件上以查看正在發生的事情或只是斷點調試它 – Sk1ppeR

+0

@ Sk1ppeR只有您的線規可以告訴您什麼是正確的解釋。請注意,65k並不是特別大,在很多情況下,你的緩衝區可能比數據小很多(這個想法是:你以大塊的形式讀取它)。 –