您的位置:首页 > 编程语言 > C#

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

2012-08-30 16:27 417 查看
转载自
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;

}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: