vb.net中轮询 vbnet console
用vb.net做串口通讯程序要调用哪些api函数?
串口API通信函数编程
发展壮大离不开广大客户长期以来的信赖与支持,我们将始终秉承“诚信为本、服务至上”的服务理念,坚持“二合一”的优良服务模式,真诚服务每家企业,认真做好每个细节,不断完善自我,成就企业,实现共赢。行业涉及成都主动防护网等,在网站建设公司、网络营销推广、WAP手机网站、VI设计、软件开发等项目上具有丰富的设计经验。
16位串口应用程序中,使用的16位的Windows API通信函数:
①OpenComm()打开串口资源,并指定输入、输出缓冲区的大小(以字节计)
CloseComm() 关闭串口;
例:int idComDev;
idComDev = OpenComm("COM1", 1024, 128);
CloseComm(idComDev);
②BuildCommDCB() 、setCommState()填写设备控制块DCB,然后对已打开的串口进行参数配置; 例:DCB dcb;
BuildCommDCB("COM1:2400,n,8,1", dcb);
SetCommState(dcb);
③ ReadComm 、WriteComm()对串口进行读写操作,即数据的接收和发送.
例:char *m_pRecieve; int count;
ReadComm(idComDev,m_pRecieve,count);
Char wr[30]; int count2;
WriteComm(idComDev,wr,count2);
16位下的串口通信程序最大的特点就在于:串口等外部设备的操作有自己特有的API函数;而32位程序则把串口操作(以及并口等)和文件操作统一起来了,使用类似的操作。
在MFC下的32位串口应用程序
32位下串口通信程序可以用两种方法实现:利用ActiveX控件;使用API 通信函数。
使用ActiveX控件,程序实现非常简单,结构清晰,缺点是欠灵活;使用API 通信函数的优缺点则基本上相反。
使用ActiveX控件:
VC++ 6.0提供的MSComm控件通过串行端口发送和接收数据,为应用程序提供串行通信功能。使用非常方便,但可惜的是,很少有介绍MSComm控件的资料。
⑴.在当前的Workspace中插入MSComm控件。
Project菜单------Add to Project----Components and Controls-----Registered
ActiveX Controls---选择Components: Microsoft Communications Control,
version 6.0 插入到当前的Workspace中。
结果添加了类CMSComm(及相应文件:mscomm.h和mscomm.cpp )。
⑵.在MainFrm.h中加入MSComm控件。
protected:
CMSComm m_ComPort;
在Mainfrm.cpp::OnCreare()中:
DWORD style=WS_VISIBLE|WS_CHILD;
if (!m_ComPort.Create(NULL,style,CRect(0,0,0,0),this,ID_COMMCTRL)){
TRACE0("Failed to create OLE Communications Control\n");
return -1; // fail to create
}
⑶.初始化串口
m_ComPort.SetCommPort(1); //选择COM?
m_ComPort. SetInBufferSize(1024); //设置输入缓冲区的大小,Bytes
m_ComPort. SetOutBufferSize(512); //设置输入缓冲区的大小,Bytes//
if(!m_ComPort.GetPortOpen()) //打开串口
m_ComPort.SetPortOpen(TRUE);
m_ComPort.SetInputMode(1); //设置输入方式为二进制方式
m_ComPort.SetSettings("9600,n,8,1"); //设置波特率等参数
m_ComPort.SetRThreshold(1); //为1表示有一个字符引发一个事件
m_ComPort.SetInputLen(0);
⑷.捕捉串口事项。MSComm控件可以采用轮询或事件驱动的方法从端口获取数据。我们介绍比较使用的事件驱动方法:有事件(如接收到数据)时通知程序。在程序中需要捕获并处理这些通讯事件。
在MainFrm.h中:
protected:
afx_msg void OnCommMscomm();
DECLARE_EVENTSINK_MAP()
在MainFrm.cpp中:
BEGIN_EVENTSINK_MAP(CMainFrame,CFrameWnd )
ON_EVENT(CMainFrame,ID_COMMCTRL,1,OnCommMscomm,VTS_NONE) //映射ActiveX控件事件
END_EVENTSINK_MAP()
⑸.串口读写. 完成读写的函数的确很简单,GetInput()和SetOutput()就可。两个函数的原型是:
VARIANT GetInput();及 void SetOutput(const VARIANT newValue);都要使用VARIANT类型(所有Idispatch::Invoke的参数和返回值在内部都是作为VARIANT对象处理的)。
无论是在PC机读取上传数据时还是在PC机发送下行命令时,我们都习惯于使用字符串的形式(也可以说是数组形式)。查阅VARIANT文档知道,可以用BSTR表示字符串,但遗憾的是所有的BSTR都是包含宽字符,即使我们没有定义_UNICODE_UNICODE也是这样! WinNT支持宽字符, 而Win95并不支持。为解决上述问题,我们在实际工作中使用CbyteArray,给出相应的部分程序如下:
void CMainFrame::OnCommMscomm(){
VARIANT vResponse; int k;
if(m_commCtrl.GetCommEvent()==2) {
k=m_commCtrl.GetInBufferCount(); //接收到的字符数目
if(k0) {
vResponse=m_commCtrl.GetInput(); //read
SaveData(k,(unsigned char*) vResponse.parray-pvData);
} // 接收到字符,MSComm控件发送事件 }
。。。。。 // 处理其他MSComm控件
}
void CMainFrame::OnCommSend() {
。。。。。。。。 // 准备需要发送的命令,放在TxData[]中
CByteArray array;
array.RemoveAll();
array.SetSize(Count);
for(i=0;iCount;i++)
array.SetAt(i, TxData[i]);
m_ComPort.SetOutput(COleVariant(array)); // 发送数据 }
二 使用32位的API 通信函数:
⑴.在中MainFrm.cpp定义全局变量
HANDLE hCom; // 准备打开的串口的句柄
HANDLE hCommWatchThread ;//辅助线程的全局函数
⑵.打开串口,设置串口
hCom =CreateFile( "COM2", GENERIC_READ | GENERIC_WRITE, // 允许读写
0, // 此项必须为0
NULL, // no security attrs
OPEN_EXISTING, //设置产生方式
FILE_FLAG_OVERLAPPED, // 我们准备使用异步通信
NULL );
我使用了FILE_FLAG_OVERLAPPED结构。这正是使用API实现非阻塞通信的关键所在。
ASSERT(hCom!=INVALID_HANDLE_VALUE); //检测打开串口操作是否成功
SetCommMask(hCom, EV_RXCHAR|EV_TXEMPTY );//设置事件驱动的类型
SetupComm( hCom, 1024,512) ; //设置输入、输出缓冲区的大小
PurgeComm( hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR
| PURGE_RXCLEAR ); //清干净输入、输出缓冲区
COMMTIMEOUTS CommTimeOuts ; //定义超时结构,并填写该结构
…………
SetCommTimeouts( hCom, CommTimeOuts ) ;//设置读写操作所允许的超时
DCB dcb ; // 定义数据控制块结构
GetCommState(hCom, dcb ) ; //读串口原来的参数设置
dcb.BaudRate =9600; dcb.ByteSize =8; dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT ;dcb.fBinary = TRUE ;dcb.fParity = FALSE;
SetCommState(hCom, dcb ) ; //串口参数配置
上述的COMMTIMEOUTS结构和DCB都很重要,实际工作中需要仔细选择参数。
⑶启动一个辅助线程,用于串口事件的处理。
Windows提供了两种线程,辅助线程和用户界面线程。辅助线程没有窗口,所以它没有自己的消息循环。但是辅助线程很容易编程,通常也很有用。
在次,我们使用辅助线程。主要用它来监视串口状态,看有无数据到达、通信有无错误;而主线程则可专心进行数据处理、提供友好的用户界面等重要的工作。
hCommWatchThread=
CreateThread( (LPSECURITY_ATTRIBUTES) NULL, //安全属性
0,//初始化线程栈的大小,缺省为与主线程大小相同
(LPTHREAD_START_ROUTINE)CommWatchProc, //线程的全局函数
GetSafeHwnd(), //此处传入了主框架的句柄
0, dwThreadID );
ASSERT(hCommWatchThread!=NULL);
⑷为辅助线程写一个全局函数,主要完成数据接收的工作。请注意OVERLAPPED结构的使用,以及怎样实现了非阻塞通信。
UINT CommWatchProc(HWND hSendWnd){
DWORD dwEvtMask=0 ;
SetCommMask( hCom, EV_RXCHAR|EV_TXEMPTY );//有哪些串口事件需要监视?
WaitCommEvent( hCom, dwEvtMask, os );// 等待串口通信事件的发生
检测返回的dwEvtMask,知道发生了什么串口事件:
if ((dwEvtMask EV_RXCHAR) == EV_RXCHAR){ // 缓冲区中有数据到达
COMSTAT ComStat ; DWORD dwLength;
ClearCommError(hCom, dwErrorFlags, ComStat ) ;
dwLength = ComStat.cbInQue ; //输入缓冲区有多少数据?
if (dwLength 0) { BOOL fReadStat ;
fReadStat = ReadFile( hCom, lpBuffer,dwLength, dwBytesRead,READ_OS( npTTYInfo ) ); //读数据
注:我们在CreareFile()时使用了FILE_FLAG_OVERLAPPED,现在ReadFile()也必须使用
LPOVERLAPPED结构.否则,函数会不正确地报告读操作已完成了.
使用LPOVERLAPPED结构, ReadFile()立即返回,不必等待读操作完成,实现非阻塞
通信.此时, ReadFile()返回FALSE, GetLastError()返回ERROR_IO_PENDING.
if (!fReadStat){
if (GetLastError() == ERROR_IO_PENDING){
while(!GetOverlappedResult(hCom,READ_OS( npTTYInfo ), dwBytesRead, TRUE )){
dwError = GetLastError();
if(dwError == ERROR_IO_INCOMPLETE) continue;//缓冲区数据没有读完,继续
…… ……
::PostMessage((HWND)hSendWnd,WM_NOTIFYPROCESS,0,0);//通知主线程,串口收到数据}
所谓的非阻塞通信,也即异步通信。是指在进行需要花费大量时间的数据读写操作(不仅仅是指串行通信操作)时,一旦调用ReadFile()、WriteFile(), 就能立即返回,而让实际的读写操作在后台运行;相反,如使用阻塞通信,则必须在读或写操作全部完成后才能返回。由于操作可能需要任意长的时间才能完成,于是问题就出现了。
非常阻塞操作还允许读、写操作能同时进行(即重叠操作?),在实际工作中非常有用。
要使用非阻塞通信,首先在CreateFile()时必须使用FILE_FLAG_OVERLAPPED;然后在 ReadFile()时lpOverlapped参数一定不能为NULL,接着检查函数调用的返回值,调用GetLastError(),看是否返回ERROR_IO_PENDING。如是,最后调用GetOverlappedResult()返回重叠操作(overlapped operation)的结果;WriteFile()的使用类似。
⑸.在主线程中发送下行命令。
BOOL fWriteStat ; char szBuffer[count];
…………//准备好发送的数据,放在szBuffer[]中
fWriteStat = WriteFile(hCom, szBuffer, dwBytesToWrite,
dwBytesWritten, WRITE_OS( npTTYInfo ) ); //写数据
//我在CreareFile()时使用了FILE_FLAG_OVERLAPPED,现在WriteFile()也必须使用LPOVERLAPPED结构.否则,函数会不正确地报告写操作已完成了.
使用LPOVERLAPPED结构,WriteFile()立即返回,不必等待写操作完成,实现非阻塞 通信.此时, WriteFile()返回FALSE, GetLastError()返回ERROR_IO_PENDING.
int err=GetLastError();
if (!fWriteStat) {
if(GetLastError() == ERROR_IO_PENDING){
while(!GetOverlappedResult(hCom, WRITE_OS( npTTYInfo ),
dwBytesWritten, TRUE )) {
dwError = GetLastError();
if(dwError == ERROR_IO_INCOMPLETE){// normal result if not finished
dwBytesSent += dwBytesWritten; continue; }
......................
//我使用了多线程技术,在辅助线程中监视串口,有数据到达时依靠事件驱动,读入数据并向主线程报告(发送数据在主线程中,相对说来,下行命令的数据总是少得多);并且,WaitCommEvent()、ReadFile()、WriteFile()都使用了非阻塞通信技术,依靠重叠(overlapped)读写操作,让串口读写操作在后台运行。
与VB .NET一起使用.NET Framework
使用 NET Framework Microsoft Visual Basic开发人员可以创建健壮的 在先前的Visual Basic版本中很难编写的应用程序 本文将讨论使用 NET Framework的好处 并且将包括一些功能强大的 Visual Basic开发人员可以与该框架一起使用的特性 包括多线程和线程池(thread pooling) Windows服务和文件系统监控等 为什么使用框架 单词框架(framework)有几种含意 在这种情况中 它指的是创建和运行应用程序的基础 拥有这样的基础使得创建应用程序变得更容易 而同时使用了一个一致的 简化的程序设计模型 作为一个Visual Basic 开发人员 你对于这种程序设计语言感觉很满意 它使得创建各种应用程序变得很容易 Visual Basic语言本身提供了固有的数据类型 如 Integer Long和String 以及一些最常用的函数 如字符串处理和数据类型转换等 当你的应用程序变得更复杂时 你可以使用Win API来完成标准的Visual Basic函数所不能实现的功能 如获取任意的注册键和数值 在许多情况中 你还可以使用(Component Object Model 组件对象模型)组件库来扩展应用程序的功能 最明显的例子是ADO(ActiveX Data Objects)库 你的应用程序可以使用它来进行数据访问 虽然Visual Basic足够灵活 可以提供这些不同的可扩展性机制 但这种灵活性仍然需要你学习几种复杂的API体系结构 你需要了解Win 如何工作 以及如何在Visual Basic中调用它们 这可能会是一个既费时又容易出错的任务 你还需要了解如何在Visual Basic中使用各种组件 每个组件都有一个不同的对象模型 最后 当你使用Win API ADO 也可能使用许多其他组件 创建自己的Visual Basic应用程序时 你需要管理这些应用程序的部署以及它们的相关性 一个典型的Visual Basic应用程序的相关性列表所包括的远远多于Visual Basic运行时(runtime);它必须包括应用程序使用的所有对象库 如ADO 公共框架背后的想法是解决这些问题 并使得用户创建健壮的应用程序变得更容易 而无需学习多种不同的API体系结构 并且无需部署和处理多种对象库的版本问题 什么是 NET Framework 术语 NET Framework指的是构成Microsoft NET平台开发基础的一组技术 这一组中的关键技术是运行时(runtime)和类库 运行时负责管理代码 在执行时向它提供服务 这与Visual Basic 运行时的作用类似 NET程序设计语言 包括Visual Basic NET Microsoft Visual C# C++管理的扩展 以及多种来自不同开发商的程序设计语言 通过一组公共的统一类来利用各种服务和特性 NET统一类提供了创建应用程序的基础 而不管你使用何种语言 无论你只是简单地连接一个字符串 还是创建一个Windows服务或多层的基于网络的应用程序 你都要用到这些统一类 统一类为访问平台的功能性提供了一种一致的方法 一旦你学会了使用类库 你就会发现所有任务都遵循同一个一致的体系结构 要编写自己的应用程序 你无需学习和掌握不同的API体系结构 由于 NET Framework 部署Visual Basic NET应用程序变得更容易了 与Visual Basic 应用程序不同 你无需配置各种相关性 如单独的数据访问库 XML语法分析器和网络API 因为所有这些功能都是 NET Framework的组成部分 通过在统一的 集成的框架上创建自己的应用程序 你可以实现学习这种框架所花费时间的最大回报 并且你将拥有更多容易部署和使用的健壮的应用程序 NET Framework与Visual Basic NET Visual Basic 运行时在简化许多公共的程序设计任务方面非常重要 但是简化这一层意味着 在拥有Visual Basic可以使用的打包程序之前 你不能使用新的操作系统特性 如DirectX 作为一个Visual Basic开发人员 你从 NET Framework获得的最重要的益处是 可以使用一致的程序设计模型既直接又容易地访问 NET平台 这意味着 你可以使用Visual Basic NET创建很难或不可能使用Visual Basic 创建的应用程序 作为一个Visual Basic 开发人员 现在你将对能够使用与其他平台语言相同的特性和功能而赞赏不已 例如 为了创建Windows服务 你无须再用Microsoft Visual C++来编写它 你也无须求助于黑客或组装机 你可以优雅 干净 容易地使用Visual Basic NET完成这项工作 为了给你一些使用 NET Framwork的例子 我们将讨论在你的应用程序中可能需要执行的 个常见任务 跟踪与事件记录 多线程 文件系统监控和创建Windows服务 跟踪与事件记录 当创建一个健壮的应用程序的时候 你必须密切注意诊断和故障排除机制 代表性地 这包括编写处理打开输出目标(事件记录或文件)的跟踪组件 编写跟踪消息和关闭输出目标 然后通过自己的代码调用关于这个组件的方法 将文本传递给记录 你将所有的时间和精力花在了创建跟踪和记录子系统上 这最终并不会对解决商务问题有所贡献 但这是创建应用程序所必需的 NET Framework包括类和其他数据类型 通过向你提供记录基础设施 使得记录跟踪消息变得很容易 图 给出了用于跟踪的 NET Framework类 类是System Diagnostics名称空间的一部分 Trace类提供了几个共享的方法 例如 Write方法允许你记录特定消息 而Assert方法允许你在特定的条件为假的情况下记录一条消息 Trace类将消息输出到Listeners集合中的对象 这个集合中的每个对象都属于继承自TraceListener的一个类 EventLogTraceListener 将消息写入事件记录 而TextWriterTraceListener则是将消息写入到一个文本文件中 默认情况下 DefaultTraceListener的一个实例被添加到Trace类的Listeners集合中 除了标准的监听程序以外 你可以实施自己跟踪监听程序 例如 你希望接收来自在防火墙后面的远程机器上运行的应用程序的跟踪输出 你可以编写一个跟踪监听程序 通过HTTP全球向你的服务器发送跟踪消息 这将会影响你的应用程序的性能 但只会在启用跟踪时才会对性能有所影响 代表性地 你需要有能力在编译的二进制文件中包括或去除跟踪代码 为了在Visual Basic 中做到这一点 你需要使用编译常量 并在#If语句中包含所有的跟踪代码 这使得代码很难理解和维护 利用 NET Framework 你只需在项目属性(Project Properties)对话框中将TRACE编译常量设为on或off状态 你无需在#If语句中包括跟踪代码 另一个普遍期望的跟踪特性是跟踪水平设置 这包括不同的跟踪设置 例如 Severe(严重) Error(错误) Warning(警告)和Information(信息) 这些设置对记录哪些信息进行控制 你可以使用跟踪组件启动时所读取的注册表数值对此进行控制 对于 NET Framework 这是完全内置的功能 你可以设置一个注册表数值来控制你当前的应用程序的记录水平 比如 只有在跟踪水平被设置为Severe(严重)的情况下 才使用Trace WriteIf和Trace WriteLineIf来记录消息 集成的跟踪和记录特性极大地增强了生产力 因为你只需使用内置的特性 将精力集中在编 *** 正的应用程序代码上
多线程应用程序 NET Framework的一个很重要的特性是 可以在不使用第三方工具或不支持的Visual Basic技巧情况下 使用Visual Basic创建多线程应用程序 NET Framework的多线程支持是由System Threading名称空间中的类和接口提供的 因此所有的 NET语言都能够以相同的方式创建和处理线程 System Threading Thread是一个核心类 提供了对创建和控制线程的支持 要创建一个线程 你可以创建一个新的System Threading Thread对象 将构造函数传递给ThreadStart代理 这个代理提供了这个线程开始执行的方法 当你准备启动这个新的线程时 可以调用Thread Start() (请参阅清单 ) 当你开始创建多线程应用程序时 你很快就会认识到需要控制对共享资源的访问 如共享的类变量 NET Framework还包括几个类和数据类型 你可以使用它们对两个线程执行的动作进行同步 在最简单的情况中 你由一个需要从不同的线程中进行更新的共享变量 要这样做 你可以使用System Threading Interlocked类 例如 你可以通过编写Interlocked Increment(num)或Interlocked Decrement(num)分别使名为num的共享变量递增或递减 你还可以使用Interlocked将变量设为某一特定值 或检查两个变量是否相等 除了这种简单情况以外 你可以使用 NET Framework类来执行更复杂的线程同步 如事件和互斥体的同步 所有都来自于 NET Framework内部 而无须使用Win API Imports System IO注释 The namespace System Threading注释 contains the Thread classImports System ThreadingModule Module Private count As LongSub Main()注释 Create the ThreadStart delegateDim tStart As ThreadStart = New _ ThreadStart(AddressOf StartCounting)注释 Create the threadDim t As Thread = New Thread(tStart)Console WriteLine( Enter q to quit )t Start() 注释 start the threadWhile (Console Read() asc( q ))注释 repeat the loop until the user enters qEnd Whilet Stop() 注释 tell thread to stop processingt Join() 注释 wait until the thread finishesEnd SubSub StartCounting()Do注释 use Interlocked Increment in case 注释 another thread is accessing the same variableInterlocked Increment(count)Console WriteLine( _ After incrementing count is : count)Thread Sleep( )LoopEnd SubEnd Module 清单 使用Visual Basic NET创建线程 你创建了一个新线程 将它传递给一个ThreadStart代理 然后调用Thread Start()启动这个线程 你可以通过调用Thread Stop()来中止这个线程 然后调用Thread Join()等待它完成关闭操作 一个线程可以使用System Threading Interlocked来使变量递增或递减 此外 NET Framework提供了一个方便的机制来对工作排队 并将起分配给线程池中的某个线程 在处理多个并发工作项目或工作请求的服务器应用程序中 这非常有用 例如 对于等待输入文件 然后将它们导入到数据库中去的应用程序 可能会对每个输入文件进行排队 以在线程池中的某个单独的线程上进行处理 System Threading ThreadPool类允许你使用共享的QueueUserWorkItem方法对工作进行排队 以前要这样做 你必须得创建和管理自己的线程池 你又需要在基础设施工作而不是在解决商务问题上花大量的时间和精力 文件系统监控 我曾经遇到过一些应用程序 需要等待和处理某个特定目录中的文件 例如 将数据从文件导入到数据库中去的应用程序 数据文件可以从某个大型机上下载 或者被转移到某个输入目录中 该应用程序将它们导入到数据库中 你不用经常地轮询该目录检查是否有新文件 可以等待生成新文件的通知 你可以在Visual Basic 中使用Win API来做到这一点 而在Visual Basic NET中你可以使用 NET Framework类来做这项工作 但是在 NET中实施文件监控与在 NET中完成其他工作的方法更加一致 因此学习曲线是最小的 你可以使用System IO FileSystemWatcher NET类对文件系统进行监视 它提供了一些属性 允许你设置监控的路径 指定是对文件还是子目录层次的变化感兴趣 System IO FileSystemWatcher还允许你指定需要监控的文件名和文件类型(例如 * xml是指监控所有XML文件的变化) 最后 你可以指定感兴趣的变化类型 例如 只对新建文件 文件属性的变化或文件大小的变化(请参阅清单 )感兴趣 在你设置了监控内容后 你需要钩住用于感兴趣的各种事件的事件处理程序 FileSystemWatcher事件有Changed Created Deleted Error和Renamed 要处理某个事件 首先你需要编写一个与FileSystemEventHandler代理相同声明的事件处理程序 然后将这个处理程序添加到FileSystemWatcher类中 这个基于代理的体系结构允许你为同一个事件添加多个处理程序 或者对于多个事件使用同一个处理程序 而你不能使用Visual Basic 做到这一点 注释 System IO contains the 注释 file monitoring classes and typesImports System IOModule Module Sub Main() 注释 FileSystemWatcher does the real work Dim fw As New FileSystemWatcher() 注释 WaitForChangedResult is what you 注释 get back when a change occurs Dim result As WaitForChangedResult 注释 set the path to monitor fw Path = C:WINNT 注释 tell it whether to watch files or directories fw Target = WatcherTarget File 注释 tell it whether to include subdirs fw IncludeSubdirectories = False 注释 hook up handlers AddHandler fw Created New FileSystemEventHandler(AddressOf OnFileNotify) 注释 enable the watcher fw Enabled = True DoConsole WriteLine( Beginning to monitor ) 注释 this is where we actually wait注释 waiting blocks execution for the specified timeoutresult = fw WaitForChanged(WatcherChangeTypes All )Console WriteLine( Hit Enter to continue q to quit ) Loop While (Console ReadLine q )End Sub注释 This is the delegate that gets 注释 called when a file is created Public Sub OnFileNotify(ByVal source As Object ByVal e As FileSystemEventArgs)Console WriteLine( Notification received for file change type is _e FullPath e ChangeType) End SubEnd Module 清单 使用FileSystemWatcher监控某个文件夹是否有新文件
lishixinzhi/Article/program/net/201311/11618
.NET平台下几种SOCKET模型的简要性能供参考
1.Socket + Threads/ThreadPool大概性能:小于1500个连接 实现:Accept一个Socket,就交给一个线程去管理,比较笨,但也比较有效,因为是同步方式,控制起来很方便。高级点的,就是交给一个线程池去管理,线程池由系统自动托管,省去了开销线程的时间。一般小型项目,用这个完全足够,开发也简单。但要注意,如果若干Socket长时间占用线程池中的线程,同时其它连接数又比较多,很容易出现提示说你没有足够的线程供使用。呵呵,让Socket少做点事,少占用时间,换一个快点的CPU是不错的方式。另外,如果有一些比较好的第三方线程池组件,也可以选择使用,比如SmartThreadPool。2.Socket + Select大概性能:大于1500个连接后性能下降 实现:Select是很常用的一种模型。是在阻塞功能中轮询一个或多个Socket,将要处理的Socket放到一个IList中,当Select轮询结束后,然后我们再自己处理这个IList中的Socket。具体的用法可以看一下MSDN。Select的效率并不能说是高的,因为当队列中待处理的Socket比较多的时候,处理最后几个Socket相当于要遍历所有前面的Socket,非常不划算的.3.Socket + Asynchronous大概性能:约7500个客户端连接 实现:BeginXXXX,EndXXXX,再熟悉不过了吧。异步Socket归根到底,还是用的线程池技术,用线程池来处理异步IO。这就又引出个问题,.NET的线程池又是用的什么实现方式,以前看过有人说,.NET的线程池是用的完成端口来实现的,我不知道这样的说法是不是正确,从查到的资料中也没有办法确认(希望这点有朋友可以告诉我)。异步Socket对于程序的处理流程来说比同步复杂了许多,异步回调函数的控制不如同步方式那样直观。但有一点我想应该是要注意的,就是回调函数应该轻装上阵,不应该处理过多的事务,对传递数据的处理,应该交给其它线程进行处理。 4.IOCP(完成端口)大概性能:约20000~50000个客户端连接 实现:现在.NET下有一些伪IOCP,大家可以去搜索一下,还没有见过开放出来的用这些伪IOCP来实现的SOCKET例子。我说的20000~50000个客户端连接,是指在C++下开发的情况,这样的情况下,需要用到的基本技术还包括内存池、查询算法等。伪IOCP能实现多少最大连接,没有资料可以查,如果有朋友知道,可以讨论一下。另外上 面提到的许多数据,是从一些资料上摘抄下来的,我没有自己试过,仅仅是拿出来和大家讨论一下。1. Introduction - Native Win32 IOCPI/O Completion Ports (IOCP) supported on Microsoft Windows platforms has two facets. It first allows I/O handles like file handles, socket handles, etc., to be associated with a completion port. Any async I/O completion event related to the I/O handle associated with the IOCP will get queued onto this completion port. This allows threads to wait on the IOCP for any completion events. The second facet is that we can create a I/O completion port that is not associated with any I/O handle. In this case, the IOCP is purely used as a mechanism for efficiently providing a thread-safe waitable queue technique. This technique is interesting and efficient. Using this technique, a pool of a few threads can achieve good scalability and performance for an application. Here is a small example. For instance, if you are implementing a HTTP server application, then you need to do the following mundane tasks apart from the protocol implementation:Create a client connection listen socket. Once we get the client connection, use the client socket to communicate with the client to and fro. You can implement it by creating one dedicated thread per client connection that can continuously communicate with the client to and fro. But this technique quickly becomes a tremendous overhead on the system, and will reduce the performance of the system as the number of simultaneous active client connections increase. This is because, threads are costly resources, and thread switching is the major performance bottle neck especially when there are more number of threads.The best way to solve this is to use an IOCP with a pool of threads that can work with multiple client connections simultaneously. This can be achieved using some simple steps...Create a client connection listen socket. Once we get the client connection, post an IOCP read message on the socket to an IOCP. One of the threads waiting for completion events on this IOCP will receive the first read message for the client. It immediately posts another read onto the same IOCP and continues processing the read message it got. Once processing the read message is completed, it again waits on the IOCP for another event. This technique will allow a small pool of threads to efficiently handle communication with hundreds of client connections simultaneously. Moreover, this is a proven technique for developing scalable server side applications on Windows platforms.The above is a simplified description of using IOCP in multithreaded systems. There are some good in-depth articles on this topic in CodeProject and the Internet. Do a bit of Googling on words like IO Completion Ports, IOCP, etc., and you will be able to find good articles.2. Introduction - Managed IOCPManaged IOCP is a small .NET class library that provides the second facet of Native Win32 IOCP. This class library can be used both by C# and VB.NET applications. I chose the name Managed IOCP to keep the readers more close to the techniques they are used to with native Win32 IOCP. As the name highlights, Managed IOCP is implemented using pure .NET managed classes and pure .NET synchronization primitives. At its core, it provides a thread-safe object queuing and waitable object receive mechanism. Apart from that, it provides a lot more features. Here is what it does:Multiple Managed IOCP instances per process. Registration of multiple threads per Managed IOCP instance. Dispatching System.Object types to a threadsafe queue maintained by each Managed IOCP instance. Waitable multi-thread safe retrieval of objects from the Managed IOCP instance queue by all the threads registered for that particular Managed IOCP instance. Ability to restrict the number of concurrent active threads processing the queued objects related to a particular Managed IOCP instance. Policy based replaceable/customizable approach for choosing a registered thread to process the next available queued object. Ability to pause the Managed IOCP processing. Internally, pauses processing of queued objects by registered threads. Also, by default, disallows enqueuing new objects (can be changed). Run the Managed IOCP instance. Internally re-starts the processing of queued objects by registered threads. Also allows enqueuing new objects (if it is disallowed previously). Modify the max. allowed concurrent threads at runtime. Provides easy accessibility to Managed IOCP instance runtime properties like... Number of active concurrent threads. Number of objects left in queue. Number of allowed concurrent threads. Running status. Safe and controlled closing of a Managed IOCP instance. 2.1. Managed IOCP in Job/Task Oriented Business ProcessesManaged IOCP can be used in other scenarios apart from the sample that I mentioned in the introduction to native Win32 IOCP. It can be used in process oriented server side business applications. For instance, if you have a business process ( _not_ a Win32 process) with a sequence of tasks that will be executed by several clients, you will have to execute several instances of the business process, one for each client in parallel. As mentioned in my introduction to native Win32 IOCP, you can achieve this by spawning one dedicated thread per business process instance. But the system will quickly run out of resources, and the system/application performance will come down as more instances are created. Using Managed IOCP, you can achieve the same sequential execution of multiple business process instances, but with fewer threads. This can be done by dispatching each task in a business process instance as an object to Managed IOCP. It will be picked up by one of the waiting threads and will be executed. After completing the execution, the thread will dispatch the next task in the business process instance to the same Managed IOCP, which will be picked up by another waiting thread. This is a continuous cycle. The advantage is that you will be able to achieve the sequential execution goal of a business process, as only one waiting thread can receive a dispatched object, and at the same time keep the system resource utilization to required levels. Also, the system and business process execution performance will increase as there are few threads executing multiple parallel business processes.3. Using Managed IOCP in .NET applicationsMultithreaded systems are complex in the context that most problems will show up in real time production scenarios. To limit the possibility of such surprises while using Managed IOCP, I created a test application using which several aspects of the Managed IOCP library can be tested. Nevertheless, I look forward for any suggestions/corrections/inputs to improve this library and its demo application.Before getting into the demo application, below is the sequence of steps that an application would typically perform while using the Managed IOCP library:Create an instance of the ManagedIOCP class: 2. using Sonic.Net;ManagedIOCP mIOCP = new ManagedIOCP();The ManagedIOCP constructor takes one argument, concurrentThreads. This is an integer that specifies how many maximum concurrent active threads are allowed to process objects queued onto this instance of ManagedIOCP. I used a no argument constructor, which defaults to a maximum of one concurrent active thread.From a thread that needs to wait on objects queued onto the ManagedIOCP instance, call the Register() method on the ManagedIOCP instance. This will return an instance of the IOCPHandle class. This is like native Win32 IOCP handle, using which the registered thread can wait on the arrival of objects onto the ManagedIOCP instance. This thread can use the Wait() method on the IOCPHandle object. The Wait() will indefinitely wait until it grabs an object queued onto the ManagedIOCP instance to which the calling thread is registered. It either comes out with an object, or an exception in case the ManagedIOCP instance is stopped (we will cover this later). 4. IOCPHandle hIOCP = mIOCP.Register();5. while(true)6. {7. try8. {9. object obj = hIOCP.Wait();10. // Process the object11. 12. }13. catch(ManagedIOCPException e)14. {15. break;16. }17. catch(Exception e)18. {19. break;20. }}Any thread (one that is registered with the ManagedIOCP instance and any non-registered thread) that has access to the ManagedIOCP instance can dispatch (Enqueue) objects to it. These objects are picked up by waiting threads that are registered with the ManagedIOCP instance onto which objects are being dispatched. 22. string str = "Test string";mIOCP.Dispatch(str);When a thread decides not to wait for objects any more, it should un-register with the ManagedIOCP instance. mIOCP.UnRegister();Once the application is done with an instance of ManagedIOCP, it should call the Close() method on it. This will release any threads waiting on this instance of ManagedIOCP, clears internal resources, and resets the internal data members, thus providing a controlled and safe closure of a ManagedIOCP instance. mIOCP.Close();There are certain useful statistics that are exposed as properties in the ManagedIOCP class. You can use them for fine tuning the application during runtime.// Current number of threads that are // concurrently processing the objects queued // onto this instance of Managed IOCP // (This is readonly property) int activeThreads = mIOCP.ActiveThreads;// Max number of concurrent threads // allowed to process objects queued onto this // instance of Managed IOCP (This is a read/write property) int concurThreads = mIOCP.ConcurrentThreads;// Current count of objects queued onto this Managed IOCP instance. // NOTE: This value may change very quickly // as multiple concurrent threads might // be processing objects from this instance of Managed IOCP queue. // So _do not_ depend on this value // for logical operations. Use this only for // monitoring purpose (Status reporting, etc.) // and during cleanup processes // (like not exiting main thread untill the queued object becomes 0, // i.e. no more objects to be processed, etc) // (This is readonly property) int qCount = mIOCP.QueuedObjectCount;// Number of threads that are registered with this instance of Managed IOCP // (This is readonly property) int regThreadCount = mIOCP.RegisteredThreads;3.1. Advanced usageFollowing are the advanced features of Managed IOCP that need to be used carefully.Managed IOCP execution can be paused at runtime. When a Managed IOCP instance is paused, all the threads registered with this instance of Managed IOCP will stop processing the queued objects. Also, if the 'EnqueueOnPause' property of the ManagedIOCP instance is false (by default, it is false), then no thread will be able to dispatch new objects onto the Managed IOCP instance queue. Calling Dispatch on the ManagedIOCP instance will throw an exception in the Pause state. If the 'EnqueueOnPause' property is set to true, then threads can dispatch objects onto the queue, but you need to be careful while setting this property to true, as this will increase the number of pending objects in the queue, thus occupying more memory. Also, when the Managed IOCP instance is re-started, all the registered threads will suddenly start processing a huge number of objects thus creating greater hikes in the system resource utilization.mIOCP.Pause();Once paused, the ManagedIOCP instance can be re-started using the Run method.mIOCP.Run();The running status of the Managed IOCP instance can be obtained using the IsRunning property:bool bIsRunning = mIOCP.IsRunning;You can retrieve the System.Threading.Thread object of the thread associated with the IOCPHandle instance, from its property named 'OwningThread'.3.2. Demo ApplicationI provided two demo applications with similar logic. The first is implemented using Managed IOCP, the other using native Win32 IOCP. These two demo applications perform the following steps:Create a global static ManagedIOCP instance or native Win32 IOCP. Create five threads. Each thread will dispatch one integer value at a time to the ManagedIOCP instance or native Win32 IOCP until the specified number of objects are completed. Start (creates a new set of five threads) and stop (closes the running threads) the object processing. The Sonic.Net (ManagedIOCP) demo application additionally demonstrates the following features of Managed IOCP that are unavailable in the Win32 IOCP:Pause and continue object processing during runtime. Change concurrent threads at runtime. Statistics like, Active Threads, Maximum Concurrent threads, Queued Objects Count and Running Status of Managed IOCP. Below is the image showing both the demo applications after their first cycle of object processing:Demo application resultsAs you can see in the above figure, Managed IOCP gives the same speed (slightly even better) as native Win32 IOCP. The goal of these two demo applications is _not_ to compare the speed or features of Win32 IOCP with that of Managed IOCP, but rather to highlight that Managed IOCP provides all the advantages of native Win32 IOCP (with additional features) but in a purely managed environment.I tested these two demo applications on a single processor CPU and a dual processor CPU. The results are almost similar, in the sense the Managed IOCP is performing as good as (sometimes performing better than) native Win32 IOCP.3.3. Source and demo application filesBelow are the details of the files included in the article's Zip file:Sonic.Net (folder) - I named this class library as Sonic.Net (Sonic stands for speed). The namespace is also specified as Sonic.Net. All the classes that I described in this article are defined within this namespace. The folder hierarchy is described below: 2. Sonic.Net3. |4. -- Assemblies5. |6. -- Solution Files7. |8. -- Sonic.Net9. |10. -- Sonic.Net Console Demo 11. |-- Sonic.Net Demo ApplicationThe Assemblies folder contains the Sonic.Net.dll (contains the ObjectPool, Queue, ManagedIOCP, IOCPHandle, and ThreadPool classes), Sonic.Net Demo Application.exe (demo application showing the usage of ManagedIOCP and IOCPHandle classes), and Sonic.Net Console Demo.exe (console demo application showing the usage of ThreadPool and ObjectPool classes).The Solution Files folder contains the VS.NET 2003 solution file for the Sonic.Net assembly project, Sonic.Net demo application WinForms project, and Sonic.Net console demo project.The Sonic.Net folder contains the Sonic.Net assembly source code.The Sonic.Net Console Demo folder contains the Sonic.Net console demo application source code. This demo shows the usage of the Managed IOCP ThreadPool, which is explained in my Managed I/O Completion Ports - Part 2 article. This demo uses a file that will be read by the ThreadPool threads. Please change the file path to a valid one on your system. The code below shows the portion in the code to change. This code is in the ManagedIOCPConsoleDemo.cs file.public static void ReadData(){ StreamReader sr = File.OpenText(@"C:\aditya\downloads\lgslides.pdf"); string st = sr.ReadToEnd(); st = null; sr.Close(); Thread.Sleep(100);}The Sonic.Net Demo Application folder contains the Sonic.Net demo application source code.Win32IOCPDemo (folder) - This folder contains the WinForms based demo application for demonstrating Win32 IOCP usage using PInvoke. When compiled, the Win32IOCPDemo.exe will be created in the Win32IOCPDemo\bin\debug or Win32IOCPDemo\bin\Release folder based on the current build configuration you selected. The default build configuration is set to Release mode. 4. Inside Managed IOCPThis section discusses the how and why part of the core logic that is used to implement Managed IOCP.4.1. Waiting and retrieving objects in Managed IOCPManaged IOCP provides a thread safe object dispatch and retrieval mechanism. This could have been achieved by a simple synchronized queue. But with synchronized queue, when a thread (thread-A) dispatches (enqueues) an object onto the queue, for another thread (thread-B) to retrieve that object, it has to continuously monitor the queue. This technique is inefficient as thread-B will be continuously monitoring the queue for arrival of objects, irrespective of whether the objects are present in the queue. This leads to heavy CPU utilization and thread switching in the application when multiple threads are monitoring the same queue, thus degrading the performance of the system.Managed IOCP deals with this situation by attaching an auto reset event to each thread that wants to monitor the queue for objects and retrieve them. This is why any thread that wants to wait on a Managed IOCP queue and retrieve objects from it has to register with the Managed IOCP instance using its 'Register' method. The registered threads wait for the object arrival and retrieve them using the 'Wait' method of the IOCPHandle instance. The IOCPHandle instance contains an AutResetEvent that will be set by the Managed IOCP instance when any thread dispatches an object onto its queue. There is an interesting problem in this technique. Let us say that there are three threads, thread-A dispatching the objects, and thread-B and thread-C waiting on object arrival and retrieving them. Now, say if thread-A dispatches 10 objects in its slice of CPU time. Managed IOCP will set the AutoResetEvent of thread-B and thread-C, thus informing them of the new object arrival. Since it is an event, it does not have an indication of how many times it has been set. So if thread-B and thread-C just wake up on the event set and retrieve one object each from the queue and again waits on the event, there would be 8 more objects left over in the queue unattended. Also, this mechanism would waste the CPU slice given to thread-B and thread-C as they are trying to go into waiting mode after processing a single object from the Managed IOCP queue.So in Managed IOCP, when thread-B and thread-C call the 'Wait' method on their respective IOCPHandle instances, the method first tries to retrieve an object from the Managed IOCP instance queue before waiting on its event. If it was able to successfully retrieve the object, it does
当前题目:vb.net中轮询 vbnet console
链接分享:http://azwzsj.com/article/doihjdp.html