金铉Unity插件库 Unity版本2018.4.32f 目前包含本地化存储功能(根据类名存储读写),TCP客户端监听类型功能
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

165 lines
6.8 KiB

using UnityEngine;
using System;
using System.Net;
using System.Net.Sockets;
using System.Collections.Concurrent;
// For parsing the client websocket requests
using System.Text;
using System.Text.RegularExpressions;
// For creating a thread
using System.Threading;
namespace WebSocketServer {
public enum WebSocketEventType {
Open,
Close,
Message
}
public struct WebSocketMessage {
public WebSocketMessage(WebSocketConnection connection, string data) {
this.id = Guid.NewGuid().ToString();
this.connection = connection;
this.data = data;
}
public string id { get; }
public WebSocketConnection connection { get; }
public string data { get; }
}
public struct WebSocketEvent {
public WebSocketEvent(WebSocketConnection connection, WebSocketEventType type, string data) {
this.id = Guid.NewGuid().ToString();
this.connection = connection;
this.type = type;
this.data = data;
}
public string id { get; }
public WebSocketEventType type { get; }
public WebSocketConnection connection { get; }
public string data { get; }
}
public class WebSocketConnection {
public string id;
private TcpClient client;
private NetworkStream stream;
private WebSocketServer server;
private Thread connectionHandler;
public WebSocketConnection(TcpClient client, WebSocketServer server) {
this.id = Guid.NewGuid().ToString();
this.client = client;
this.stream = client.GetStream();
this.server = server;
}
public bool Establish() {
// Wait for enough bytes to be available
while (!stream.DataAvailable);
while(client.Available < 3);
// Translate bytes of request to a RequestHeader object
Byte[] bytes = new Byte[client.Available];
stream.Read(bytes, 0, bytes.Length);
RequestHeader request = new RequestHeader(Encoding.UTF8.GetString(bytes));
// Check if the request complies with WebSocket protocol.
if (WebSocketProtocol.CheckConnectionHandshake(request)) {
// If so, initiate the connection by sending a reply according to protocol.
Byte[] response = WebSocketProtocol.CreateHandshakeReply(request);
stream.Write(response, 0, response.Length);
Debug.Log("WebSocket client connected.");
// Start message handling
connectionHandler = new Thread(new ThreadStart(HandleConnection));
connectionHandler.IsBackground = true;
connectionHandler.Start();
// Call the server callback.
WebSocketEvent wsEvent = new WebSocketEvent(this, WebSocketEventType.Open, null);
server.events.Enqueue(wsEvent);
return true;
} else {
return false;
}
}
private void HandleConnection () {
while (true) {
WebSocketDataFrame dataframe = ReadDataFrame();
if (dataframe.fin) {
if ((WebSocketOpCode)dataframe.opcode == WebSocketOpCode.Text) {
// Let the server know of the message.
string data = WebSocketProtocol.DecodeText(dataframe);
WebSocketEvent wsEvent = new WebSocketEvent(this, WebSocketEventType.Message, data);
server.events.Enqueue(wsEvent);
} else if ((WebSocketOpCode)dataframe.opcode == WebSocketOpCode.Close) {
// Handle closing the connection.
Debug.Log("Client closed the connection.");
// Close the connection.
stream.Close();
client.Close();
// Call server callback.
WebSocketEvent wsEvent = new WebSocketEvent(this, WebSocketEventType.Close, null);
server.events.Enqueue(wsEvent);
// Jump out of the loop.
break;
}
} else {
Debug.Log("Framentation encoutered.");
}
}
}
private WebSocketDataFrame ReadDataFrame() {
const int DataframeHead = 2; // Length of dataframe head
const int ShortPayloadLength = 2; // Length of a short payload length field
const int LongPayloadLength = 8; // Length of a long payload length field
const int Mask = 4; // Length of the payload mask
// Wait for a dataframe head to be available, then read the data.
while (!stream.DataAvailable && client.Available < DataframeHead);
Byte[] bytes = new Byte[DataframeHead];
stream.Read(bytes, 0, DataframeHead);
// Decode the message head, including FIN, OpCode, and initial byte of the payload length.
WebSocketDataFrame dataframe = WebSocketProtocol.CreateDataFrame();
WebSocketProtocol.ParseDataFrameHead(bytes, ref dataframe);
// Depending on the dataframe length, read & decode the next bytes for payload length
if (dataframe.length == 126) {
while (client.Available < ShortPayloadLength); // Wait until data is available
Array.Resize(ref bytes, bytes.Length + ShortPayloadLength);
stream.Read(bytes, bytes.Length - ShortPayloadLength, ShortPayloadLength); // Read the next two bytes for length
} else if (dataframe.length == 127) {
while (client.Available < LongPayloadLength); // Wait until data is available
Array.Resize(ref bytes, bytes.Length + LongPayloadLength);
stream.Read(bytes, bytes.Length - LongPayloadLength, LongPayloadLength); // Read the next two bytes for length
}
WebSocketProtocol.ParseDataFrameLength(bytes, ref dataframe); // Parse the length
if (dataframe.mask) {
while (client.Available < Mask); // Wait until data is available
Array.Resize(ref bytes, bytes.Length + Mask);
stream.Read(bytes, bytes.Length - Mask, Mask); // Read the next four bytes for mask
}
while (client.Available < dataframe.length); // Wait until data is available
Array.Resize(ref bytes, bytes.Length + dataframe.length);
stream.Read(bytes, bytes.Length - dataframe.length, dataframe.length); // Read the payload
dataframe.data = bytes;
return dataframe;
}
}
}