2

我正在尝试使用 VB.NET 创建最简单的 WebSocket 服务器。我设法实现握手,但握手后无法发送消息。以下是我的代码:

Dim serverTcp As TcpListener
Dim serverThread As Thread

Sub Main()
    '' Start server
    serverThread = New Thread(AddressOf serverProc)
    serverThread.Start()
End Sub

Private Sub serverProc()
    '' Listen to port 8181
    serverTcp = New TcpListener(8181)
    serverTcp.Start()

    Console.WriteLine("Listen to port 8181 ...")

    '' Accept any connection
    While (True)
        Dim curSocket As Socket = serverTcp.AcceptSocket()
        Dim thread As New Thread(AddressOf clientProc)
        thread.Start(curSocket)
    End While
End Sub

Private Sub clientProc(ByVal sck As Socket)
    Dim netStream As New NetworkStream(sck)
    Dim netReader As New IO.StreamReader(netStream)
    Dim netWriter As New IO.StreamWriter(netStream)

    Dim key As String = ""

    Console.WriteLine("Accept new connection ...")

    '' Reading handshake message
    While (True)
        Dim line As String = netReader.ReadLine()
        If line.Length = 0 Then
            Exit While
        End If

        If (line.StartsWith("Sec-WebSocket-Key: ")) Then
            key = line.Split(":")(1).Trim()
        End If

        Console.WriteLine("Data: " & line)
    End While

    '' Calculate accept-key
    key += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
    key = getSHA1Hash(key)

    '' Response handshake message
    Dim response As String
    response = "HTTP/1.1 101 Switching Protocols" & vbCrLf
    response &= "Upgrade: websocket" & vbCrLf
    response &= "Connection: Upgrade" & vbCrLf
    response &= "Sec-WebSocket-Accept: " & key & vbCrLf & vbCrLf
    netWriter.Write(response)
    netWriter.Flush()

    '' Sending Hello World message
    Dim message As String = "Hello World"
    Dim messageByte() As Byte = System.Text.Encoding.UTF8.GetBytes(message)
    Dim startByte() As Byte = {&H0}
    Dim endByte() As Byte = {&HFF}

    sck.Send(startByte, 1, 0)
    sck.Send(messageByte)
    sck.Send(endByte, 1, 0)
End Sub

Function getSHA1Hash(ByVal strToHash As String) As String
    Dim sha1Obj As New Security.Cryptography.SHA1CryptoServiceProvider
    Dim bytesToHash() As Byte = System.Text.Encoding.ASCII.GetBytes(strToHash)
    Dim result As String

    bytesToHash = sha1Obj.ComputeHash(bytesToHash)
    result = Convert.ToBase64String(bytesToHash)

    Return result
End Function

标准说我需要发送0x00字节,然后是 UTF8 的字节,并以0xFF字节结束。我已经按照它说的做了,但我的 HTML 客户端无法接收到该消息。

以下是我的 HTML5 代码:

<script>
if('WebSocket' in window){
  connect('ws://localhost:8181/service');
}

function connect(host) {
  var ws = new WebSocket(host);
  ws.onopen = function () {
    alert('connected');
  };

  ws.onmessage = function (evt) {  
    alert('reveived data:'+evt.data);
  };

  ws.onclose = function () {
    alert('socket closed');
  };
};
</script>
4

1 回答 1

3

标准说我需要发送 0x00 字节,然后是 UTF8 字节,并以 0xFF 字节结束

真的吗?̶你从哪里弄来的?̶我不认为有这样的事情在说明书。

Simonic statet in his comment that starting with 0x00 and ending with 0xFF was used in the deprecated Hixie-76 variant of the protocol.

Have a look at the actual specification (RFC 6455).


For better understanding, have a look at this great answer:

The frames you're sending need to be formatted according to the WebSocket framing format. For sending messages, this format is as follows:

  • one byte which contains the type of data (and some additional info which is out of scope for a trivial server)
  • one byte which contains the length
  • either two or eight bytes if the length does not fit in the second byte (the second byte is then a code saying how many bytes are used for the length)
  • the actual (raw) data

I translated this java implementation for you (in a quick'n'dirty way, there may be some errors) to VB.Net, and it's working:

Sub SendMessage(sck As Socket, message as String)
    Dim  rawData =  System.Text.Encoding.UTF8.GetBytes(message)

    Dim frameCount = 0
    Dim frame(10) As byte

    frame(0) = cbyte(129)

    if rawData.length <= 125 Then
        frame(1) = CByte( rawData.length)
        frameCount = 2
    else if rawData.length >= 126 AndAlso rawData.length <= 65535
        frame(1) = CByte( 126)
        Dim len = cbyte(rawData.length)
        frame(2) = CByte(((len >> 8 ) & CByte(255)))
        frame(3) = CByte((len & CByte(255)))
        frameCount = 4
    else
        frame(1) = CByte( 127)
        Dim len = CByte( rawData.length)
        frame(2) = CByte(((len >> 56 ) & CByte(255)))
        frame(3) = CByte(((len >> 48 ) & CByte(255)))
        frame(4) = CByte(((len >> 40 ) & CByte(255)))
        frame(5) = CByte(((len >> 32 ) & CByte(255)))
        frame(6) = CByte(((len >> 24 ) & CByte(255)))
        frame(7) = CByte(((len >> 16 ) & CByte(255)))
        frame(8) = CByte(((len >> 8 ) & CByte(255)))
        frame(9) = CByte((len & CByte(255)))
        frameCount = 10
    End If

    Dim bLength = frameCount + rawData.length
    Console.WriteLine(frameCount)
    Console.WriteLine(rawData.length)
    Dim reply(bLength+1) as byte

    Dim bLim = 0
    for i=0 to frameCount-1
        Console.WriteLine(blim)
        reply(bLim) = frame(i)
        bLim += 1
    Next
    
    for i=0 to rawData.length-1
        Console.WriteLine(blim)
        reply(bLim) = rawData(i)
        bLim += 1
    Next
    
    sck.Send(reply)
End Sub

You can use it in your clientProc:

'' Sending Hello World message
SendMessage(sck, "Hello World")

enter image description here

于 2012-10-17T11:50:42.797 回答