2012-01-26 3 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()에 버그가 있다고 생각. keyForHashString.Concat(key, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11")

에 할당되어야합니다. 클라이언트의 키에 추가하는 값은 하드 코딩되어야하며 동적으로 생성 된 GUID 일 수 없습니다. spec의 4.2.2 절 5 절을 참조하십시오.

또 다른 점은 Sec-WebSocket-Protocol 헤더 요청 확인을 고려해야합니다. 이것이 클라이언트에 의해 보내 진다면, 여러분은 핸드 셰이크 응답의 헤더를 반향시킬 것을 기대할 것입니다 (여러분의 서버가 물론 서브 프로토콜을 지원한다고 가정 할 때). 이렇게하면 핸드 셰이크가 멈추지 않지만 나중에 클라이언트가 핸드 셰이크 응답을 거부하게 할 수 있습니다.

+0

죄송합니다. simonc 나는 악수가 끝나고 그 문제가있었습니다. 거기에 문제가있었습니다. 나는 실험하면서 그들을 주석 처리했다. 나는 근원을 새롭게 할 것이다. 어쨌든 고마워. –

+0

설명 : 클라이언트 핸드 셰이크에 Sec-WebSocket-Protocol 헤더가 없습니다. GET/데모 HTTP/1.1 업그레이드 : 웹 소켓 연결 : 호스트를 업그레이드 : 로컬 호스트 : 8181 원산지 : HTTP : // localhost를 : 64,784 초 - 웹 소켓 - 키 : Pa6n/e6GEVasIDbwIHvoMQ의 == 을 클라이언트 핸드 셰이크는 다음과 같이 초 - 웹 소켓-버전 : 13 내 서버 응답은 다음과 같이 보았다 : HTTP/1.1 101 전환 프로토콜 업그레이드 : 웹 소켓 연결 : 업그레이드 초-WebSocket을 수락 다음 사항에 대한 t5oQWBbjgYLIn7mF54q77iGCNq0는 = –

+0

감사합니다. 나는 내가 봤던 또 다른 문제에 대한 노트로 나의 대답을 업데이트했다. 잘하면이 하나가 당신을 위해 물건을 다룰 것입니다. – simonc

관련 문제