using System; using System.Collections.Generic; using System.Net; using System.Security.Cryptography; using System.Net.Security; using System.Net.WebSockets; using System.Runtime.InteropServices; using System.Net.Http; using System.Threading; using System.Threading.Tasks; using System.Text; namespace SogClient { public class WebSession { const int BUFFER_LENGTH_MAX = 1024 * 1024 * 100; private ClientSessionSettings m_clientSettings; private ClientWebSocket m_webSocket; internal DateTime LastDataTime; private byte[] m_recvBuffer = new byte[1024 * 64]; private int m_alreadyRecvLength = 0; private int m_messageLength = 0; private Queue m_recvBigDataMessageQueue = new Queue(); private Queue m_recvMessageQueue = new Queue(); private Queue m_sendMessageQueue = new Queue(); private int m_dataLengthInSendQueue = 0; private byte[] m_sendBuffer = new byte[1024 * 64]; private int m_sendDataLeft = 0; private object m_sendLock = new object(); private bool m_sendPending = false; private byte[] m_headerBytes; //消息头的长度 private int m_messageHeaderLength; private IProtoPacker m_protoPacker; private string m_uri; public long SessionID { get; private set; } public bool IsConnected { get; private set; } public bool IsConnecting { get; private set; } public bool IsError { get; private set; } public bool IsClosed { get; private set; } public bool IsClosing { get; private set; } public IPEndPoint RemoteEndPoint => m_clientSettings.RemoteEndPoint; /// /// /// Socket. public WebSession(ClientSessionSettings clientSettings) { m_clientSettings = clientSettings; string uri = $"ws://{clientSettings.RemoteEndPoint.Address}:{clientSettings.RemoteEndPoint.Port}/"; m_uri = uri; Console.WriteLine($"Connect:{uri}"); ClientWebSocket webSocketClient = new ClientWebSocket(); webSocketClient.Options.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; m_protoPacker = ProtoPackerFactory.Instance.GetProtoPacker(); m_messageHeaderLength = m_protoPacker.GetHeaderLength(); m_headerBytes = new byte[m_protoPacker.GetHeaderLength()]; this.m_webSocket = webSocketClient; } public void ResetSessionID(long sesssionID) { SessionID = sesssionID; } public void Dispose() { Console.WriteLine($"Connect:{SessionID} Dispose"); if (m_webSocket != null) { m_webSocket.Dispose(); m_webSocket = null; } m_clientSettings = null; } private void OnOpen() { IsConnected = true; } private void OnError(Exception e) { TraceLog.Debug($"WebSocketClientSession OnError {e}"); IsError = true; } private void OnClose() { TraceLog.Debug($"WebSocketClientSession OnClose"); IsClosed = true; } public async Task Close() { // 直接丢弃所有数据 m_alreadyRecvLength = 0; if (m_webSocket == null) { return; } if (IsClosed || IsClosing) { return; } IsConnected = false; IsClosing = true; try { await m_webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None); OnClose(); } catch (Exception e) { TraceLog.Write("WebSocket netsession Close err, message {0} ", e); } finally { TraceLog.Write("WebSocket netsession Close message {0} "); m_webSocket = null; } } public async void Connect() { if (m_webSocket == null) { return; } if (IsConnected || IsConnecting) { TraceLog.WriteError($"repeated connect websocket"); return; } TraceLog.Debug($"WebSocket connect {m_uri}"); IsConnecting = true; try { await m_webSocket.ConnectAsync(new Uri(m_uri), CancellationToken.None); OnOpen(); await Receive(); } catch (Exception ex) { OnError(ex); TraceLog.Error($"WebSocketSession Connected err! message:{ex}"); } finally { if (m_webSocket != null && m_webSocket.State == WebSocketState.Open) { await m_webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None); OnClose(); } } } private async Task Receive() { while (true) { var result = await m_webSocket.ReceiveAsync(new ArraySegment(m_recvBuffer, m_alreadyRecvLength, m_recvBuffer.Length-m_alreadyRecvLength), CancellationToken.None); if (result.MessageType == WebSocketMessageType.Binary) { m_alreadyRecvLength += result.Count; TryReadMessageFromBuffer(); } else if (result.MessageType == WebSocketMessageType.Close) { OnClose(); break; } } } public void TryReadMessageFromBuffer() { if (m_alreadyRecvLength < m_messageHeaderLength) { return; } int iBufferLeftLength = m_alreadyRecvLength; int iBufferStartPos = 0; TraceLog.Debug($"WebSocket TryReadMessageFromBuffer111 :{m_recvMessageQueue.Count} {m_alreadyRecvLength}"); while (iBufferLeftLength >= m_messageHeaderLength) { MessageHeader header; header.Type = 0; header.Length = 0; header.ObjectID = 0; header.ServerID = 0; m_messageLength = m_protoPacker.UnPackHeader(m_recvBuffer, iBufferStartPos, iBufferLeftLength, ref header); m_messageLength = header.Length; //判断是否合法 if (m_messageLength < 0 || m_messageLength > 64 * 1024 - 24) { //主动断线 TraceLog.WriteError("websocket recv a invalid length {0} packet,close session {1}, remote {2}", m_messageLength, SessionID, RemoteEndPoint); Close(); return; } //有完整的消息了 if (m_messageLength + m_messageHeaderLength <= iBufferLeftLength) { if (m_messageLength >= 0 && header.Type > 0) { byte[] data = new byte[m_messageLength]; Buffer.BlockCopy(m_recvBuffer, iBufferStartPos + m_messageHeaderLength, data, 0, m_messageLength); MessageData message = new MessageData(); message.Data = data; message.Header = header; if (header.Type == (int)SpecialMessageType.BigMessageStart || header.Type == (int)SpecialMessageType.BigMessageTrans) { TraceLog.Debug($"WebSocket TryReadMessageFromBuffer222 bigmessage:{m_messageLength} {m_messageHeaderLength} {iBufferLeftLength}"); m_recvBigDataMessageQueue.Enqueue(message); BigDataMessage.TryGetFullBigDataMessage(m_recvBigDataMessageQueue, m_recvMessageQueue); } else { m_recvMessageQueue.Enqueue(message); } } iBufferStartPos += m_messageLength + m_messageHeaderLength; iBufferLeftLength -= m_messageLength + m_messageHeaderLength; } else { break; } } if (iBufferLeftLength > 0 && iBufferStartPos > 0) { //剩下的内容向前移动 Buffer.BlockCopy(m_recvBuffer, iBufferStartPos, m_recvBuffer, 0, iBufferLeftLength); } m_alreadyRecvLength = iBufferLeftLength; TraceLog.Debug($"WebSocket TryReadMessageFromBuffer333 {m_recvMessageQueue.Count} {m_alreadyRecvLength}"); } public bool IsHaveDataRead() { return m_recvMessageQueue.Count > 0; } public Queue GetReceivedDataQueue() { return m_recvMessageQueue; } public bool IsFull() { return m_dataLengthInSendQueue >= BUFFER_LENGTH_MAX; } public void SendMessageToQueue(MessageData message) { TraceLog.Debug($"WebSocket SendMessageToQueue 11111 {m_sendMessageQueue.Count} {message.Header.Type}"); if (IsFull()) { TraceLog.WriteError("websocket send buff full drop msg type {0}, length {1} remote {2}", message.Header.Type, message.Header.Length, RemoteEndPoint.ToString()); return; } m_sendMessageQueue.Enqueue(message); m_dataLengthInSendQueue += message.Header.Length; } public async Task RealSendAsync() { if (m_webSocket == null) { return; } if (!IsConnected) { return; } if (m_sendDataLeft <= 0) { return; } if (m_webSocket.State != WebSocketState.Open) { return; } lock(m_sendLock){ if (m_sendPending) { return; } m_sendPending = true; } try { TraceLog.Debug($"WebSocket RealSendAsync 111111 {m_sendDataLeft} {m_sendMessageQueue.Count}"); await m_webSocket.SendAsync(new ArraySegment(m_sendBuffer, 0, m_sendDataLeft), WebSocketMessageType.Binary, true, CancellationToken.None); OnSendCallBack(); TraceLog.Debug($"WebSocket RealSendAsync 22222 {m_sendDataLeft} {m_sendMessageQueue.Count}"); } catch (Exception ex) { TraceLog.WriteError($"WebSocket RealSendAsync err SessionID:{SessionID} errmessage:{ex}"); } } private void OnSendCallBack() { lock (m_sendLock) { if (m_sendPending == false) { return; } m_sendPending = false; m_sendDataLeft = 0; } } public bool IsHaveDataSend() { if (m_webSocket == null) { return false; } if (m_sendMessageQueue.Count > 0) { return true; } return m_sendDataLeft > 0; } public void TryCopySendBuffer() { //只有buffer的数据全部发送完毕后才行 if (m_sendDataLeft > 0) { RealSendAsync(); return; } while (m_sendMessageQueue.Count > 0) { MessageData message = m_sendMessageQueue.Dequeue(); m_dataLengthInSendQueue -= message.Header.Length; int headerLength = m_protoPacker.PackHeader(message.Header, m_headerBytes); Buffer.BlockCopy(m_headerBytes, 0, m_sendBuffer, m_sendDataLeft, m_messageHeaderLength); m_sendDataLeft += m_messageHeaderLength; Buffer.BlockCopy(message.Data, 0, m_sendBuffer, m_sendDataLeft, message.Data.Length); m_sendDataLeft += message.Data.Length; //查看一下,下个消息长度能否copy成功,不行就跳出 if (m_sendMessageQueue.Count > 0) { message = m_sendMessageQueue.Peek(); if (m_sendDataLeft + message.Data.Length + m_messageHeaderLength >= m_sendBuffer.Length) { break; } } } } } }