public void Start(int numConnectMax, List <Thread> threads, int portListen, Func <CommuParam, ReceiveBuffParam, int> afterReceiveCallBack, Func <object, CommuParam, byte[]> beforeSendCallBack, Action <CommuParam> breakCallBack) { this._MaxConnectNum = numConnectMax; CommuEngine._s_DuplexSocketEvents = new DuplexSocketEvent[this._MaxConnectNum]; CommuEngine._s_EventsPerSocket = new int[this._MaxConnectNum]; this._ConnNumPerEngine = this._MaxConnectNum / this._EngineNum; if ((this._MaxConnectNum % this._EngineNum) > 0) { this._ConnNumPerEngine++; } #region Init DuplexSocket's DataStructrue this._DuplexSocketEventPool = new DuplexSocketEventPool(this._MaxConnectNum); for (int i = 1; i < this._MaxConnectNum; i++) { DuplexSocketEvent duplexSocket = new DuplexSocketEvent(CommuEngine.SIZE_SEND_BUFF, CommuEngine.SIZE_RECV_BUFF, CommuEngine.SIZE_RECV_BUFF, i, portListen); duplexSocket.AfterReceiveCallBack = afterReceiveCallBack; duplexSocket.BeforeSendCallBack = beforeSendCallBack; duplexSocket.BreakCallBack = breakCallBack; this._DuplexSocketEventPool.Push(duplexSocket); CommuEngine._s_DuplexSocketEvents[i] = duplexSocket; } #endregion CommuEngine._s_CommuEngineEvents = new AsyncQueue <UInt64> [this._EngineNum]; this._timerHeaps = new MinHeap <OnTimer> [this._EngineNum]; for (int i = 0; i < this._EngineNum; i++) { //OnTimer this._timerHeaps[i] = new MinHeap <OnTimer>(this._ConnNumPerEngine); CommuEngine._s_CommuEngineEvents[i] = new AsyncQueue <UInt64>(); WLLibrary.ThreadHandle.StartBackgroundParamerterizedThread(CommuEngine.Instance.MainLoop, i, threads); } WLLibrary.Communication.Tcp.TCPListener.Start(portListen, threads); }
/// <summary> /// 处理连接 /// </summary> /// <param name="e"></param> private void ProcessAccept(SocketAsyncEventArgs e) { try { if (e.AcceptSocket != null && e.AcceptSocket.Connected) { try { DuplexSocketEvent duplexSocket = CommuEngine.Instance.GetFreeDuplexSocket(); if (duplexSocket != null) { IPEndPoint ipepAcceptAddress = (IPEndPoint)e.AcceptSocket.RemoteEndPoint; duplexSocket.eReceive.AcceptSocket = duplexSocket.eSend.AcceptSocket = e.AcceptSocket; duplexSocket.commuParam.ip = ipepAcceptAddress.Address.ToString(); duplexSocket.commuParam.port = ipepAcceptAddress.Port; CommuEngine.Instance.AddEvent(duplexSocket.SocketID, EventType.Event_New); } else { //e.AcceptSocket.Shutdown(SocketShutdown.Both); e.AcceptSocket.Close(); } e.AcceptSocket = null; } catch (Exception) { //LogEngine.Write(LOGTYPE.ERROR, ex.ToString()); } } } catch (Exception) { //LogEngine.Write(LOGTYPE.ERROR, "【严重】监听处理异常,原因:" + ex.ToString()); } finally { this.StartAccept(ref e); } }
/// <summary> /// [Safe] /// </summary> /// <param name="e"></param> public void Push(DuplexSocketEvent e) { if (e == null) { throw new ArgumentNullException("e"); } else { if (e.eReceive.AcceptSocket != null) { e.eReceive.AcceptSocket = null; } if (e.eSend.AcceptSocket != null) { e.eSend.AcceptSocket = null; } lock (_lock) { _freesocketpool.Enqueue(e); } } }
/// <summary> /// 接纳新连接,启动接收,发送,断开处理线程主体 /// </summary> public void MainLoop(object state) { int idxEngine = Convert.ToInt32(state); int numCurLoop = 0, numMaxLoop = 0; Socket socket = null; byte[] sockSendBuf = null; DuplexSocketEvent sockDup = null; UInt64 eventsOuterData = 0uL; int socketId = 0; int events = 0; byte[] sendEachBuffer = null; AsyncQueue <UInt64> eventsOuter = CommuEngine._s_CommuEngineEvents[idxEngine]; UInt64[] dataPoolOnce = new UInt64[CommuEngine.POOL_MAX_LOOP]; MinHeap <OnTimer> timerHeap = this._timerHeaps[idxEngine]; int idxBegin = idxEngine * this._ConnNumPerEngine; if (idxBegin == 0) { idxBegin = 1; } int idxEnd = (idxEngine + 1) * this._ConnNumPerEngine - 1; if (idxEnd > this._MaxConnectNum - 1) { idxEnd = this._MaxConnectNum - 1; } while (this._systemRun) { socket = null; try { numCurLoop = 0; numMaxLoop = eventsOuter.DequeueToArray(dataPoolOnce); while (numCurLoop < numMaxLoop) { eventsOuterData = dataPoolOnce[numCurLoop++]; socketId = (int)(eventsOuterData & 0x00000000FFFFFFFFL); CommuEngine._s_EventsPerSocket[socketId] |= (int)(eventsOuterData >> 32); } for (int i = idxBegin; i <= idxEnd; i++) { events = CommuEngine._s_EventsPerSocket[i]; if (events < 1) { continue; } socketId = i; CommuEngine._s_EventsPerSocket[i] = 0; sockDup = CommuEngine._s_DuplexSocketEvents[socketId]; if ((events & (int)EventType.Event_New) > 0) { #region New Connect socket = sockDup.eReceive.AcceptSocket; try { if (socket != null && !socket.ReceiveAsync(sockDup.eReceive)) { sockDup.ProcessReceive(sockDup.eReceive); } } catch (System.InvalidOperationException) { LogEngine.Write(LOGTYPE.ERROR, sockDup.SocketID.ToString(), "/s,", idxEngine.ToString(), "/idx,", sockDup.eReceive.LastOperation.ToString()); } catch (Exception ex2) { LogEngine.Write(LOGTYPE.ERROR, sockDup.SocketID.ToString(), "/s,", idxEngine.ToString(), "/idx,", ex2.Message); } OnTimer timer = new OnTimer(OnTimer.TimerHeapType.ONCE, 10 * 1000, sockDup.ConnectOnTimer); timerHeap.Push(timer); #endregion } else if ((events & (int)EventType.Event_StopCommu) > 0) { #region Stop if (sockDup.IsBreak) { continue; } try { socket = sockDup.eReceive.AcceptSocket; if (socket != null) { //socket.Shutdown(SocketShutdown.Both); socket.Close(); } } catch (Exception ex) { LogEngine.Write(LOGTYPE.ERROR, "Event_StopCommu:", ex.ToString()); } finally { sockDup.eReceive.AcceptSocket = sockDup.eSend.AcceptSocket = null; sockDup.SetBreak(); if (sockDup.BreakCallBack != null) { sockDup.BreakCallBack(sockDup.commuParam); } } #endregion } else if ((events & (int)EventType.Event_Close) > 0) { #region Close //回收 this._DuplexSocketEventPool.Push(sockDup);//second if (!sockDup.IsBreak) { LogEngine.Write(LOGTYPE.ERROR, "Get Event_StopCommu,But Target Not Break:", sockDup.SocketID.ToString(), "/sid"); } #endregion } else { sockDup = CommuEngine._s_DuplexSocketEvents[socketId]; if (sockDup.IsBreak) { continue; } //if ((events & Event_Receive) > 0) //{ // #region Receive // #endregion //} if ((events & (int)EventType.Event_SendComplet) > 0) { #region SendComplet if (sockDup.SendPool.Count > 0) { events |= (int)EventType.Event_Send; } #endregion } if ((events & (int)EventType.Event_Send) > 0) { #region 处理发放 sockSendBuf = sockDup.SendBuffer; while (sockDup.SendPool.Count > 0) { sendEachBuffer = sockDup.SendPool.First(); #region Concat bytes if (sendEachBuffer.Length <= sockSendBuf.Length) { if (sendEachBuffer.Length <= (sockSendBuf.Length - sockDup.waitSendLen)) { sendEachBuffer = sockDup.SendPool.Dequeue(); Buffer.BlockCopy(sendEachBuffer, 0, sockSendBuf, sockDup.waitSendLen, sendEachBuffer.Length); sockDup.waitSendLen += sendEachBuffer.Length; if (sockDup.waitSendLen >= CommuEngine.MTU_SEND) { break; } } else { break; } } else { sockDup.SendPool.Dequeue();//drop data //LogEngine.Write(LOGTYPE.ERROR, "ProtocolData TooLong Max:", sockSendBuf.Length.ToString(), ",", sockDup.Profile); } #endregion } #region ProcessSend if (sockDup.waitSendLen > 0) { sockDup.eSend.SetBuffer(sockSendBuf, 0, sockDup.waitSendLen); sockDup.sendBeginTicks = DateTime.Now.Ticks; socket = sockDup.eSend.AcceptSocket; try { if (socket != null && socket.Connected && !socket.SendAsync(sockDup.eSend)) { sockDup.ProcessSend(sockDup.eSend); } } catch (SocketException) { if (sockDup.eSend.SocketError == SocketError.MessageSize) { sockDup.Break(CommuBreak.SERVER_SEND_DATA_SIZE); } else { sockDup.Break(CommuBreak.SERVER_SEND_EXPECT); } } } #endregion #endregion } } } //OnTimer while (timerHeap.Count > 0 && timerHeap.Root.Weight <= DateTime.Now.Ticks) { if (timerHeap.Root.TimeOutCallBack != null) { timerHeap.Root.TimeOutCallBack(null); } if (timerHeap.Root.Type == OnTimer.TimerHeapType.ALWAYS) { timerHeap.ChangeWeight(timerHeap.Root.HeapIndex, timerHeap.Root.RefreshWeight()); } else { timerHeap.PopRoot(); } } } catch (System.Exception ex) { LogEngine.Write(LOGTYPE.ERROR, "CommuEngine MainLoop:", ex.ToString()); } finally { Thread.Sleep(1); } } }