Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
875 views
in Technique[技术] by (71.8m points)

html - Websocket Server VB.NET - Data Frame

I am trying to create the simplest WebSocket server with VB.NET. I manage to implement handshake but fail to send message after handshake. The following is my code:

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

The standard says that I need to send 0x00 byte, following by byte of UTF8, and end with 0xFF byte. I have done as it say yet my HTML client cannot receive the message.

The following is my HTML5 code:

<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>
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The standard says that I need to send 0x00 byte, following by byte of UTF8, and end with 0xFF byte

R?e?a?l?l?y??? ?W?h?e?r?e? ?d?i?d? ?y?o?u? ?g?e?t? ?t?h?a?t??? ?I? ?d?o?n?'?t? ?t?h?i?n?k? ?t?h?e?r?e? ?i?s? ?s?o?m?e?t?h?i?n?g? ?l?i?k?e? ?t?h?i?s? ?i?n? ?t?h?e? s?p?e?c?i?f?i?c?a?t?i?o?n?.

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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...