/// <summary> /// 启动服务器,会开启工作线程然后释放一个DoStart信号量。 /// </summary> /// <param name="port">端口号</param> /// <param name="threadCount">服务器使用的处理线程数量</param> /// <param name="hostName">服务器的主机IP,一般使用Any表示所有的可能IP</param> public void Start(int port, int threadCount = 1, string hostName = "Any") { try { DxDebug.LogConsole("DNServer.Start():服务器工作线程数 " + threadCount); if (disposed) { TokenManager.GetInst().Clear(); _msgQueue = new DQueue <NetWorkMsg>(MSG_QUEUE_CAPACITY); _msgSemaphore = new Semaphore(0, MSG_QUEUE_CAPACITY); _workThread = new Thread[threadCount]; for (int i = 0; i < threadCount; i++) { _workThread[i] = new Thread(DoWork); _workThread[i].IsBackground = true; //工作线程的优先级(影响不大) _workThread[i].Priority = ThreadPriority.Highest; _workThread[i].Name = "SeverThread " + i; _workThread[i].Start(); //启动线程 } disposed = false; } _port = port; NetWorkMsg msg = new NetWorkMsg(NetWorkMsg.Tpye.S_Start, null); msg.text1 = hostName; AddMessage(msg); } catch (Exception e) { DxDebug.LogError("DNServer.Start():异常 " + e.Message); } }
/// <summary> /// 添加一个工作任务到消息队列,提供给这些线程来处理 /// </summary> /// <param name="msg"></param> public void AddMessage(IWorkMsg msg) { try { if (_msgQueue.EnqueueMaxLimit(msg)) { if (_curSemCount < 1)//如果当前的信号量剩余不多的时候 { Interlocked.Increment(ref _curSemCount); _msgSemaphore.Release();// 释放信号量 } } else { DxDebug.LogWarning("WorkThread.AddMessage():大于工作线程的能力了,丢弃了一条消息!"); } if (_msgQueuePeakLength < _msgQueue.Count) { _msgQueuePeakLength = _msgQueue.Count;//记录当前的峰值长度 } } catch (SemaphoreFullException) { DxDebug.LogError("WorkThread.AddMessage():大于工作线程的能力了:"); throw; } catch (Exception e) { DxDebug.LogError("WorkThread.AddMessage():异常:" + e.Message); throw; } }
private void DoConnect() { try { //DxDebug.LogConsole("DNClient.DoConnect():执行Connect..."); //标记正在连接 IsConnecting = true; Interlocked.Exchange(ref _snedingCount, 0); this.Clear();//清空数据 if (_socketClient != null) { //DxDebug.LogConsole("DNClient.DoConnect():断开原先连接!"); _socketClient.Disconnect(); _socketClient.Bind(_host, _port);//绑定新ip _socketClient.Clear(); DxDebug.LogConsole("DNClient.DoConnect():-----------正在连接..."); _socketClient.Connect(); DxDebug.LogConsole("DNClient.DoConnect():-----------连接服务器成功!" + _host + ":" + _port); } else { _socketClient = new SocketClient(_host, _port, _packet2); if (_socketClient == null) { DxDebug.LogError("DNClient.DoConnect():-----------连接服务器失败!_socketClient对象未能创建成功。"); return; } _socketClient.EventReceive += OnReceive; //加入接收事件 _socketClient.EventSend += OnSend; //加入发送事件 _socketClient.EventError += OnError; //加入错误事件 DxDebug.LogConsole("DNClient.DoConnect():-----------正在连接..."); _socketClient.Connect(); DxDebug.LogConsole("DNClient.DoConnect():-----------连接服务器成功!" + _host + ":" + _port); } if (EventConnectSuccess != null) { try { EventConnectSuccess(this); }//事件类型:ConnectError catch (Exception e) { DxDebug.LogError("DNClient.DoConnect():执行EventError事件异常:" + e.Message); } } } catch (Exception e) { DxDebug.LogError("DNClient.DoConnect():-----------连接服务器失败!: " + e.Message); if (EventError != null) { try { EventError(this, EventType.ConnectError, e); }//事件类型:ConnectError catch (Exception e2) { DxDebug.LogError("DNClient.DoConnect():执行EventError事件异常:" + e2.Message); } } } //标记已经结束了连接 IsConnecting = false; }
/// <summary> /// 连接服务器,输入IP和端口号。会强制重新初始化整个类,这样起到底层重启的作用。 /// </summary> /// <param name="host">主机IP</param> /// <param name="port">端口号</param> public void Connect(string host, int port) { try { DxDebug.LogConsole("DNClient.Connect():连接服务器 主机:" + host + " 端口:" + port); //标记正在连接 IsConnecting = true; //if (_disposed) //{ // DxDebug.LogConsole("DNClient.Connect():这个类对象是被释放状态,重新初始化"); Init(); //} //进行一次连接的时候,把消息队列清空 Clear(); Interlocked.Exchange(ref this._host, host); //给类成员赋值 Interlocked.Exchange(ref this._port, port); //给类成员赋值 NetWorkMsg msg = _msgPool.Dequeue(); if (msg == null) { msg = new NetWorkMsg(NetWorkMsg.Tpye.C_Connect); } else { msg.Reset(NetWorkMsg.Tpye.C_Connect); } AddMessage(msg); LastMsgReceTickTime = DateTime.Now.Ticks; LastMsgSendTickTime = DateTime.Now.Ticks; } catch (Exception e) { IsConnecting = false;//连接失败了 DxDebug.LogError("DNClient.Connect():异常:" + e.Message); if (EventError != null) { try { EventError(this, EventType.ConnectError, e);//事件类型:ConnectError } catch (Exception e2) { DxDebug.LogWarning("DNClient.Connect():执行EventError事件异常:" + e2.Message); } } Dispose();//释放 } }
/// <summary> /// 线程的工作函数 /// </summary> private void DoWork() { DxDebug.LogConsole("WorkThread.DoWork():工作线程启动!"); while (_isRun) { IWorkMsg msg = null; try { //记录线程空闲 RecThreadStatus(Thread.CurrentThread.ManagedThreadId, false); _msgSemaphore.WaitOne(); Interlocked.Decrement(ref _curSemCount); //记录线程开始工作 RecThreadStatus(Thread.CurrentThread.ManagedThreadId, true); while (true) { msg = _msgQueue.Dequeue(); if (msg != null) { //递增计数 Interlocked.Increment(ref _procMsgCount); try { //取一条消息进行执行 msg.DoWork(); } catch (Exception e) { DxDebug.LogWarning("WorkThread.DoWork():执行msg异常:" + msg.Name + "异常信息:" + e.Message); } } else { break; } } } catch (Exception e) { if (msg != null) { DxDebug.LogError("WorkThread.DoWork():异常:" + msg.Name + "异常信息:" + e.Message); } else { DxDebug.LogError("WorkThread.DoWork():异常:目前IWorkMsg为null(可能空闲),异常信息:" + e.Message); } } } }
/// <summary> /// 工作线程启动 /// </summary> public void Start() { try { //标记线程可以运行 _isRun = true; if (_disposed) { //标记自己已经有了资源申请 _disposed = false; try { DxDebug.LogConsole("WorkThread.Start():这个类对象经被释放或刚刚构造,重新初始化"); _msgQueue = new DQueue <IWorkMsg>(MSG_QUEUE_CAPACITY, _initMsgQueueSize); _msgSemaphore = new Semaphore(0, 64);//由于AddMessage的改动,这里只需要是随便一个数既可 _isWorking = new bool[_threadCount]; _lastWorkTime = new long[_threadCount]; _workThreadID = new int[_threadCount]; _workThread = new Thread[_threadCount]; for (int i = 0; i < _threadCount; i++) { _workThread[i] = new Thread(DoWork); _workThread[i].IsBackground = true; //工作线程的优先级(影响不大) _workThread[i].Priority = ThreadPriority.Highest; _workThread[i].Name = name + i; //记录线程ID _workThreadID[i] = _workThread[i].ManagedThreadId; _workThread[i].Start(); //启动线程 } } catch (Exception e) { DxDebug.LogError("WorkThread.Start():构造失败!异常:" + e.Message); Dispose(); } } else { Dispose(); Start(); } } catch (Exception e) { DxDebug.LogError("WorkThread.Start():异常:" + e.Message); } }
/// <summary> /// 设置工作目录路径,如果传入空则表示工作路径为当前程序运行路径.通常来说在运行之前都应该指定一个目录 /// </summary> public bool SetDirCache(string dir) { try { DxDebug.LogConsole("DNServer.SetDirCache():尝试设置工作文件夹路径 dir = " + dir); if (String.IsNullOrEmpty(dir)) { dirCache = Directory.GetCurrentDirectory(); DxDebug.LogConsole("DNServer.SetDirCache():输入路径为空,所以设置文件夹为" + dirCache); } else { dirCache = dir; //赋值 } if (!Directory.Exists(dirCache)) //如果这个目录不存在,那么就尝试创建一下这个目录 { DxDebug.LogConsole("DNServer.SetDirCache():文件夹不存在,创建文件夹..."); Directory.CreateDirectory(dirCache); } string testfile = System.IO.Path.Combine(dirCache, "dirtestFile_"); DxDebug.LogConsole("DNServer.SetDirCache():进行文件读写测试..."); FileStream fs = File.Create(testfile); //创建一下试试 fs.WriteByte(0xff); fs.Flush(); fs.Close(); fs = File.Open(testfile, FileMode.Open); if (fs.ReadByte() != 0xff) { dirCache = null; return(false); } fs.Close(); File.Delete(testfile); DxDebug.LogConsole("DNClient.SetDirCache():进行文件读写测试成功"); return(true);//如果允许到这里都没有错误,那么说明这个目录可以正常使用 } catch (Exception e) { DxDebug.LogError("DNServer.SetDirCache():设置工作文件夹失败! " + e.Message); } dirCache = null; return(false); }
/// <summary> /// 加入一条要执行的消息,如果加入的过快而无法发送,则将产生信号量溢出异常,表明当前发送数据频率要大于系统能力 /// </summary> /// <param name="msg"></param> internal void AddMessage(NetWorkMsg msg) { try { if (msg != null) { _msgQueue.Enqueue(msg); } if (_curSemCount < 1) //信号量剩余较少的时候才去释放信号量 { Interlocked.Increment(ref _curSemCount); _msgSemaphore.Release(); } } catch (SemaphoreFullException) { //当前发送数据频率要大于系统能力,可尝试增加消息队列长度 string msgtype = ""; switch (msg.type) { case NetWorkMsg.Tpye.S_Start: msgtype = "S_Start"; break; case NetWorkMsg.Tpye.S_Send: msgtype = "S_Send"; break; case NetWorkMsg.Tpye.S_Receive: msgtype = "S_Receive"; break; default: break; } DxDebug.LogError("DNServer.AddMessage():大于系统能力,当前最后一条:" + msgtype); throw; } catch (Exception e) { DxDebug.LogError("DNServer.AddMessage():*****发生错误! " + e.Message); throw; } }
/// <summary> /// 初始化这个对象,会创建工作线程 /// </summary> private void Init() { try { //if (!_disposed)//强制释放一遍 //{ // DxDebug.LogConsole("DNClient.Init():释放资源"); // Dispose(); //} if (_msgQueue == null) { _msgQueue = new DQueue <NetWorkMsg>(int.MaxValue, 256); } if (_msgPool == null) { _msgPool = new DQueue <NetWorkMsg>(int.MaxValue, 256); } if (_msgSemaphore == null) { _msgSemaphore = new Semaphore(0, 4); Interlocked.Exchange(ref _curSemCount, 0); } if (_workThread == null) { _workThread = new Thread(DoWork); _workThread.IsBackground = true; _workThread.Start(); //启动线程 } _disposed = false; IsInited = true; } catch (Exception e) { Dispose(); DxDebug.LogError("DNClient.Init():异常:" + e.Message); } }
private void DoWork() { try { DxDebug.LogConsole("DNClient.DoWork():-----------通信线程启动!"); while (true) { Interlocked.Exchange(ref _isThreadWorking, 0);//标记当前线程已经停止工作 _msgSemaphore.WaitOne(); Interlocked.Decrement(ref _curSemCount); //递减信号量计数 Interlocked.Exchange(ref _isThreadWorking, 1); //标记当前线程已经正在执行工作 //_cpuTime.WorkStart(); //时间分析计时 while (true) { NetWorkMsg msg = _msgQueue.Dequeue(); if (msg == null) { break; } float waitTime = (DateTime.Now.Ticks - msg.timeTickCreat) / 10000;//毫秒 if (waitTime > _warringWaitTime) { _warringWaitTime += 500; DxDebug.LogWarning("DNClient.DoWork():NetWorkMsg等待处理时间过长!waitTime:" + waitTime); } else if ((_warringWaitTime - waitTime) > 500) { _warringWaitTime -= 500; } if (msg != null) { switch (msg.type) { case NetWorkMsg.Tpye.C_Connect: DoConnect(); break; case NetWorkMsg.Tpye.C_Send: DoSend(msg); break; case NetWorkMsg.Tpye.C_Receive: DoReceive(); break; case NetWorkMsg.Tpye.C_AsynClose: DoClose(); _workThread = null; //把这个成员置为空 return; //执行完就结束了整个线程函数 default: break; } //用过的消息放回池里 _msgPool.EnqueueMaxLimit(msg); } else { // _cpuTime.Calculate();//空闲的话就计算一下 } //long costTime = _cpuTime.WaitStart(); //时间分析计时 } } } catch (Exception e) { DxDebug.LogError("DNClient.DoWork():异常:通信线程执行异常! " + e.Message); } }
/// <summary> /// 加入一条要执行的消息,如果加入的过快而无法发送,则将产生信号量溢出异常,表明当前发送数据频率要大于系统能力 /// </summary> /// <param name="msg"></param> internal void AddMessage(NetWorkMsg msg) { if (_disposed) { DxDebug.LogWarning("DNClient.AddMessage():DNClient对象已经被释放,不能再加入消息。msgType = " + msg.type.ToString()); return; } try { DxDebug.Log("DNClient.AddMessage():向消息队列中添加消息"); if (msg != null) { _msgQueue.Enqueue(msg); //消息进队列 } if (_curSemCount < 1) //如果当前的信号量剩余不多的时候 { Interlocked.Increment(ref _curSemCount); _msgSemaphore.Release();// 释放信号量 } //发送数据队列长度为128则认为消息已经积攒较长 if (_packet2.SendMsgCount > 128 && _isQueueFull == false)//MAX_SEND_DATA_QUEUE { _isQueueFull = true; if (EventSendQueueIsFull != null) { try { EventSendQueueIsFull(this); } catch (Exception e) { DxDebug.LogWarning("DNClient.AddMessage():执行事件EventMsgQueueIsFull异常:" + e.Message); } } if (_isDebugLog) { DxDebug.LogWarning("DNClient.AddMessage():向消息队列中添加消息,发送队列长度较长:" + _packet2.SendMsgCount); } } else if (_isQueueFull)//如果现在的状态是发送队列较长的状态,那么再去记录峰值长度 { if (_sendQueuePeakLength < _packet2.SendMsgCount) { _sendQueuePeakLength = _packet2.SendMsgCount;//记录当前的峰值长度 } } } catch (SemaphoreFullException) { //当前发送数据频率要大于系统能力,可尝试增加消息队列长度 string msgtype = ""; switch (msg.type) { case NetWorkMsg.Tpye.C_Connect: msgtype = "C_Connect"; break; case NetWorkMsg.Tpye.C_Send: msgtype = "C_Send"; break; case NetWorkMsg.Tpye.C_Receive: msgtype = "C_Receive"; break; default: break; } DxDebug.LogError("DNClient.AddMessage():大于系统能力,当前最后一条:" + msgtype); //throw;//这个throw还是应该去掉 _msgPool.EnqueueMaxLimit(msg); } catch (Exception e) { DxDebug.LogError("DNClient.AddMessage():异常:" + e.Message); //throw;//这个throw还是应该去掉 _msgPool.EnqueueMaxLimit(msg); } }