ListenClientRequest():循環 Accept(),檢查 IP 重複,建立 TSession,啟動 BeginReceive()。HandleDatagrams():循環取出 _datagramQueue,解析、驗證、入庫。CheckClientState():掃描 _sessionTable,三階段清理(Shutdown → Close → Remove),釋放資源。| 類別 | 職責 |
|---|---|
TDatagramReceiver | 核心進程:Socket 生命週期、執行緒協調、資源管理、對外公共 API |
TSession | 客戶端會話封裝:Socket、接收緩衝區、最後活動時間、狀態機 |
TDatagram | 封包實體:型別判斷、解析、資料載體 |
StartReceiver()public bool StartReceiver()
{
try
{
_stopReceiver = true; this.Close(); // 清理舊資源
if (!ConnectDatabase()) return false;
// 重置計數器
_clientCount = _datagramQueueCount = _datagramCount =
_errorDatagramCount = _exceptionCount = 0;
_sessionTable = new Hashtable(_maxAllowClientCount);
_datagramQueue = new Queue<TDatagram>(_maxAllowDatagramQueueCount);
_stopReceiver = false;
if (!CreateReceiverSocket()) return false;
// ThreadPool 佇列三大核心執行緒
if (!ThreadPool.QueueUserWorkItem(ListenClientRequest)) return false;
if (!ThreadPool.QueueUserWorkItem(HandleDatagrams)) return false;
if (!ThreadPool.QueueUserWorkItem(CheckClientState)) return false;
_stopConnectRequest = false;
}
catch { OnReceiverException(); _stopReceiver = true; }
return !_stopReceiver;
}
關鍵點:使用委托而非 Callback 物件、Interlocked 原子計數、_stopReceiver 旗標統一控制迴圈退出。
CreateReceiverSocket()private bool CreateReceiverSocket()
{
try
{
_receiverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_receiverSocket.Bind(new IPEndPoint(IPAddress.Any, _tcpSocketPort));
_receiverSocket.Listen(_maxAllowListenQueueLength);
return true;
}
catch { OnReceiverException(); return false; }
}
ListenClientRequest() - 異步套異步模式private void ListenClientRequest(object state)
{
while (!_stopReceiver)
{
// 停止連線請求處理
if (_stopConnectRequest) { /* 關閉 socket、清理 */ continue; }
if (_receiverSocket == null && !CreateReceiverSocket()) continue;
try
{
if (_receiverSocket.Poll(_loopWaitTime, SelectMode.SelectRead))
{
Socket client = _receiverSocket.Accept();
if (client != null && client.Connected)
{
// 連線數上限、IP 重複檢查
if (_clientCount >= _maxAllowClientCount || CheckSameClientIP(client))
{ /* 關閉拒絕 */ }
else
{
var session = new TSession(client) { LoginTime = DateTime.Now };
lock (_sessionTable)
{
// 確保 Session ID 唯一
while (_sessionTable.ContainsKey(session.ID))
session.ID = 100000 + session.ID;
_sessionTable.Add(session.ID, session);
Interlocked.Increment(ref _clientCount);
}
OnClientRequest();
// 關鍵:異步接收,回調 EndReceiveData
try { session.ClientSocket.BeginReceive(session.ReceiveBuffer, 0,
session.ReceiveBufferLength, SocketFlags.None, EndReceiveData, session); }
catch { session.DisconnectType = TDisconnectType.Exception; session.State = TSessionState.NoReply; }
}
}
}
}
catch { /* 例外處理、關閉 client */ }
// Thread.Sleep(適當毫秒) 降低 CPU 佔用
}
}
設計亮點:Poll 非阻塞檢查、lock 保護共享資料結構、異常時標記狀態交由清理執行緒處理。
HandleDatagrams()private void HandleDatagrams(object state)
{
while (!_stopReceiver)
{
HandleOneDatagram();
// 連線斷線自動重連邏輯
if (!_stopReceiver && _sqlConnection.State == ConnectionState.Closed)
{
OnReceiverWork();
try { _sqlConnection.Open(); } catch { OnReceiverException(); }
}
}
}
private void HandleOneDatagram()
{
TDatagram dg = null;
lock (_datagramQueue)
if (_datagramQueue.Count > 0) { dg = _datagramQueue.Dequeue(); Interlocked.Decrement(ref _datagramQueueCount); }
if (dg == null) return;
dg.Clear(); dg = null; // 釋放參考
}
CheckClientState() - 三階段狀態機private void CheckClientState(object state)
{
while (!_stopReceiver)
{
var now = DateTime.Now;
// 建立副本避免長時間持有鎖
Hashtable snapshot;
lock (_sessionTable) { snapshot = new Hashtable(_sessionTable); }
foreach (TSession session in snapshot.Values)
{
Monitor.Enter(session);
try
{
switch (session.State)
{
case TSessionState.NoReply:
session.State = TSessionState.Closing;
session.ClientSocket?.Shutdown(SocketShutdown.Both); break;
case TSessionState.Closing:
session.State = TSessionState.Closed;
session.ClientSocket?.Close(); break;
case TSessionState.Closed:
lock (_sessionTable) { _sessionTable.Remove(session.ID); Interlocked.Decrement(ref _clientCount); }
OnClientRequest(); session.Clear(); break;
case TSessionState.Normal:
if ((now - session.LastDataReceivedTime).TotalSeconds > _maxSocketDataTimeout)
{ session.DisconnectType = TDisconnectType.Timeout; session.State = TSessionState.NoReply; }
break;
}
}
finally { Monitor.Exit(session); }
}
snapshot.Clear();
// Thread.Sleep(間隔)
}
}
關鍵模式:快照隔離(複製 Hashtable 再遍歷)、狀態機驅動清理(NoReply→Closing→Closed)、Monitor 細粒度鎖(鎖 Session 而非整張表)。
ConnectionState.Closed 並重開。此框架展示了早期 .NET 在高併發網路服務上的工程化實踐:ThreadPool 統一調度、非同步 I/O、狀態機資源管理、快照隔離鎖策略。雖然現代開發傾向 async/await、Channels、Kestrel 等高階抽象,但核心思想——關注點分離、失敗隔離、背壓控制——至今仍具參考價值。