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.
440 lines
13 KiB
440 lines
13 KiB
/*
|
|
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();
|
|
}
|
|
}
|
|
}
|
|
|