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.
294 lines
9.7 KiB
294 lines
9.7 KiB
/*
|
|
Sog 游戏基础库
|
|
2016 by zouwei
|
|
*/
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using System.Net;
|
|
using System.Net.Sockets;
|
|
|
|
namespace Sog
|
|
{
|
|
public class ClusterChannel
|
|
{
|
|
public const int BufferSize = 655360;
|
|
|
|
public uint LocalAppID { get; private set; }
|
|
public uint RemoteAppID { get; private set; }
|
|
|
|
public string LocalAppIDStr { get; private set; }
|
|
public string RemoteAppIDStr { get; private set; }
|
|
|
|
//我是不是客户端方,是的话就要主动发起连接请求,不是的话则等待对方主动连接我
|
|
public bool IsClient { get; private set; }
|
|
//是否已经开始连接
|
|
public bool IsStartConnecting { get; private set; }
|
|
public NetSession ConnectedSession { get; private set; }
|
|
|
|
private ClientSessionSettings m_clientSessionSettings;
|
|
private ClientSession m_clientSession;
|
|
private long m_disConnectTime = 0;
|
|
private bool m_bNeedReconnect = false;
|
|
|
|
private long m_iSendMessageCount = 0;
|
|
//测试断线重连逻辑,用来主动断线用,应该关闭
|
|
private bool m_testReconnect = false;
|
|
|
|
private Queue<MessageData> m_recvivedMessage = new Queue<MessageData>();
|
|
private object m_recvlocker = new object();
|
|
private object m_sendlocker = new object();
|
|
|
|
//cluster网络处理模式
|
|
private SessionNetSelectMode NetSelectMode;
|
|
|
|
//缺省不支持多线程send,这个只在同步模式起作用
|
|
public bool MultiThreadSendSafe = false;
|
|
|
|
//我连他人
|
|
public delegate void OnIToItConnectOrDisConnectHandler(uint serverID, bool isConnect);
|
|
public OnIToItConnectOrDisConnectHandler OnIToItConnectOrDisConnect;
|
|
|
|
public ClusterChannel(uint localAppID,uint remoteAppID,bool isClinet, SessionNetSelectMode netMode)
|
|
{
|
|
LocalAppID = localAppID;
|
|
RemoteAppID = remoteAppID;
|
|
IsClient = isClinet;
|
|
IsStartConnecting = false;
|
|
|
|
LocalAppIDStr = ServerIDUtils.IDToString(localAppID);
|
|
RemoteAppIDStr = ServerIDUtils.IDToString(remoteAppID);
|
|
|
|
NetSelectMode = netMode;
|
|
}
|
|
|
|
public void StartConnect(ClusterApp thisApp,ClusterApp remoteApp)
|
|
{
|
|
IPEndPoint remoteIPEndPoint = ClusterApp.GetRemoteIpEndPoint(thisApp, remoteApp);
|
|
|
|
TraceLog.Trace("ClusterChannel.StartConnect remote {0}, my idc {1} remote idc {2} remote listenAnyIP {3}",
|
|
remoteIPEndPoint, thisApp.idc, remoteApp.idc, remoteApp.listenAnyIP);
|
|
|
|
IsStartConnecting = true;
|
|
|
|
if (m_clientSessionSettings == null)
|
|
{
|
|
m_clientSessionSettings = new ClientSessionSettings(remoteApp.BufferSize, remoteIPEndPoint, ProtocolType.Tcp);
|
|
}
|
|
|
|
if (m_clientSession == null)
|
|
{
|
|
m_clientSession = new TcpClientSession(m_clientSessionSettings, NetSelectMode);
|
|
|
|
m_clientSession.Connected += socket_OnConnected;
|
|
m_clientSession.ConnectFail += socket_OnConnectFail;
|
|
m_clientSession.Disconnected += socket_OnDisconnected;
|
|
m_clientSession.DataReceived += OnRecvDataFromSocket;
|
|
}
|
|
|
|
m_clientSession.Connect();
|
|
}
|
|
|
|
//关闭连接和清空资源
|
|
public void CloseConnect()
|
|
{
|
|
if (m_clientSession != null)
|
|
{
|
|
m_clientSession.Dispose();
|
|
m_clientSessionSettings = null;
|
|
m_clientSession = null;
|
|
m_recvivedMessage.Clear();
|
|
}
|
|
}
|
|
|
|
private void socket_OnConnected(object clientSocket,SessionEventArgs e)
|
|
{
|
|
TraceLog.Trace("ClusterChannel.socket_OnConnected remote {0}", m_clientSessionSettings.RemoteEndPoint);
|
|
|
|
//设置缓冲大小
|
|
m_clientSession.NetSessionObj.SetSocketBufferSize(BufferSize);
|
|
|
|
ConnectedSession = m_clientSession.NetSessionObj;
|
|
|
|
ConnectedSession.WriteSendRecvLog = true;
|
|
|
|
MessageData message = new MessageData();
|
|
message.Header.Length = 0;
|
|
message.Header.Type = (int)SpecialMessageType.ClusterClientRegister;
|
|
message.Header.ObjectID = 0;
|
|
message.Header.ServerID = LocalAppID;
|
|
|
|
m_clientSession.DirectSendNoQueue(message);
|
|
|
|
if(NetSelectMode == SessionNetSelectMode.Asynchronous)
|
|
{
|
|
ConnectedSession.StartRecvAsync();
|
|
ConnectedSession.StartSendAsync();
|
|
}
|
|
OnIToItConnectOrDisConnect?.Invoke(RemoteAppID, true);
|
|
}
|
|
|
|
private void socket_OnConnectFail(object clientSocket, SessionEventArgs e)
|
|
{
|
|
m_bNeedReconnect = true;
|
|
m_disConnectTime = AppTime.GetNowSysMs();
|
|
|
|
TraceLog.Trace("ClusterChannel.socket_OnConnectFail at MsTime {0}", m_disConnectTime);
|
|
OnIToItConnectOrDisConnect?.Invoke(RemoteAppID, false);
|
|
}
|
|
|
|
private void socket_OnDisconnected(object clientSocket, SessionEventArgs e)
|
|
{
|
|
//重连
|
|
ConnectedSession = null;
|
|
m_bNeedReconnect = true;
|
|
m_disConnectTime = AppTime.GetNowSysMs();
|
|
|
|
TraceLog.Trace("ClusterChannel.socket_OnDisconnected at MsTime {0}", m_disConnectTime);
|
|
OnIToItConnectOrDisConnect?.Invoke(RemoteAppID, false);
|
|
}
|
|
|
|
public void OnRecvDataFromSocket(object clientSocket, SessionEventArgs e)
|
|
{
|
|
if (NetSelectMode == SessionNetSelectMode.Synchronous)
|
|
{
|
|
m_recvivedMessage.Enqueue(e.Message);
|
|
}
|
|
else
|
|
{
|
|
lock (m_recvlocker)
|
|
{
|
|
m_recvivedMessage.Enqueue(e.Message);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public void BindSocket(NetSession socket)
|
|
{
|
|
//原来的存在
|
|
if(ConnectedSession != null && ConnectedSession.IsSocketClosed == false)
|
|
{
|
|
TraceLog.Trace("ClusterChannel.BindSocket close exist session {0}", ConnectedSession.SessionID);
|
|
ConnectedSession.Close();
|
|
}
|
|
|
|
TraceLog.Trace("ClusterChannel.BindSocket new session {0}", socket.SessionID);
|
|
ConnectedSession = socket;
|
|
}
|
|
|
|
public void UnBindSocket()
|
|
{
|
|
ConnectedSession = null;
|
|
}
|
|
|
|
|
|
public void Update(long nowMs)
|
|
{
|
|
if (m_clientSession != null)
|
|
{
|
|
m_clientSession.Update(nowMs);
|
|
|
|
//重连
|
|
if (m_bNeedReconnect)
|
|
{
|
|
//一秒最多重连一次,linux下太快
|
|
if (AppTime.GetNowSysMs() - m_disConnectTime >= 2000)
|
|
{
|
|
TraceLog.Debug("ClusterChannel.Update NowMsTime {0} disConnectTime {1}", nowMs, m_disConnectTime);
|
|
|
|
//这个m_bNeedReconnect要放在Reconnect之前,因为有可能connect立即返回结果或者结果非常快回调,快到这里reconnect没结束,
|
|
//调用socket_OnConnectFail,这时m_bNeedReconnect变成true后在Reconnect结束后又变成false会出错,不会再重连了
|
|
m_bNeedReconnect = false;
|
|
m_clientSession.Reconnect();
|
|
//以下是测试代码
|
|
//System.Threading.Thread.Sleep(500);
|
|
//m_bNeedReconnect = false;
|
|
//TraceLog.Debug("ClusterChannel.Update Reconnect call finish,wait long time, now {0}",DateTime.Now);
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public void Send(MessageData message)
|
|
{
|
|
if (ConnectedSession == null)
|
|
{
|
|
TraceLog.Debug("ClusterChannel.Send no ConnectedSession type {0}", message.Header.Type);
|
|
return;
|
|
}
|
|
|
|
|
|
if (NetSelectMode == SessionNetSelectMode.Synchronous)
|
|
{
|
|
if(MultiThreadSendSafe)
|
|
{
|
|
lock(m_sendlocker)
|
|
{
|
|
ConnectedSession.SendMessageToAsyncQueue(message);
|
|
m_iSendMessageCount++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ConnectedSession.SendMessageToQueue(message);
|
|
|
|
m_iSendMessageCount++;
|
|
}
|
|
|
|
|
|
//测试断线重连逻辑,主动断线
|
|
if (m_testReconnect)
|
|
{
|
|
if (m_clientSession != null && IsClient && (m_iSendMessageCount % 1000) == 0)
|
|
{
|
|
TraceLog.Debug("ClusterChannel.Send m_iSendMessageCount {0} close socket", m_iSendMessageCount);
|
|
|
|
m_clientSession.Close();
|
|
|
|
ConnectedSession = null;
|
|
m_bNeedReconnect = true;
|
|
m_disConnectTime = AppTime.GetNowSysMs();
|
|
}
|
|
}
|
|
}
|
|
else if(NetSelectMode == SessionNetSelectMode.Asynchronous)
|
|
{
|
|
ConnectedSession.StartSendAsyncMessage(message);
|
|
m_iSendMessageCount++;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public MessageData RecvOneFromQueue()
|
|
{
|
|
if (m_recvivedMessage.Count <= 0)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
if (NetSelectMode == SessionNetSelectMode.Synchronous)
|
|
{
|
|
MessageData message = m_recvivedMessage.Dequeue();
|
|
|
|
return message;
|
|
}
|
|
else
|
|
{
|
|
lock (m_recvlocker)
|
|
{
|
|
MessageData message = m_recvivedMessage.Dequeue();
|
|
|
|
return message;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|