C# 实现的多线程异步Socket数据包接收器框架(3)

来源:互联网 发布:linux软件 编辑:程序博客网 时间:2024/04/28 03:01
转载自 zhonghuafy

3.3 处理数据包

该线程循环查看数据包队列,完成数据包的解析与存储等工作。具体实现时,如果队列中没有数据包,可以考虑等待若干毫秒,提高CPU利用率。

Code
private void HandleDatagrams(object state)
{
while (!_stopReceiver)
{
this.HandleOneDatagram();// 处理一个数据包

if (!_stopReceiver)
{
// 如果连接关闭,则重新建立,可容许几个连接错误出现
if (_sqlConnection.State== ConnectionState.Closed)
{
this.OnReceiverWork();

try
{
_sqlConnection.Open();
}
catch
{
this.OnReceiverException();
}
}
}
}
}

/// <summary>
/// 处理一个包数据,包括:验证、存储
/// </summary>
private void HandleOneDatagram()
{
TDatagram datagram
=null;

lock (_datagramQueue)
{
if (_datagramQueue.Count> 0)
{
datagram
= _datagramQueue.Dequeue();// 取队列数据
Interlocked.Decrement(ref _datagramQueueCount);
}
}

if (datagram== null)return;

datagram.Clear();
datagram
= null; // 释放对象
}

3.4 检查与清理会话

本线程负责处理建立连接后的客户端会话TSession或Socket对象的关闭与资源清理工作,其它方法中出现异常等情况,尽可能标记相关TSession对象的属性NoReply=true,表示该会话已经无效、需要清理。

检查会话队列并清理资源分3步:第一步,Shutdown()客户端Socket,此时可能立即触发某些Socket的异步方法EndReceive();第二步,Close()客户端Socket,释放占用资源;第三步,从会话表中清除该会话对象。其中,第一步完成后,某个TSession也许不会立即到第二步,因为可能需要处理其异步结束方法。

需要指出, 由于涉及多线程处理,需要频繁加解锁操作,清理工作前先建立一个会话队列列副本sessionTable2,检查与清理该队副本列列的TSession对象。

Code
/// <summary>
/// 检查客户端状态(扫描方式,若长时间无数据,则断开)
/// </summary>
private void CheckClientState(object state)
{
while (!_stopReceiver)
{
DateTime thisTime
= DateTime.Now;

// 建立一个副本 ,然后对副本进行操作
Hashtable sessionTable2 =new Hashtable();
lock (_sessionTable)
{
foreach (TSession sessionin _sessionTable.Values)
{
if (session!= null)
{
sessionTable2.Add(session.ID, session);
}
}
}

foreach (TSession sessionin sessionTable2.Values)// 对副本进行操作
{
Monitor.Enter(session);
try
{
if (session.State== TSessionState.NoReply)// 分三步清除一个 Session
{
session.State
= TSessionState.Closing;
if (session.ClientSocket!= null)
{
try
{
// 第一步:shutdown
session.ClientSocket.Shutdown(SocketShutdown.Both);
}
catch { }
}
}
else if (session.State == TSessionState.Closing)
{
session.State
= TSessionState.Closed;
if (session.ClientSocket!= null)
{
try
{
// 第二步: Close
session.ClientSocket.Close();
}
catch { }
}
}
else if (session.State == TSessionState.Closed)
{

lock (_sessionTable)
{
// 第三步:remove from table
_sessionTable.Remove(session.ID);
Interlocked.Decrement(
ref _clientCount);
}

this.OnClientRequest();
session.Clear();
// 清空缓冲区
}
else if (session.State == TSessionState.Normal)// 正常的会话
{

TimeSpan ts
= thisTime.Subtract(session.LastDataReceivedTime);
if (Math.Abs(ts.TotalSeconds)> _maxSocketDataTimeout)// 超时,则准备断开连接
{
session.DisconnectType
= TDisconnectType.Timeout;
session.State
= TSessionState.NoReply;// 标记为将关闭、准备断开
}
}
}
finally
{
Monitor.Exit(session);
}
}
// end foreach

sessionTable2.Clear();
}
// end while
}
原创粉丝点击