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

转载自 zhonghuafy

//from http://www.cnblogs.com/wcfgroup/archive/2008/10/06/1304512.html

几天前在博问中看到一个C# Socket问题,就想到笔者2004年做的一个省级交通流量接收服务器项目,当时的基本求如下:

  • 接收自动观测设备通过无线网卡、Internet和Socket上报的交通量数据包
  • 全年365*24运行的自动观测设备5分钟上报一次观测数据,每笔记录约2K大小
  • 规划全省将有100个左右的自动观测设备(截止2008年10月还只有30个)

当时,VS2003才发布年多,笔者也是接触C#不久。于是Google了国内国外网,希望找点应用C#解决Socket通信问题的思路和代码。最后,找到了两篇帮助最大的文章:一篇是国人写的Socket接收器框架,应用了独立的客户端Socket会话(Session)概念,给笔者提供了一个接收服务器的总体框架思路;另一篇是美国人写的,提出了多线程、分段接收数据包的技术方案,描述了多线程、异步Socket的许多实现细节,该文坚定了笔者采用多线程和异步方式处理Socket接收器的技术路线。

具体实现和测试时笔者还发现,在Internet环境下的Socket应用中,需要系统有极强的容错能力:没有办法控制异常,就必须允许它们存在(附加源代码中可以看到,try{}catch{}语句较多)。对此,笔者设计了一个专门的检查和清理线程,完成无效或超时会话的清除和资源释放工作。

依稀记得,国内框架作者的名称空间有ibm,认为是IBM公司职员,通过邮件后才知道其人在深圳。笔者向他请教了几个问题,相互探讨了几个技术关键点。可惜,现在再去找,已经查不到原文和邮件了。只好借此机会,将本文献给这两个素未谋面的技术高人和同行,也盼望拙文或源码能给读者一点有用的启发和帮助。

1、主要技术思路

整个系统由三个核心线程组成,并由.NET线程池统一管理:

  • 侦听客户端连接请求线程:ListenClientRequest(),循环侦听客户端连接请求。如果有,检测该客户端IP,看是否是同一观测设备,然后建立一个客户端TSession对象,并通过Socket异步调用方法BeginReceive()接收数据包、EndReceive()处理数据包
  • 数据包处理线程:HandleDatagrams(),循环检测数据包队列_datagramQueue,完成数据包解析、判断类型、存储等工作
  • 客户端状态检测线程:CheckClientState(),循环检查客户端会话表_sessionTable,判断会话对象是否有效,设置超时会话关闭标志,清楚无效会话对象及释放其资源

2、主要类简介

系统主要由3个类组成:

  • TDatagramReceiver(数据包接收服务器):系统的核心进程类,建立Socket连接、处理与存储数据包、清理系统资源,该类提供全部的public属性和方法
  • TSession(客户端会话):由每个客户端的Socket对象组成,有自己的数据缓冲区,清理线程根据该对象的最近会话时间判断是否超时
  • TDatagram(数据包类):判断数据包类别、解析数据包

3、关键函数和代码

下面简介核心类TDatagramReceiver的关键实现代码。

3.1 系统启动

系统启动方法StartReceiver()首先清理资源、创建数据库连接、初始化若干计数值,然后创建服务器端侦听Socket对象,最后调用静态方法ThreadPool.QueueUserWorkItem()在线程池中创建3个核心处理线程。

Code
/// <summary>
/// 启动接收器
/// </summary>
public bool StartReceiver()
{
try
{
_stopReceiver
= true;

this.Close();

if (!this.ConnectDatabase()) return false;

_clientCount
= 0;
_datagramQueueCount
= 0;
_datagramCount
= 0;
_errorDatagramCount
= 0;
_exceptionCount
= 0;

_sessionTable
= new Hashtable(_maxAllowClientCount);
_datagramQueue
= new Queue<TDatagram>(_maxAllowDatagramQueueCount);

_stopReceiver
= false; // 循环中均要该标志

if (!this.CreateReceiverSocket()) //建立服务器端 Socket 对象
{
return false;
}

// 侦听客户端连接请求线程, 使用委托推断, 不建 CallBack 对象
if (!ThreadPool.QueueUserWorkItem(ListenClientRequest))
{
return false;
}

// 处理数据包队列线程
if (!ThreadPool.QueueUserWorkItem(HandleDatagrams))
{
return false;
}

// 检查客户会话状态, 长时间未通信则清除该对象
if (!ThreadPool.QueueUserWorkItem(CheckClientState))
{
return false;
}

_stopConnectRequest
= false; // 启动接收器,则自动允许连接
}
catch
{
this.OnReceiverException();
_stopReceiver
= true;
}
return !_stopReceiver;
}

你可能感兴趣的:(多线程,框架,socket,C#,服务器,internet)