mirror of
https://gitee.com/jisol/jisol-game/
synced 2025-09-27 10:46:17 +00:00
提交Unity 联机Pro
This commit is contained in:
@@ -0,0 +1,355 @@
|
||||
#if !BESTHTTP_DISABLE_WEBSOCKET && (!UNITY_WEBGL || UNITY_EDITOR)
|
||||
|
||||
using System;
|
||||
using BestHTTP.Extensions;
|
||||
using BestHTTP.PlatformSupport.Memory;
|
||||
using System.Runtime.CompilerServices;
|
||||
using BestHTTP.PlatformSupport.IL2CPP;
|
||||
using BestHTTP.Logger;
|
||||
|
||||
#if BESTHTTP_WITH_BURST
|
||||
using Unity.Burst;
|
||||
using Unity.Burst.Intrinsics;
|
||||
using static Unity.Burst.Intrinsics.X86.Avx2;
|
||||
using static Unity.Burst.Intrinsics.X86.Sse2;
|
||||
using static Unity.Burst.Intrinsics.Arm.Neon;
|
||||
#endif
|
||||
|
||||
namespace BestHTTP.WebSocket.Frames
|
||||
{
|
||||
/// <summary>
|
||||
/// Denotes a binary frame. The "Payload data" is arbitrary binary data whose interpretation is solely up to the application layer.
|
||||
/// This is the base class of all other frame writers, as all frame can be represented as a byte array.
|
||||
/// </summary>
|
||||
#if BESTHTTP_WITH_BURST
|
||||
[BurstCompile]
|
||||
#endif
|
||||
[Il2CppEagerStaticClassConstruction]
|
||||
public struct WebSocketFrame
|
||||
{
|
||||
public WebSocketFrameTypes Type { get; private set; }
|
||||
|
||||
public BufferSegment Data { get; private set; }
|
||||
|
||||
public WebSocket Websocket { get; private set; }
|
||||
|
||||
public byte Header;
|
||||
|
||||
public WebSocketFrame(WebSocket webSocket, WebSocketFrameTypes type, BufferSegment data)
|
||||
:this(webSocket, type, data, true)
|
||||
{ }
|
||||
|
||||
public WebSocketFrame(WebSocket webSocket, WebSocketFrameTypes type, BufferSegment data, bool useExtensions)
|
||||
: this(webSocket, type, data, true, useExtensions)
|
||||
{
|
||||
}
|
||||
|
||||
public WebSocketFrame(WebSocket webSocket, WebSocketFrameTypes type, BufferSegment data, bool isFinal, bool useExtensions)
|
||||
:this(webSocket, type, data, isFinal, useExtensions, copyData: true)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public WebSocketFrame(WebSocket webSocket, WebSocketFrameTypes type, BufferSegment data, bool isFinal, bool useExtensions, bool copyData)
|
||||
{
|
||||
if (!isFinal)
|
||||
throw new NotSupportedException("isFinal parameter is not true");
|
||||
this.Type = type;
|
||||
this.Websocket = webSocket;
|
||||
this.Data = data;
|
||||
|
||||
if (this.Data.Data != null)
|
||||
{
|
||||
if (copyData)
|
||||
{
|
||||
var from = this.Data;
|
||||
|
||||
var buffer = BufferPool.Get(this.Data.Count, true);
|
||||
this.Data = new BufferSegment(buffer, 0, this.Data.Count);
|
||||
|
||||
Array.Copy(from.Data, (int)from.Offset, this.Data.Data, this.Data.Offset, this.Data.Count);
|
||||
}
|
||||
}
|
||||
else
|
||||
this.Data = BufferSegment.Empty;
|
||||
|
||||
// We use the header only for storing extension flags only
|
||||
this.Header = 0x00;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("[WebSocketFrame Type: {0}, Header: {1:X2}, Data: {2}]", this.Type, this.Header, this.Data);
|
||||
}
|
||||
|
||||
public void WriteTo(Action<BufferSegment, BufferSegment> callback, uint maxFragmentSize, bool mask, LoggingContext context)
|
||||
{
|
||||
|
||||
|
||||
if (HTTPManager.Logger.Level <= Logger.Loglevels.All)
|
||||
HTTPManager.Logger.Verbose("WebSocketFrame", "WriteTo - Frame: " + ToString(), context);
|
||||
|
||||
if ((this.Type == WebSocketFrameTypes.Binary || this.Type == WebSocketFrameTypes.Text))
|
||||
{
|
||||
DoExtensions();
|
||||
if (this.Data.Count > maxFragmentSize)
|
||||
FragmentAndSend(callback, maxFragmentSize, mask, context);
|
||||
else
|
||||
WriteFragment(callback, (byte)(0x80 | this.Header | (byte)this.Type), this.Data, mask, context);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteFragment(callback, (byte)(0x80 | this.Header | (byte)this.Type), this.Data, mask, context);
|
||||
}
|
||||
}
|
||||
|
||||
private void DoExtensions()
|
||||
{
|
||||
if (this.Websocket != null && this.Websocket.Extensions != null)
|
||||
{
|
||||
for (int i = 0; i < this.Websocket.Extensions.Length; ++i)
|
||||
{
|
||||
var ext = this.Websocket.Extensions[i];
|
||||
if (ext != null)
|
||||
{
|
||||
this.Header |= ext.GetFrameHeader(this, this.Header);
|
||||
BufferSegment newData = ext.Encode(this);
|
||||
|
||||
if (newData != this.Data)
|
||||
{
|
||||
BufferPool.Release(this.Data);
|
||||
|
||||
this.Data = newData;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void FragmentAndSend(Action<BufferSegment, BufferSegment> callback, uint maxFragmentSize, bool mask, LoggingContext context)
|
||||
{
|
||||
int pos = this.Data.Offset;
|
||||
int endPos = this.Data.Offset + this.Data.Count;
|
||||
|
||||
byte header = (byte)(0x00 | this.Header | (byte)this.Type);
|
||||
|
||||
while (pos < endPos)
|
||||
{
|
||||
int chunkLength = Math.Min((int)maxFragmentSize, endPos - pos);
|
||||
|
||||
WriteFragment(callback: callback,
|
||||
Header: header,
|
||||
Data: this.Data.Slice((int)pos, (int)chunkLength),
|
||||
mask: mask,
|
||||
context: context);
|
||||
|
||||
pos += chunkLength;
|
||||
|
||||
// set only the IsFinal flag, every other flags are zero
|
||||
header = (byte)(pos + chunkLength >= this.Data.Count ? 0x80 : 0x00);
|
||||
}
|
||||
}
|
||||
|
||||
private static unsafe void WriteFragment(Action<BufferSegment, BufferSegment> callback, byte Header, BufferSegment Data, bool mask, LoggingContext context)
|
||||
{
|
||||
// For the complete documentation for this section see:
|
||||
// http://tools.ietf.org/html/rfc6455#section-5.2
|
||||
|
||||
// Header(1) + Len(8) + Mask (4)
|
||||
byte[] wsHeader = BufferPool.Get(13, true);
|
||||
int pos = 0;
|
||||
|
||||
// Write the header
|
||||
wsHeader[pos++] = Header;
|
||||
|
||||
// The length of the "Payload data", in bytes: if 0-125, that is the payload length. If 126, the following 2 bytes interpreted as a
|
||||
// 16-bit unsigned integer are the payload length. If 127, the following 8 bytes interpreted as a 64-bit unsigned integer (the
|
||||
// most significant bit MUST be 0) are the payload length. Multibyte length quantities are expressed in network byte order.
|
||||
if (Data.Count < 126)
|
||||
{
|
||||
wsHeader[pos++] = (byte)(0x80 | (byte)Data.Count);
|
||||
}
|
||||
else if (Data.Count < UInt16.MaxValue)
|
||||
{
|
||||
wsHeader[pos++] = (byte)(0x80 | 126);
|
||||
var count = (UInt16)Data.Count;
|
||||
wsHeader[pos++] = (byte)(count >> 8);
|
||||
wsHeader[pos++] = (byte)(count);
|
||||
}
|
||||
else
|
||||
{
|
||||
wsHeader[pos++] = (byte)(0x80 | 127);
|
||||
|
||||
var count = (UInt64)Data.Count;
|
||||
wsHeader[pos++] = (byte)(count >> 56);
|
||||
wsHeader[pos++] = (byte)(count >> 48);
|
||||
wsHeader[pos++] = (byte)(count >> 40);
|
||||
wsHeader[pos++] = (byte)(count >> 32);
|
||||
wsHeader[pos++] = (byte)(count >> 24);
|
||||
wsHeader[pos++] = (byte)(count >> 16);
|
||||
wsHeader[pos++] = (byte)(count >> 8);
|
||||
wsHeader[pos++] = (byte)(count);
|
||||
}
|
||||
|
||||
if (Data != BufferSegment.Empty)
|
||||
{
|
||||
// All frames sent from the client to the server are masked by a 32-bit value that is contained within the frame. This field is
|
||||
// present if the mask bit is set to 1 and is absent if the mask bit is set to 0.
|
||||
// If the data is being sent by the client, the frame(s) MUST be masked.
|
||||
|
||||
uint hash = mask ? (uint)wsHeader.GetHashCode() : 0;
|
||||
|
||||
wsHeader[pos++] = (byte)(hash >> 24);
|
||||
wsHeader[pos++] = (byte)(hash >> 16);
|
||||
wsHeader[pos++] = (byte)(hash >> 8);
|
||||
wsHeader[pos++] = (byte)(hash);
|
||||
|
||||
// Do the masking.
|
||||
if (mask)
|
||||
{
|
||||
fixed (byte* pData = Data.Data/*, pmask = &wsHeader[pos - 4]*/)
|
||||
{
|
||||
byte* alignedMask = stackalloc byte[4];
|
||||
alignedMask[0] = wsHeader[pos - 4];
|
||||
alignedMask[1] = wsHeader[pos - 3];
|
||||
alignedMask[2] = wsHeader[pos - 2];
|
||||
alignedMask[3] = wsHeader[pos - 1];
|
||||
|
||||
ApplyMask(pData, Data.Offset, Data.Count, alignedMask);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
wsHeader[pos++] = 0;
|
||||
wsHeader[pos++] = 0;
|
||||
wsHeader[pos++] = 0;
|
||||
wsHeader[pos++] = 0;
|
||||
}
|
||||
|
||||
var header = wsHeader.AsBuffer(pos);
|
||||
|
||||
if (HTTPManager.Logger.Level <= Logger.Loglevels.All)
|
||||
HTTPManager.Logger.Verbose("WebSocketFrame", string.Format("WriteFragment - Header: {0}, data chunk: {1}", header.ToString(), Data.ToString()), context);
|
||||
|
||||
callback(header, Data);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#if BESTHTTP_WITH_BURST
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
#endif
|
||||
public unsafe static void ApplyMask(
|
||||
#if BESTHTTP_WITH_BURST
|
||||
[NoAlias]
|
||||
#endif
|
||||
byte* pData,
|
||||
int DataOffset,
|
||||
int DataCount,
|
||||
#if BESTHTTP_WITH_BURST
|
||||
[NoAlias]
|
||||
#endif
|
||||
byte* pmask
|
||||
)
|
||||
{
|
||||
int targetOffset = DataOffset + DataCount;
|
||||
uint umask = *(uint*)pmask;
|
||||
|
||||
#if BESTHTTP_WITH_BURST
|
||||
if (targetOffset - DataOffset >= 32)
|
||||
{
|
||||
if (IsAvx2Supported)
|
||||
{
|
||||
v256 mask = new v256(umask);
|
||||
v256 ldstrMask = new v256((byte)0xFF);
|
||||
|
||||
while (targetOffset - DataOffset >= 32)
|
||||
{
|
||||
// load data
|
||||
v256 data = mm256_maskload_epi32(pData + DataOffset, ldstrMask);
|
||||
|
||||
// xor
|
||||
v256 result = mm256_xor_si256(data, mask);
|
||||
|
||||
// store
|
||||
mm256_maskstore_epi32(pData + DataOffset, ldstrMask, result);
|
||||
|
||||
// advance
|
||||
DataOffset += 32;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (targetOffset - DataOffset >= 16)
|
||||
{
|
||||
v128 mask = new v128(umask);
|
||||
|
||||
if (IsSse2Supported)
|
||||
{
|
||||
while (targetOffset - DataOffset >= 16)
|
||||
{
|
||||
// load data
|
||||
v128 data = loadu_si128(pData + DataOffset);
|
||||
|
||||
// xor
|
||||
var result = xor_si128(data, mask);
|
||||
|
||||
// store
|
||||
storeu_si128(pData + DataOffset, result);
|
||||
|
||||
// advance
|
||||
DataOffset += 16;
|
||||
}
|
||||
}
|
||||
else if (IsNeonSupported)
|
||||
{
|
||||
while (targetOffset - DataOffset >= 16)
|
||||
{
|
||||
// load data
|
||||
v128 data = vld1q_u8(pData + DataOffset);
|
||||
|
||||
// xor
|
||||
v128 result = veorq_u8(data, mask);
|
||||
|
||||
// store
|
||||
vst1q_u8(pData + DataOffset, result);
|
||||
|
||||
// advance
|
||||
DataOffset += 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// fallback to calculate by reinterpret-casting to ulong
|
||||
if (targetOffset - DataOffset >= 8)
|
||||
{
|
||||
ulong* ulpData = (ulong*)(pData + DataOffset);
|
||||
|
||||
#if UNITY_ANDROID && !UNITY_EDITOR
|
||||
if ((long)ulpData % sizeof(ulong) == 0)
|
||||
{
|
||||
#endif
|
||||
// duplicate the mask to fill up a whole ulong.
|
||||
ulong ulmask = (((ulong)umask << 32) | umask);
|
||||
|
||||
while (targetOffset - DataOffset >= 8)
|
||||
{
|
||||
*ulpData = *ulpData ^ ulmask;
|
||||
|
||||
ulpData++;
|
||||
DataOffset += 8;
|
||||
}
|
||||
#if UNITY_ANDROID && !UNITY_EDITOR
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// process remaining bytes (0..7)
|
||||
for (int i = DataOffset; i < targetOffset; ++i)
|
||||
pData[i] = (byte)(pData[i] ^ pmask[(i - DataOffset) % 4]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2f674a60005f409438aa505311bf2e7a
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,220 @@
|
||||
#if !BESTHTTP_DISABLE_WEBSOCKET && (!UNITY_WEBGL || UNITY_EDITOR)
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
using BestHTTP.Extensions;
|
||||
using BestHTTP.PlatformSupport.Memory;
|
||||
|
||||
namespace BestHTTP.WebSocket.Frames
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an incoming WebSocket Frame.
|
||||
/// </summary>
|
||||
public struct WebSocketFrameReader
|
||||
{
|
||||
#region Properties
|
||||
|
||||
public byte Header { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if it's a final Frame in a sequence, or the only one.
|
||||
/// </summary>
|
||||
public bool IsFinal { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The type of the Frame.
|
||||
/// </summary>
|
||||
public WebSocketFrameTypes Type { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The decoded array of bytes.
|
||||
/// </summary>
|
||||
public BufferSegment Data { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Textual representation of the received Data.
|
||||
/// </summary>
|
||||
public string DataAsText { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal & Private Functions
|
||||
|
||||
internal unsafe void Read(Stream stream)
|
||||
{
|
||||
// For the complete documentation for this section see:
|
||||
// http://tools.ietf.org/html/rfc6455#section-5.2
|
||||
|
||||
this.Header = ReadByte(stream);
|
||||
|
||||
// The first byte is the Final Bit and the type of the frame
|
||||
IsFinal = (this.Header & 0x80) != 0;
|
||||
Type = (WebSocketFrameTypes)(this.Header & 0xF);
|
||||
|
||||
byte maskAndLength = ReadByte(stream);
|
||||
|
||||
// The second byte is the Mask Bit and the length of the payload data
|
||||
if ((maskAndLength & 0x80) != 0)
|
||||
throw new NotImplementedException($"Payload from the server is masked!");
|
||||
|
||||
// if 0-125, that is the payload length.
|
||||
var length = (UInt64)(maskAndLength & 127);
|
||||
|
||||
// If 126, the following 2 bytes interpreted as a 16-bit unsigned integer are the payload length.
|
||||
if (length == 126)
|
||||
{
|
||||
byte[] rawLen = BufferPool.Get(2, true);
|
||||
|
||||
stream.ReadBuffer(rawLen, 2);
|
||||
|
||||
if (BitConverter.IsLittleEndian)
|
||||
Array.Reverse(rawLen, 0, 2);
|
||||
|
||||
length = (UInt64)BitConverter.ToUInt16(rawLen, 0);
|
||||
|
||||
BufferPool.Release(rawLen);
|
||||
}
|
||||
else if (length == 127)
|
||||
{
|
||||
// If 127, the following 8 bytes interpreted as a 64-bit unsigned integer (the
|
||||
// most significant bit MUST be 0) are the payload length.
|
||||
|
||||
byte[] rawLen = BufferPool.Get(8, true);
|
||||
|
||||
stream.ReadBuffer(rawLen, 8);
|
||||
|
||||
if (BitConverter.IsLittleEndian)
|
||||
Array.Reverse(rawLen, 0, 8);
|
||||
|
||||
length = (UInt64)BitConverter.ToUInt64(rawLen, 0);
|
||||
|
||||
BufferPool.Release(rawLen);
|
||||
}
|
||||
|
||||
if (length == 0L)
|
||||
{
|
||||
Data = BufferSegment.Empty;
|
||||
return;
|
||||
}
|
||||
|
||||
var buffer = BufferPool.Get((long)length, true);
|
||||
|
||||
uint readLength = 0;
|
||||
|
||||
try
|
||||
{
|
||||
do
|
||||
{
|
||||
int read = stream.Read(buffer, (int)readLength, (int)(length - readLength));
|
||||
|
||||
if (read <= 0)
|
||||
throw ExceptionHelper.ServerClosedTCPStream();
|
||||
|
||||
readLength += (uint)read;
|
||||
} while (readLength < length);
|
||||
}
|
||||
catch
|
||||
{
|
||||
BufferPool.Release(buffer);
|
||||
throw;
|
||||
}
|
||||
this.Data = new BufferSegment(buffer, 0, (int)length);
|
||||
}
|
||||
|
||||
private byte ReadByte(Stream stream)
|
||||
{
|
||||
int read = stream.ReadByte();
|
||||
|
||||
if (read < 0)
|
||||
throw ExceptionHelper.ServerClosedTCPStream();
|
||||
|
||||
return (byte)read;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Functions
|
||||
|
||||
/// <summary>
|
||||
/// Assembles all fragments into a final frame. Call this on the last fragment of a frame.
|
||||
/// </summary>
|
||||
/// <param name="fragments">The list of previously downloaded and parsed fragments of the frame</param>
|
||||
public void Assemble(List<WebSocketFrameReader> fragments)
|
||||
{
|
||||
// this way the following algorithms will handle this fragment's data too
|
||||
fragments.Add(this);
|
||||
|
||||
UInt64 finalLength = 0;
|
||||
for (int i = 0; i < fragments.Count; ++i)
|
||||
finalLength += (UInt64)fragments[i].Data.Count;
|
||||
|
||||
byte[] buffer = BufferPool.Get((long)finalLength, true);
|
||||
UInt64 pos = 0;
|
||||
for (int i = 0; i < fragments.Count; ++i)
|
||||
{
|
||||
if (fragments[i].Data.Count > 0)
|
||||
Array.Copy(fragments[i].Data.Data, fragments[i].Data.Offset, buffer, (int)pos, (int)fragments[i].Data.Count);
|
||||
fragments[i].ReleaseData();
|
||||
|
||||
pos += (UInt64)fragments[i].Data.Count;
|
||||
}
|
||||
|
||||
// All fragments of a message are of the same type, as set by the first fragment's opcode.
|
||||
this.Type = fragments[0].Type;
|
||||
|
||||
// Reserver flags may be contained only in the first fragment
|
||||
|
||||
this.Header = fragments[0].Header;
|
||||
this.Data = new BufferSegment(buffer, 0, (int)finalLength);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function will decode the received data incrementally with the associated websocket's extensions.
|
||||
/// </summary>
|
||||
public void DecodeWithExtensions(WebSocket webSocket)
|
||||
{
|
||||
if (webSocket.Extensions != null)
|
||||
for (int i = 0; i < webSocket.Extensions.Length; ++i)
|
||||
{
|
||||
var ext = webSocket.Extensions[i];
|
||||
if (ext != null)
|
||||
{
|
||||
var newData = ext.Decode(this.Header, this.Data);
|
||||
if (this.Data != newData)
|
||||
{
|
||||
this.ReleaseData();
|
||||
this.Data = newData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.Type == WebSocketFrameTypes.Text)
|
||||
{
|
||||
if (this.Data != BufferSegment.Empty)
|
||||
{
|
||||
this.DataAsText = System.Text.Encoding.UTF8.GetString(this.Data.Data, this.Data.Offset, this.Data.Count);
|
||||
this.ReleaseData();
|
||||
}
|
||||
else
|
||||
HTTPManager.Logger.Warning("WebSocketFrameReader", "Empty Text frame received!");
|
||||
}
|
||||
}
|
||||
|
||||
public void ReleaseData()
|
||||
{
|
||||
BufferPool.Release(this.Data);
|
||||
this.Data = BufferSegment.Empty;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("[{0} Header: {1:X2}, IsFinal: {2}, Data: {3}]", this.Type.ToString(), this.Header, this.IsFinal, this.Data);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 551161b05e7dd8c4d85aadf44c841056
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,48 @@
|
||||
#if !BESTHTTP_DISABLE_WEBSOCKET && (!UNITY_WEBGL || UNITY_EDITOR)
|
||||
|
||||
namespace BestHTTP.WebSocket.Frames
|
||||
{
|
||||
public enum WebSocketFrameTypes : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// A fragmented message's first frame's contain the type of the message(binary or text), all consecutive frame of that message must be a Continuation frame.
|
||||
/// Last of these frame's Fin bit must be 1.
|
||||
/// </summary>
|
||||
/// <example>For a text message sent as three fragments, the first fragment would have an opcode of 0x1 (text) and a FIN bit clear,
|
||||
/// the second fragment would have an opcode of 0x0 (Continuation) and a FIN bit clear,
|
||||
/// and the third fragment would have an opcode of 0x0 (Continuation) and a FIN bit that is set.</example>
|
||||
Continuation = 0x0,
|
||||
Text = 0x1,
|
||||
Binary = 0x2,
|
||||
//Reserved1 = 0x3,
|
||||
//Reserved2 = 0x4,
|
||||
//Reserved3 = 0x5,
|
||||
//Reserved4 = 0x6,
|
||||
//Reserved5 = 0x7,
|
||||
|
||||
/// <summary>
|
||||
/// The Close frame MAY contain a body (the "Application data" portion of the frame) that indicates a reason for closing,
|
||||
/// such as an endpoint shutting down, an endpoint having received a frame too large, or an endpoint having received a frame that
|
||||
/// does not conform to the format expected by the endpoint.
|
||||
/// As the data is not guaranteed to be human readable, clients MUST NOT show it to end users.
|
||||
/// </summary>
|
||||
ConnectionClose = 0x8,
|
||||
|
||||
/// <summary>
|
||||
/// The Ping frame contains an opcode of 0x9. A Ping frame MAY include "Application data".
|
||||
/// </summary>
|
||||
Ping = 0x9,
|
||||
|
||||
/// <summary>
|
||||
/// A Pong frame sent in response to a Ping frame must have identical "Application data" as found in the message body of the Ping frame being replied to.
|
||||
/// </summary>
|
||||
Pong = 0xA,
|
||||
//Reserved6 = 0xB,
|
||||
//Reserved7 = 0xC,
|
||||
//Reserved8 = 0xD,
|
||||
//Reserved9 = 0xE,
|
||||
//Reserved10 = 0xF,
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 111b231c861908546b2c5acfa6d69bae
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Reference in New Issue
Block a user