using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; using System.Security.Cryptography; using System.Xml; using Fleck; using System.Net.Security; using System.Security.Cryptography.X509Certificates; namespace Sog { public class WebSession : NetSession { const int WEBSOCKET_BUFFER_SIZE = 1024 * 64; private const string WebSocketResponseGuid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; // 证书 private X509Certificate2 m_certificate; // 掩码 private byte[] m_maskBytes = new byte[4]; private const UInt32 KeepAliveInterval = 60000; private const UInt32 RetryInterval = 10000; private bool m_recvAsyncPending; private bool m_sendAsyncPending; private object m_recvAsyncLocker; private object m_sendAsyncLocker; private AsyncState m_recvAsyncState; private AsyncState m_sendAsyncState; private object m_authenticateLocker; private bool m_authenticating; // 子协议协商,目前没有 private IEnumerable supportedSubProtocols; private bool IsHandShake; private object m_sendHandShakeLocker = new object(); private bool m_sendHandShakePending = false; public bool IsSendingClose { private set; get; } private object m_sendCloseFrameLocker = new object(); internal long LastCloseWebSocketSecond; // 避免太长时间无法关闭,设置一个超时 private string m_scheme; private bool needShutdown; // 只是为了判断是否需要socket.shutdown // 这个带有webSocket的控制帧头 private byte[] m_webRecvBuffer; protected int m_webAlreadyRecvLength; private Stream m_webStream; public string clientIp;//ip public WebSession(Socket socket, string scheme) : base(socket) { m_scheme = scheme; supportedSubProtocols = new string[0]; m_recvBuffer = new byte[WEBSOCKET_BUFFER_SIZE]; m_sendBuffer = new byte[WEBSOCKET_BUFFER_SIZE]; m_webRecvBuffer = new byte[WEBSOCKET_BUFFER_SIZE]; IsHandShake = false; IsSendingClose = false; InitRecvSendAsyncObject(); m_remoteEndPoint = (IPEndPoint)m_socket.RemoteEndPoint; m_minHeaderLength = m_protoPacker.GetHeaderLength(); m_headerBytes = new byte[m_protoPacker.GetFullHeaderLength()]; m_zeroLengthBytes = BuildZeroFrame(); // socket.Connected表示最近一次IO操作时的socket状态 // 这里Connected说明是server.accept成功时 if (m_socket.Connected) { needShutdown = true; } if (OSUtils.IsWindows()) { SetKeepAlive(socket, KeepAliveInterval, RetryInterval); } m_webStream = new NetworkStream(m_socket); } private void SetKeepAlive(Socket socket, UInt32 keepAliveInterval, UInt32 retryInterval) { int size = sizeof(UInt32); UInt32 on = 1; byte[] inArray = new byte[size * 3]; Array.Copy(BitConverter.GetBytes(on), 0, inArray, 0, size); Array.Copy(BitConverter.GetBytes(keepAliveInterval), 0, inArray, size, size); Array.Copy(BitConverter.GetBytes(retryInterval), 0, inArray, size * 2, size); socket.IOControl(IOControlCode.KeepAliveValues, inArray, null); } /// /// 构造一个空包websocket帧 /// /// private byte[] BuildZeroFrame() { byte[] zeroFrameData = new byte[10]; zeroFrameData[0] = (byte)((byte)FrameType.Binary + 128); zeroFrameData[1] = (byte)8; return zeroFrameData; } protected override void OnBindSocket() { m_remoteEndPoint = (IPEndPoint)m_socket.RemoteEndPoint; needShutdown = true; InitRecvSendAsyncObject(); } private void InitRecvSendAsyncObject() { m_recvAsyncLocker = new object(); m_sendAsyncLocker = new object(); m_authenticateLocker = new object(); m_sendAsyncState = new AsyncState(0, 0, false); m_recvAsyncState = new AsyncState(0, 0, false); } protected override void CloseSocket() { try { // 在调用Accept和Connect之前访问socket.RemoteEndPoint会抛出异常 TraceLog.Trace("WebSession.CloseSocket remote {0}", m_remoteEndPoint); if (m_socket != null && needShutdown) { needShutdown = false; m_socket.Shutdown(SocketShutdown.Both); } } catch (SocketException ex) { TraceLog.Trace("WebSession.CloseSocket SocketException errcode {0} msg {1}" , ex.ErrorCode, ex.Message); } catch (Exception ex) { TraceLog.Exception(ex); } finally { if (m_socket != null) { m_webStream.Close(); m_webStream.Dispose(); m_webStream = null; m_socket.Close(); m_socket = null; } } } public override void CheckSocketAndSendKeepAlive() { if (m_socket == null) { return; } //发送0字节是没有效果的,这里发一个空包,这个功能增大网络流量,可以将时间设置大点 //需要客户端兼容 long span = AppTime.GetNowSysSecond() - LastSendDataTimeSecond; if (span >= 60) { LastSendDataTimeSecond = AppTime.GetNowSysSecond(); try { if (m_webStream.CanWrite) { m_noWriteableCheckCount = 0; //有数据不能发送,会破坏结构 if (m_sendDataLeft == 0) { m_webStream.Write(m_zeroLengthBytes, 0, m_zeroLengthBytes.Length); } } else { CheckNoWriteableSocket(); } } catch (SocketException ex) { TraceLog.Error("WebSession.CheckSocketAndSendKeepAlive remote {0} SocketException err {1}" , m_remoteEndPoint, ex.SocketErrorCode); if (ex.SocketErrorCode != SocketError.WouldBlock) { Close(); } } catch (Exception ex) { TraceLog.Error("WebSession.CheckSocketAndSendKeepAlive remote {0} SocketException message {1}" , m_remoteEndPoint, ex.Message); Close(); } } } private void CheckNoWriteableSocket() { if (m_socket == null) { return; } // 通过send来判断socket是否还有效,万一成功时m_sendDataLeft!=0,就把消息打断了 // 改为count++; 后续只要socket有一次成功的recv/send就把计数清0 m_noWriteableCheckCount++; TraceLog.Trace("WebSession.CheckNoWriteableSocket socket no writeable, remote {0}, noWriteableCheckCount {1}" , m_remoteEndPoint, m_noWriteableCheckCount); LastSendDataTimeSecond = AppTime.GetNowSysSecond(); //如果连续多个5秒socket不可写,可以认为是断线了 if (m_noWriteableCheckCount >= 5) { TraceLog.Error("WebSession.CheckNoWriteableSocket socket no writeable, need close it remote {0}, noWriteableCheckCount {1} to much" , m_remoteEndPoint, m_noWriteableCheckCount); Close(); } } public override void RecvReadableSocket() { if (m_socket == null) { return; } try { int leftLen = m_webRecvBuffer.Length - m_webAlreadyRecvLength; int iRecvLen = m_webStream.Read(m_webRecvBuffer, m_webAlreadyRecvLength, leftLen); if (iRecvLen > 0) { TotalRecvLength += iRecvLen; LastRecvDataTimeSecond = AppTime.GetNowSysSecond(); m_webAlreadyRecvLength += iRecvLen; leftLen -= iRecvLen; if (WriteSendRecvLog) { TraceLog.Trace("WebSession.RecvReadableSocket sessionid {0} try recv remote {1}, really recv length {2} free buffer length {3}" , SessionID, m_remoteEndPoint, iRecvLen, leftLen); } TryReadWebSocketMessageFromBuffer(false, false); } } catch (SocketException socketex) { TraceLog.Error("WebSession.RecvReadableSocket socket sessionid {0} receive error HResult {1} message {2}" , SessionID, socketex.HResult, socketex.Message); Close(); } catch (Exception ex) { TraceLog.Error("WebSession.RecvReadableSocket socket sessionid {0} receive unkonw error, message {1}" , SessionID, ex.Message); Close(); } } public override void WriteWriteableSocket() { if (m_socket == null) { return; } m_noWriteableCheckCount = 0; try { if (m_sendDataLeft == 0) { CopyWebSocketSendBuffer(); } if (m_sendDataLeft > 0) { int requestSendLength = m_sendDataLeft; m_webStream.Write(m_sendBuffer, m_sendDataPos, requestSendLength); if (requestSendLength > 0) { TotalSendLength += requestSendLength; LastSendDataTimeSecond = AppTime.GetNowSysSecond(); m_sendDataLeft -= requestSendLength; if (m_sendDataLeft == 0) { m_sendDataPos = 0; } else { m_sendDataPos += requestSendLength; } OnSendCompleted(); } if (WriteSendRecvLog) { TraceLog.Trace("WebSession.WriteWriteableSocket session {5} try send remote {0} length {1}, really send length {2} left length {3} dataLengthInSendQueue {4}" , m_remoteEndPoint, requestSendLength, requestSendLength, m_sendDataLeft, m_dataLengthInSendQueue, SessionID); } } } catch (SocketException ex) { // 正常 if (ex.SocketErrorCode == SocketError.WouldBlock) { TraceLog.Trace("WebSession.WriteWriteableSocket session {0} send erro, errorcode WouldBlock" , SessionID); } else { TraceLog.Error("WebSession.WriteWriteableSocket session {0} send erro, errorcode {1} message {2}" , SessionID, ex.SocketErrorCode, ex.Message); TraceLog.Exception(ex); Close(); } } catch (Exception ex) { TraceLog.Error("WebSession.WriteWriteableSocket socket session {0} send erro, message {1}", SessionID, ex.Message); TraceLog.Exception(ex); Close(); } } public override void StartSendAsync() { if (m_socket == null) { return; } lock (m_authenticateLocker) { if (m_authenticating) { return; } } lock (m_sendAsyncLocker) { if (m_sendAsyncPending) { return; } m_sendAsyncPending = true; } TraceLog.TraceDetail("WebSession.StartSendAsync socket session {0}", SessionID); DoSendAsync(); } private void DoSendAsync() { if (m_sendDataLeft == 0) { CopyWebSocketSendBuffer(); } if (m_sendDataLeft > 0) { try { m_sendAsyncState.m_offset = m_sendDataPos; m_sendAsyncState.m_count = m_sendDataLeft; m_webStream.BeginWrite(m_sendBuffer, m_sendDataPos, m_sendDataLeft, OnSendAsyncCallback, m_sendAsyncState); } catch(Exception e) { TraceLog.Error("WebSession.DoSendAsync webSession {0} send error message {1}", SessionID, e); Close(); lock (m_sendAsyncLocker) { m_sendAsyncPending = false; } } }// keep alive else if (!IsSendingClose && AppTime.GetNowSysSecond() - LastSendDataTimeSecond >= 60) { try { m_sendAsyncState.m_keepAlive = true; TraceLog.Trace("WebSession.DoSendAsync socket session {0} keep alive, send empty message 000", SessionID); LastSendDataTimeSecond = AppTime.GetNowSysSecond(); m_webStream.BeginWrite(m_zeroLengthBytes, 0, m_zeroLengthBytes.Length, OnSendAsyncCallback, m_sendAsyncState); TraceLog.Trace("WebSession.DoSendAsync socket session {0} keep alive, send empty message 111", SessionID); } catch (Exception e){ TraceLog.Error("WebSession.DoSendAsync webSession {0} keep alive send error message {1}", SessionID, e); Close(); lock (m_sendAsyncLocker) { m_sendAsyncPending = false; } } } else { lock (m_sendAsyncLocker) { m_sendAsyncPending = false; } } } /// /// Send完成后需要调用一下,判断是否打开 /// private void OnSendCompleted() { lock (m_sendHandShakeLocker) { if (m_sendHandShakePending) { m_sendHandShakePending = false; IsHandShake = true; OnAsyncModeWebsocketOpen(); return; } } lock (m_sendCloseFrameLocker) { if (IsSendingClose) { IsSendingClose = false; Close(); return; } } } /// /// 异步send的CallBack /// /// /// private void OnSendAsyncCallback(IAsyncResult ar) { try { m_webStream.EndWrite(ar); var asyncState = ar.AsyncState as AsyncState; if (asyncState.m_keepAlive) { // keep alive if (WriteSendRecvLog) { TraceLog.TraceDetail("WebSession.OnSendAsyncCallback session {0} keepalive callback remote {1} left length {2} dataLengthInSendQueue {3}" , SessionID, m_remoteEndPoint, m_sendDataLeft, m_dataLengthInSendQueue); } } else { int iSendBytes = asyncState.m_count; TotalSendLength += iSendBytes; m_sendDataLeft -= iSendBytes; if (m_sendDataLeft == 0) { m_sendDataPos = 0; } else { m_sendDataPos += iSendBytes; } if (WriteSendRecvLog) { TraceLog.TraceDetail("WebSession.OnSendAsyncCallback session {0} remote {1} send length {2} left length {3} dataLengthInSendQueue {4}" , SessionID, m_remoteEndPoint, iSendBytes, m_sendDataLeft, m_dataLengthInSendQueue); } } m_sendAsyncState.Clear(); } catch (Exception ex) { TraceLog.Error("WebSession.OnSendAsyncCallback session {0} IsSocketClosed {1} SocketError {2} " , SessionID, IsSocketClosed, ex); Close(); lock (m_sendAsyncLocker) { m_sendAsyncPending = false; } return; } OnSendCompleted(); if (IsSocketClosed) { return; } DoSendAsync(); } public event NetEventHandler AsyncModeWebsocketOpen; private void OnAsyncModeWebsocketOpen() { SessionEventArgs e = new SessionEventArgs(); e.Session = this; TraceLog.TraceDetail("WebSession.OnAsyncModeWebsocketOpen remote {0} session {1}" , e.Session.RemoteEndPoint, e.Session.SessionID); if (AsyncModeWebsocketOpen != null) { AsyncModeWebsocketOpen(null, e); } } // 进行ssl验证 public void Authenticate(X509Certificate2 certificate) { lock (m_authenticateLocker) { if (m_authenticating) { return; } m_authenticating = true; } var sslStrem = new SslStream(m_webStream, false); m_webStream = sslStrem; Task authTask = sslStrem.AuthenticateAsServerAsync(certificate); authTask.ContinueWith(AuthenticateCallBack); } private void AuthenticateCallBack(Task authTask) { lock(m_authenticateLocker) { m_authenticating = false; } if (authTask.IsFaulted) { TraceLog.Error($"{SessionID } Authenticate falid"); // 认证失败,直接关掉 Close(); } else { StartRecvAsync(); } } public override void StartRecvAsync() { if (m_socket == null) { return; } lock (m_authenticateLocker) { if (m_authenticating) { return; } } lock (m_recvAsyncLocker) { if (m_recvAsyncPending) { return; } m_recvAsyncPending = true; } TraceLog.TraceDetail("WebSession.StartRecvAsync socket session {0}", SessionID); DoRecvAsync(); } private void DoRecvAsync() { if (m_webStream == null) { return; } try { TraceLog.TraceDetail("WebSession.DoRecvAsync socket session {0}", SessionID); m_recvAsyncState.m_offset = m_webAlreadyRecvLength; m_webStream.BeginRead(m_webRecvBuffer, m_webAlreadyRecvLength, m_webRecvBuffer.Length - m_webAlreadyRecvLength, OnRecvAsyncCallback, m_recvAsyncState); } catch (SocketException socketex) { TraceLog.Error("WebSession.DoRecvAsync socket session {0} receive error HResult {1} message {2}" , SessionID, socketex.HResult, socketex.Message); Close(); lock (m_recvAsyncLocker) { m_recvAsyncPending = false; } } catch (Exception ex) { TraceLog.Error("WebSession.DoRecvAsync socket session {0} receive unkonw error, message {1}" , SessionID, ex.Message); Close(); lock (m_recvAsyncLocker) { m_recvAsyncPending = false; } } } private void OnRecvAsyncCallback(IAsyncResult ar) { try { if (m_webStream == null) { return; } int iRecvLen = m_webStream.EndRead(ar); if (iRecvLen > 0) { m_webAlreadyRecvLength += iRecvLen; TotalRecvLength += iRecvLen; LastRecvDataTimeSecond = AppTime.GetNowSysSecond(); if (WriteSendRecvLog) { TraceLog.TraceDetail("WebSession.OnRecvAsyncCallback session {0} remote {1} recv length {2} m_alreadyRecvLength {3}" , SessionID, m_remoteEndPoint, iRecvLen, m_alreadyRecvLength); } TryReadWebSocketMessageFromBuffer(false, true); //继续接收消息 DoRecvAsync(); } else { TraceLog.Error("WebSession.OnRecvAsyncCallback m_webStream session {0} IsSocketClosed {1} recvLen:0 so close" , SessionID, IsSocketClosed); Close(); lock (m_recvAsyncLocker) { m_recvAsyncPending = false; } return; } } catch (Exception ex) { //接收过程中关闭 TraceLog.Debug("WebSession.OnRecvAsyncCallback socket session {0} receive unkonw error, message {1}", SessionID, ex.Message); Close(); lock (m_recvAsyncLocker) { m_recvAsyncPending = false; } } } /// /// websocket有控制帧头,自己使用新的 /// protected void CopyWebSocketSendBuffer() { //只有buffer的数据全部发送完毕后才行 if (m_sendDataLeft > 0) { return; } if (m_sendMessageAsyncQueue.Count > 0) { lock (m_sendMessageAsyncQueueLocker) { while (m_sendMessageAsyncQueue.Count > 0) { MessageData message = m_sendMessageAsyncQueue.Dequeue(); //调用这个,大消息需要拆分下 //线程安全,也不会有顺序问题 SendMessageToQueue(message); } } } while (m_sendMessageQueue.Count > 0) { MessageData message = m_sendMessageQueue.Dequeue(); m_dataLengthInSendQueue -= message.Header.Length; int headerLength = m_protoPacker.PackHeader(message.Header, m_headerBytes); // 这里加webSocket控制帧的头 PacketFrameDataHeadToSendBuffer(FrameType.Binary, headerLength + message.Buffer.Length); Buffer.BlockCopy(m_headerBytes, 0, m_sendBuffer, m_sendDataLeft, headerLength); m_sendDataLeft += headerLength; Buffer.BlockCopy(message.Buffer.Data, 0, m_sendBuffer, m_sendDataLeft, message.Buffer.Length); m_sendDataLeft += message.Buffer.Length; message.FreeData(); //查看一下,下个消息长度能否copy成功,不行就跳出 if (m_sendMessageQueue.Count > 0) { message = m_sendMessageQueue.Peek(); if (m_sendDataLeft + message.Buffer.Length + 100 >= m_sendBuffer.Length) { break; } } } } /// /// 解包webSocket的控制帧头后,数据放到 m_RecvBuffer 中 /// /// /// protected void TryReadWebSocketMessageFromBuffer(bool threadSafe, bool raiseAsyncModeEvent) { if (!IsHandShake) { AnswerHandShake(); return; } // 这里解包并放到 m_RecvBuffer 中 UnPacketFrameDataToRecvBuffer(); // 解包控制帧可能会直接关闭socket if (IsSocketClosed) { return; } TryReadMessageFromBuffer(threadSafe, raiseAsyncModeEvent); } private void AnswerHandShake() { byte[] data = new byte[m_webAlreadyRecvLength]; Buffer.BlockCopy(m_webRecvBuffer, 0, data, 0, m_webAlreadyRecvLength); m_webAlreadyRecvLength = 0; WebSocketHttpRequest request = RequestParser.Parse(data, m_scheme); if (!IsValidWebSocketRequest(request)) { Close(); return; } lock (m_sendHandShakeLocker) { if (m_sendHandShakePending) { return; } m_sendHandShakePending = true; } if (request.Headers.ContainsKey("X-Forwarded-For")) { this.clientIp = request.Headers["X-Forwarded-For"]; } else { this.clientIp = RemoteEndPoint.ToString().Split(':')[0]; } string subProtocol = SubProtocolNegotiator.Negotiate(supportedSubProtocols, request.SubProtocols); var builder = new StringBuilder(); builder.Append("HTTP/1.1 101 Switching Protocols\r\n"); builder.Append("Upgrade: websocket\r\n"); builder.Append("Connection: Upgrade\r\n"); if (subProtocol != null) builder.AppendFormat("Sec-WebSocket-Protocol: {0}\r\n", subProtocol); var responseKey = CreateResponseKey(request["Sec-WebSocket-Key"]); builder.AppendFormat("Sec-WebSocket-Accept: {0}\r\n", responseKey); builder.Append("\r\n"); var handshake = Encoding.ASCII.GetBytes(builder.ToString()); // handshake 直接发送 Buffer.BlockCopy(handshake, 0, m_sendBuffer, m_sendDataLeft, handshake.Length); m_sendDataLeft += handshake.Length; StartSendAsync(); } public static string CreateResponseKey(string requestKey) { var combined = requestKey + WebSocketResponseGuid; var bytes = SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(combined)); return Convert.ToBase64String(bytes); } private bool IsValidWebSocketRequest(WebSocketHttpRequest request) { string version = HandlerFactory.GetVersion(request); if (version == "7" || version == "8" || version == "13") { return true; } return false; } /// /// 打包websocket数据帧到 m_sendBuffer /// /// /// /// /// /// /// private void PacketFrameDataHeadToSendBuffer(FrameType frameType, int length) { m_sendBuffer[m_sendDataLeft++] = (byte)((byte)frameType + 128); byte[] frameHeader; // todo XD 需要注意大小字节序 这里可以改成 BitConverter.TryWriteBytes,参考 PackHeader if (length > UInt16.MaxValue) { m_sendBuffer[m_sendDataLeft++] = (byte)127; frameHeader = BitConverter.GetBytes((ulong)length); if (BitConverter.IsLittleEndian) { Array.Reverse(frameHeader); } Buffer.BlockCopy(frameHeader, 0, m_sendBuffer, m_sendDataLeft, frameHeader.Length); m_sendDataLeft += frameHeader.Length; } else if (length > 125) { m_sendBuffer[m_sendDataLeft++] = (byte)126; frameHeader = BitConverter.GetBytes((ushort)length); if (BitConverter.IsLittleEndian) { Array.Reverse(frameHeader); } Buffer.BlockCopy(frameHeader, 0, m_sendBuffer, m_sendDataLeft, frameHeader.Length); m_sendDataLeft += frameHeader.Length; } else { m_sendBuffer[m_sendDataLeft++] = (byte)length; } } public void CheckSendCloseFrameTimeOut() { if (LastCloseWebSocketSecond > 0) { //2秒都没有成功关闭,直接强关了 if (AppTime.GetNowSysSecond() - LastCloseWebSocketSecond > 2) { Close(); } } } public void CloseWebSocket(int closeCode = WebSocketStatusCodes.NormalClosure) { // socket已关闭 if (IsSocketClosed) { return; } CheckSendCloseFrameTimeOut(); // checkTimeOut可能会关掉 if (IsSocketClosed) { return; } lock (m_sendCloseFrameLocker) { if (IsSendingClose) { return; } IsSendingClose = true; LastCloseWebSocketSecond = AppTime.GetNowSysSecond(); } byte[] closeBytes = BitConverter.GetBytes(closeCode); PacketFrameDataHeadToSendBuffer(FrameType.Close, closeBytes.Length); Buffer.BlockCopy(closeBytes, 0, m_sendBuffer, m_sendDataLeft, closeBytes.Length); m_sendDataLeft += closeBytes.Length; StartSendAsync(); } /// /// 从 m_webRecvBuffer 解控制帧头到 m_recvBuffer /// 同时需要判断帧类型,将不符合的丢弃 /// private void UnPacketFrameDataToRecvBuffer() { // websocket 单帧数据长度最小2 if (m_webAlreadyRecvLength < 2) { return; } int iBufferLeftLength = m_webAlreadyRecvLength; int iBufferStartPos = 0; while (iBufferLeftLength >= 2) { // 第128位判断是否最后一帧 bool isFinal = (m_webRecvBuffer[0] & 128) != 0; // 保留位,此位在 spec5.2中必须为0 int reservedBits = (m_webRecvBuffer[0] & 112); // 帧类型。 FrameType frameType = (FrameType)(m_webRecvBuffer[0] & 15); // websocket协议约定,客户端→服务端的帧必须用掩码处理 bool isMasked = (m_webRecvBuffer[1] & 128) != 0; // 长度控制位 int lengthCtrl = (m_webRecvBuffer[1] & 127); if (!isMasked || reservedBits != 0 //Must be zero per spec 5.2 || !Enum.IsDefined(typeof(FrameType), frameType) ) { Close(); return; } // 去掉控制帧头 iBufferStartPos += 2; iBufferLeftLength -= 2; // 获得数据长度 int realDataLength; if (lengthCtrl == 127) { if (iBufferLeftLength < 8) { // 长度不够,数据未完整 return; } if (BitConverter.IsLittleEndian) { Array.Reverse(m_webRecvBuffer, iBufferStartPos, 8); } realDataLength = (int)BitConverter.ToUInt64(m_webRecvBuffer, iBufferStartPos); iBufferLeftLength -= 8; iBufferStartPos += 8; } else if (lengthCtrl == 126) { if (iBufferLeftLength < 2) { // 长度不够,数据未完整 return; } if (BitConverter.IsLittleEndian) { Array.Reverse(m_webRecvBuffer, iBufferStartPos, 2); } realDataLength = (int)BitConverter.ToUInt16(m_webRecvBuffer, iBufferStartPos); iBufferLeftLength -= 2; iBufferStartPos += 2; } else { realDataLength = lengthCtrl; } // 获得掩码 if (iBufferLeftLength < 4) { // 长度不够,数据未完整 return; } Buffer.BlockCopy(m_webRecvBuffer, iBufferStartPos, m_maskBytes, 0, 4); iBufferLeftLength -= 4; iBufferStartPos += 4; if (iBufferLeftLength < realDataLength) { // 长度不够,数据未完整 return; } switch (frameType) { case FrameType.Binary: case FrameType.Continuation: // copy数据到m_recvBuffer Buffer.BlockCopy(m_webRecvBuffer, iBufferStartPos, m_recvBuffer, m_alreadyRecvLength, realDataLength); // 掩码处理数据 for (int i = 0, j = m_alreadyRecvLength; i < realDataLength; i++, j++) { m_recvBuffer[j] = (byte)(m_recvBuffer[j] ^ m_maskBytes[i % 4]); } m_alreadyRecvLength += realDataLength; // 整体前移动 iBufferStartPos += realDataLength; iBufferLeftLength -= realDataLength; Buffer.BlockCopy(m_webRecvBuffer, iBufferStartPos, m_webRecvBuffer, 0, iBufferLeftLength); iBufferStartPos = 0; m_webAlreadyRecvLength = iBufferLeftLength; break; case FrameType.Ping: case FrameType.Pong: case FrameType.Text: // 整体前移动 iBufferStartPos += realDataLength; iBufferLeftLength -= realDataLength; Buffer.BlockCopy(m_webRecvBuffer, iBufferStartPos, m_webRecvBuffer, 0, iBufferLeftLength); iBufferStartPos = 0; m_webAlreadyRecvLength = iBufferLeftLength; break; case FrameType.Close: // 收到关闭帧需要回个关闭帧然后关闭 CloseWebSocket(); break; default: // 按理说不该收到这些帧类型,打印一下关闭吧 TraceLog.Debug($"WebSesion recv other FrameType {frameType}"); CloseWebSocket(WebSocketStatusCodes.UnsupportedDataType); break; } } } } }