我目前正在编写一个Visual Basic脚本,该脚本在本地机器ip(127.0.0.1)和端口8181上打开TcpListener。我从谷歌浏览器连接到我的websocket服务器(通过AcceptSocket方法)。从Chrome,我向服务器发出发送请求,服务器可以读取它和所有内容。当我发回消息(如回声)时,我可以第一次发送它,但第二次出现错误:
Received unexpected continuation frame.
我需要的是一个 CByte,它告诉帧开始一个新的框架或结束打开的框架(不关闭套接字连接)
这是否可实现,如果是,解决方案是什么?
我用SendMessage(sck, "test")
称潜艇
这是我的邮件发件人的代码:
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
ElseIf rawData.Length >= 126 AndAlso rawData.Length <= 65535 Then
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
For i = 0 To reply.Length - 1
Console.WriteLine("Byte: " & reply(i))
Console.WriteLine("Char: " & CByte(reply(i)))
Next
sck.Send(reply, reply.Length, 0)
End Sub
更新:
将行Dim reply(bLength + 1) As Byte
更改为Dim reply(bLength) As Byte
后,我没有收到连续帧错误,而是收到一个新错误:
A server must not mask any frames that it sends to the client.
希望这些信息可以指出问题所在。
更新 2:
下面是整个客户端 Sub 对客户端执行所有操作。从接受到握手再到消息内容。
Private Sub clientStarter(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()
Dim dataSent As [Byte]() = Nothing
Dim dataRecieved(1024) As [Byte]
Dim bytes As Int32
Console.WriteLine(dataRecieved)
Dim message As String = Nothing
While (True)
If (sck.Connected = False) Then
Exit While
End If
bytes = sck.Receive(dataRecieved, dataRecieved.Length, 0)
'Console.WriteLine(bytes)
While (bytes > 0)
Console.WriteLine("recieved Data")
message = System.Text.Encoding.UTF8.GetString(dataRecieved, 0, bytes)
Console.WriteLine(bytes)
bytes = 0
If (bytes = 0) Then
Console.WriteLine("test")
Console.WriteLine(message)
dataSent = System.Text.Encoding.UTF8.GetBytes(message, 0, bytes)
SendMessage(sck, "test")
message = Nothing
End If
End While
End While
End Sub
更新 3(解决方案):
我已经解决了我的问题。通过将frame(1) = CByte(rawData.Length)
更改为frame(1) = CByte(rawData.Length + 1)
它合并了结尾 0 字节,现在消息的正确长度是正确的,让我摆脱了屏蔽问题。我想消息字节的末尾应该包含在消息长度中。
看起来您在消息末尾包含一个额外的字节。 不应该是行
Dim reply(bLength + 1) As Byte
更改为
Dim reply(bLength) As Byte
相反? 消息中所需要的只是操作码 + 长度 ( frameCount
) + 消息 ( rawData.Length
)。 websocket 客户端会将这些字节作为完整的有效消息读取。 然后,它将从您的消息中读取剩余字节作为新消息的开头,从而有效地破坏您实际发送的下一条消息。