Написал простенький вебсокет сервер взяв от
сюда некоторые методы.
Мой кодclass WS
{
private readonly string GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
private readonly string ip;
private readonly int port;
byte[] Segment { get; } = new byte[512];
public Socket socket { get; set; }
public WS(int port, string ip)
{
this.port = port;
this.ip = ip;
IPAddress[] ipAddress = Dns.GetHostAddresses(this.ip);
IPEndPoint ipLocalEndPoint = new IPEndPoint(ipAddress[0], this.port);
this.socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
this.Bind(ipLocalEndPoint);
this.Listen();
}
private byte[] GetHandshake(string key)
{
string acceptSHA1 = key + GUID;
byte[] encodingBytes = Encoding.ASCII.GetBytes(acceptSHA1);
byte[] hash = SHA1.HashData(encodingBytes);
var hashString = Convert.ToBase64String(hash);
byte[] msg = Encoding.UTF8.GetBytes("HTTP/1.1 101 Switching Protocols\r\n" +
"Upgrade: websocket\r\n" +
"Connection: Upgrade\r\n" +
"Sec-WebSocket-Accept: " + hashString +
"\r\n\r\n");
Console.WriteLine(Encoding.UTF8.GetString(msg));
return msg;
}
public async Task<int> GetKeyWS(Socket acceptData)
{
await acceptData.ReceiveAsync(this.Segment);
HttpInfo headersKey = new HttpInfo(this.Segment);
byte[] buffer = GetHandshake(headersKey.GetHeaderValue("Sec-WebSocket-Key"));
await acceptData.SendAsync(buffer);
byte[] bytes = new byte[65536];
while (true)
{
if (bytes[0] == 136)
{
for (int i = 0; i < 6; ++i)
{
Console.WriteLine(bytes[i]);
}
return 0;
}
else
{
await acceptData.ReceiveAsync(bytes);
Console.WriteLine(acceptData.RemoteEndPoint);
int payload = bytes[1] & 127;
int payloadLength = (bytes[1] & 127) < 126 ? bytes[1] & 127 : BitConverter.ToInt16(new byte[] { bytes[3], bytes[2] }, 0);
byte[] dataBuffer;
byte[] slice = new byte[4];
int offset = 0;
if (payloadLength <= 125)
{
slice = bytes[2..^5];
offset = 2;
}
int payload_first_byte = offset + 4;
byte[] decode = new byte[payloadLength];
for (int i = 0; i < payload; ++i, ++payload_first_byte)
{
decode[i] = (byte)(bytes[payload_first_byte] ^ slice[i % 4]);
}
dataBuffer = new byte[] { 129, Convert.ToByte(payload) };
byte[] arraySend = new byte[dataBuffer.Length + decode.Length];
Array.Copy(dataBuffer, 0, arraySend, 0, dataBuffer.Length);
Array.Copy(decode, 0, arraySend, 2, decode.Length);
await acceptData.SendAsync(arraySend);
}
}
}
private void Bind(IPEndPoint ep)
{
this.socket.Bind(ep);
}
private void Listen()
{
this.socket.Listen();
}
}
internal class Program
{
static async Task<int> Main()
{
WS ws = new(7878, "192.168.0.2");
try
{
while (true)
{
var acceptAsync = await ws.socket.AcceptAsync();
new Thread(async () => await ws.GetKeyWS(acceptAsync)).Start();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return 0;
}
}
}
Клиент<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
</head>
<body>
<form name="publish">
<input type="text" name="message" onsubmit="return false;">
<input type="submit" value="Отправить" onsubmit="return false;">
</form>
<div id="messages"></div>
<script>
let manualPongIntervalId;
const ws = new WebSocket("ws://192.168.0.2:7878");
const serverPingInterval = 30000;
let socket = null;
ws.onopen = () => {
console.log('OPEN')
}
document.forms.publish.onsubmit = function(e) {
e.preventDefault();
let outgoingMessage = this.message.value;
ws.send(outgoingMessage);
return false
}
ws.onmessage = function(event) {
let message = event.data;
let messageElem = document.createElement('div');
messageElem.textContent = message;
document.getElementById('messages').prepend(messageElem);
};
ws.onclose = (event) => {
};
ws.onerror = function(error) {
console.log(`[error] ${error.message}`);
};
</script>
</body>
</html>
GetFrameDatapublic static SFrameMaskData GetFrameData(byte[] Data)
{
int opcode = Data[0] & 127;
int l = Data[1] & 127;
// If the length of the message is in the 2 first indexes
if (l <= 125)
{
int dataLength = (Data[1] & 127);
Console.WriteLine("opcode - " + opcode);
return new SFrameMaskData(dataLength, 2, dataLength + 6, (EOpcodeType)opcode);
}
// If the length of the message is in the following two indexes
if (l == 126)
{
// Combine the bytes to get the length
int dataLength = BitConverter.ToInt16(new byte[] { Data[3], Data[2] }, 0);
return new SFrameMaskData(dataLength, 4, dataLength + 8, (EOpcodeType)opcode);
}
// If the data length is in the following 8 indexes
if (l == 127)
{
// Get the following 8 bytes to combine to get the data
byte[] combine = new byte[8];
for (int i = 0; i < 8; i++) combine[i] = Data[i + 2];
// Combine the bytes to get the length
//int dataLength = (int)BitConverter.ToInt64(new byte[] { Data[9], Data[8], Data[7], Data[6], Data[5], Data[4], Data[3], Data[2] }, 0);
int dataLength = (int)BitConverter.ToInt64(combine, 0);
return new SFrameMaskData(dataLength, 10, dataLength + 14, (EOpcodeType)opcode);
}
// error
return new SFrameMaskData(0, 0, 0, 0);
}
В хроме все хорошо, при открытии соединения я не чего не получаю, при закрытии соединения получаю
byte[0] - 136
opcode - 8
lenght - 2
Frame - ClosedConnection
Но при открытии в других браузерах, я сразу же получаю не понятные сообщения.
В opera при открытии
spoiler,oezUbow_bow_bow_bow_bow_bow_bow_bow_bow_bow_bow_bow_bow_bow_bow_bow_bow_bow_bow_bow_bow_bow_bow_b
byte[0] - 110
opcode - 110
lenght - 100
Frame - 110
При закрытии соединения
byte[0] - 136
opcode - 8
lenght - 2
Frame - ClosedConnection
byte[0] - 110
opcode - 110
lenght - 100
Frame - 110
В яндексе такое сообщение при открытии
spoilerocyybitsbitsbitsbitsbitsbitsbitsbitsbitsbitsbitsbitsbitsbitsbitsbitsbitsbitsbitsbitsbitsbitsbit
byte[0] - 119
opcode - 119
lenght - 95
Frame - 119
При закрытии соединения
byte[0] - 136
opcode - 8
lenght - 2
Frame - ClosedConnection
byte[0] - 119
opcode - 119
lenght - 95
Frame - 119
Не могу понять, или это я что то не так делаю, или суть вопроса?