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.

441 lines
13 KiB

1 month ago
/*
Sog
2016 by zouwei
*/
using System;
using System.Net;
using System.Net.Sockets;
using System.Collections.Generic;
using System.Security.Cryptography;
namespace SogClient
{
/// <summary>
/// Client socket.
/// </summary>
public class WebClientSession : IMessageTransWeb, IDisposable
{
public WebSession m_webSession { get; private set; }
private ClientSessionSettings m_clientSettings;
protected ConnectedClientSessionUpdate m_sessionUpdate;
/// <summary>
/// connected.
/// </summary>
public bool IsConnected
{
get
{
if (m_isConnected == false)
{
return false;
}
//如果加密需要收到key
if (m_clientSettings.CryptoMessage && m_teaKey == null)
{
return false;
}
return true;
}
}
private bool m_isConnecting = false;
private bool m_isConnected;
static object m_rsaCrypto;
SogFastXTEAKey m_teaKey;
private ushort m_sendSeq;
/// <summary>
/// 接收到数据事件
/// </summary>
public event WebNetEventHandler DataReceived;
private void OnDataReceived(WebSessionEventArgs e)
{
TraceLog.Trace("webClientSession recv data, remote {0} SessionID {1} length {2}", e.Session.RemoteEndPoint, e.Session.SessionID, e.Message.Header.Length);
if (m_clientSettings.CryptoMessage)
{
if (e.Message.Header.Type == (int)SpecialMessageType.SessionKey)
{
OnSessionKeyReceive(e.Message);
return;
}
}
if (DataReceived != null)
{
DataReceived(this, e);
}
}
/// <summary>
/// 连接成功事件
/// </summary>
public event WebNetEventHandler Connected;
private void OnConnected(WebSessionEventArgs e)
{
TraceLog.Trace("WebClientSession connect {0} success", m_clientSettings.RemoteEndPoint);
//如果需要加密在收到key消息后connected
if (m_clientSettings.CryptoMessage)
{
TraceLog.Trace("WebClientSession need cryptomessage,so wait sessionkey message", m_clientSettings.RemoteEndPoint);
return;
}
}
/// <summary>
/// 连接失败事件
/// </summary>
public event WebNetEventHandler ConnectFail;
private void OnConnectFail(WebSessionEventArgs e)
{
TraceLog.Trace("WebClientSession connect {0} failed", m_clientSettings.RemoteEndPoint);
if (ConnectFail != null)
{
ConnectFail(this, e);
}
m_isConnected = false;
m_isConnecting = false;
CloseWebSocket();
}
/// <summary>
/// 连接断开事件
/// </summary>
public event WebNetEventHandler Disconnected;
private void OnDisconnected(WebSessionEventArgs e)
{
TraceLog.Trace("WebClientSession connection lost {0} ", m_clientSettings.RemoteEndPoint);
if (Disconnected != null)
{
Disconnected(this, e);
}
m_isConnected = false;
m_isConnecting = false;
CloseWebSocket();
}
private void CloseWebSocket()
{
//清空密钥,重新连接就需要重新请求密钥
m_teaKey = null;
m_sendSeq = 0;
TraceLog.Debug("CloseWebSocket 11111");
if (m_webSession != null)
{
try
{
m_webSession.Close();
}
catch (Exception e)
{
TraceLog.Trace("WebClientSession CloseSocket err {0} ", e);
}
finally
{
TraceLog.Debug("CloseWebSocket 222222222222222");
m_webSession = null;
}
}
}
/// <summary>
///
/// </summary>
/// <param name="clientSettings"></param>
/// <param name="requestHandler"></param>
public WebClientSession(ClientSessionSettings clientSettings, ConnectedClientSessionUpdate updateMgr)
{
this.m_clientSettings = clientSettings;
m_webSession = new WebSession(this.m_clientSettings);
Console.WriteLine("WebClientSession Init");
m_sessionUpdate = updateMgr;
}
/// <summary>
///
/// </summary>
public void Reconnect()
{
m_isConnected = false;
m_isConnecting = true;
//m_socketClient = new Socket(this.m_clientSettings.RemoteEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
//m_socketClient.Blocking = false;
Connect();
}
/// <summary>
/// Connect this instance.
/// </summary>
public void Connect()
{
TraceLog.Trace("clientsession begin connect");
m_sendSeq = 0;
m_isConnected = false;
try
{
m_isConnecting = true;
m_webSession.Connect();
}
catch (Exception ex)
{
//这个是正常的
TraceLog.Trace("connect to {0},wait connected finish SocketErrorCode err {1},", m_clientSettings.RemoteEndPoint, ex);
}
}
public void Update()
{
UpdateConnect();
UpdateReadWrite();
}
private void UpdateConnect()
{
if (m_webSession == null)
{
return;
}
if (m_isConnecting)
{
if (m_webSession.IsError)
{
WebSessionEventArgs e = new WebSessionEventArgs();
e.Session = m_webSession;
OnConnectFail(e);
}
else if (m_webSession.IsConnected)
{
ConnectComplated();
}
}
if (m_isConnected)
{
if (m_webSession.IsClosed)
{
WebSessionEventArgs e = new WebSessionEventArgs();
e.Session = m_webSession;
OnDisconnected(e);
return;
}
else if (m_webSession.IsError)
{
WebSessionEventArgs e = new WebSessionEventArgs();
e.Session = m_webSession;
OnDisconnected(e);
return;
}
}
}
protected void UpdateReadWrite()
{
if (m_webSession == null)
{
return;
}
if (m_isConnected)
{
m_sessionUpdate.AddWebSessionToList(this);
}
}
private void ConnectComplated()
{
TraceLog.Trace("ClientSession.ConnectComplated");
m_isConnected = true;
m_isConnecting = false;
WebSessionEventArgs e = new WebSessionEventArgs();
e.Session = m_webSession;
SendPublicKeyToRemote();
OnConnected(e);
}
private void SendPublicKeyToRemote()
{
TraceLog.Trace("clientsession SendPublicKeyToRemote");
if (m_rsaCrypto == null)
{
m_rsaCrypto = new object();
RSABigIntegerUtils.GenRSAKey();
TraceLog.Trace("clientsession RSABigIntegerUtils.GenRSAKey");
}
//清空一下,保证逻辑
m_teaKey = null;
MessageData message = new MessageData();
message.Data = null;
message.Header.Type = (int)SpecialMessageType.PublicKey;
if (m_clientSettings.CryptoMessage)
{
RSAParameters rp = RSABigIntegerUtils.GetRSAParameters();
byte[] data = new byte[2 + rp.Modulus.Length + rp.Exponent.Length];
//string modulus = Convert.ToBase64String(rp.Modulus);
//string exp = Convert.ToBase64String(rp.Exponent);
byte[] modLenByte = BitConverter.GetBytes((Int16)rp.Modulus.Length);
Buffer.BlockCopy(modLenByte, 0, data, 0, 2);
Buffer.BlockCopy(rp.Modulus, 0, data, 2, rp.Modulus.Length);
Buffer.BlockCopy(rp.Exponent, 0, data, 2 + rp.Modulus.Length, rp.Exponent.Length);
message.Data = data;
message.Header.Length = data.Length;
}
else
{
byte[] data = BitConverter.GetBytes((Int16)6666);
message.Data = data;
message.Header.Length = data.Length;
}
Send(message);
}
private void OnSessionKeyReceive(MessageData message)
{
TraceLog.Trace("clientsession OnSessionKeyReceive");
if (m_rsaCrypto == null)
{
return;
}
byte[] keyBytes = RSABigIntegerUtils.DecryptBytesPrivite(message.Data);
m_teaKey = new SogFastXTEAKey(keyBytes);
if (Connected != null)
{
WebSessionEventArgs e = new WebSessionEventArgs();
e.Session = m_webSession;
Connected(this, e);
}
}
public override void Send(WebSession webSession, MessageData message)
{
if (m_teaKey != null && message.Data != null && message.Data.Length > 0)
{
SogFastXTEA.Encrypt(message.Data, m_teaKey);
}
m_sendSeq++;
ushort crcValue = 0;
if (message.Data != null && message.Data.Length > 0)
{
crcValue = CRC.CRC16(message.Data, message.Data.Length);
}
message.Header.ServerID = ((uint)m_sendSeq << 16) + crcValue;
webSession.SendMessageToQueue(message);
}
public void Send(MessageData message)
{
if (m_teaKey != null && message.Data != null && message.Data.Length > 0)
{
SogFastXTEA.Encrypt(message.Data, m_teaKey);
}
m_sendSeq++;
ushort crcValue = 0;
if (message.Data != null && message.Data.Length > 0)
{
crcValue = CRC.CRC16(message.Data, message.Data.Length);
}
message.Header.ServerID = ((uint)m_sendSeq << 16) + crcValue;
m_webSession.SendMessageToQueue(message);
}
public void ReceiveMessage()
{
Queue<MessageData> dataList = m_webSession.GetReceivedDataQueue();
TraceLog.Debug($"ReceiveMessage 111111111111 {dataList.Count}");
for (int i = 0; i < dataList.Count; i++)
{
MessageData message = dataList.Dequeue();
//加密的消息需要解密
if (m_clientSettings.CryptoMessage
&& m_teaKey != null
&& message.Data != null
&& message.Data.Length > 0)
{
try
{
SogFastXTEA.Decrypt(message.Data, m_teaKey);
}
catch (Exception ex)
{
//解密失败
TraceLog.Exception(ex);
continue;
}
}
try
{
WebSessionEventArgs e = new WebSessionEventArgs();
e.Message = message;
e.Session = m_webSession;
OnDataReceived(e);
}
catch (Exception ex)
{
// 接收协议失败
TraceLog.Exception(ex);
continue;
}
}
TraceLog.Debug($"ReceiveMessage 555555555555 {dataList.Count}");
}
public void OnUpdateConnectedSocketError()
{
TraceLog.Trace("ClientSession.OnUpdateConnectedSocketError close session");
WebSessionEventArgs e = new WebSessionEventArgs();
e.Session = m_webSession;
OnDisconnected(e);
Close();
}
/// <summary>
///
/// </summary>
/// <param name="reason"></param>
public void Close(string reason = "")
{
//After receiving data processing close
m_isConnected = false;
CloseWebSocket();
}
/// <summary>
///
/// </summary>
public void Dispose()
{
Close();
}
}
}