串口通信控件 Prepared on 22 November 2020
附录A串行通信控件MSComm
在VisualStudio(、VC++.NET、C#.NET)中编写串口通讯程序,一般都使用MicrosoftCommunicationControl(简称MSComm)的通讯控件,只要通过对此控件的属性和事件进行相应编程操作,就可以轻松地实现串口通讯。但在技术广泛应用的今天,VisualStudio没有将此控件加入控件库,所以人们采用了3种方法在VisualStudio中编写串口通讯程序:第一种方法是通过采用原来的MSComm控件,这是最简单的,最方便的方法,但需要注册(可以通过安装或VC++来实现);第二种方法是采用微软在.NET中推出的一个串口控件SerialPort,方便地实现所需要串口通讯的多种功能;第三种方法是用API函数进行串口通信,虽然难度高,但可以方便实现自己想要的各种功能。
一、MScomm控件的使用
MSComm控件全称为MicrosoftCommunicationsControl,是Microsoft公司提供的简化Windows下串行通信编程的ActiveX控件,它既可以用来提供简单的串行端口通信功能,也可以用来创建功能完备的、事件驱动的高级通信工具。
MSComm控件在串口编程时非常方便,程序员不必花时间去了解较为复杂的API函数,而且在、VC++.NET、C#.NET等语言中均可使用。使用它可以建立与串行端口的连接,通过串行端口连接到其它通信设备(例如调制解调器),发出命令,交换数据,以及监视和响应串行连接中发生的事件和错误。利用它可以进行诸如拨打电话、监视串行端口的输入数据乃至创建功能完备的终端程序等。
1.MSComm控件处理通信的方式
MSComm控件通过串行端口传输和接收数据,为应用程序提供串行通信功能。
它提供下列两种处理通信的方式:
1)事件驱动方式
该方式相当于一般程序设计中的中断方式。当串口发生事件或错误时,MSComm控件会产生OnComm事件,用户程序可以捕获该事件进行相应处理。它是处理串行端口交互作用的一种非常有效的方法。在许多情况下,在事件发生时程序会希望得到通知,例如,在串口接收缓冲区中有一个字符到达或一个变化发生时,程序都可以利用MSComm控件的OnComm事件捕获并处理这些通信事件;OnComm事件还可以检查和处理通信错误。在程序的每个关键功能之后,可以通过检查CommEvent属性的值来查询事件和错误。
在程序设计中,可以在OnComm事件处理函数中加入自己的处理代码,一旦事件发生即可自动执行该段程序。这种方法的优点是程序响应及时,可靠性高。
2)查询方式
在程序的每个关键功能之后,在用户程序中设计定时或不定时的查询,通过检查CommEvent 属性的值来查询事件和错误,从而作出相应的处理。在进行简单应用程序设计时可采用这种方法。例如,如果写一个简单的电话拨号程序,则没有必要对每接收一个字符都产生事件,因为唯一等待接收的字符是调制解调器的“OK ”响应。
查询方式的进行可用计时器Timer 或Do…Loop 程序实现。查询方式实质上还是事件驱动,但在有些情况下,这种方式显得更为便捷。
2.MSComm 控件的引用
开始一个项目的设计时,、VC++.NET 、C#.NET 的工具箱中会有许多默认的控件让设计者选用,这些原本就出现在工具箱中的控件是内置控件,它提供了一些基本的系统设计组件给设计者,不过,功能比较特别的控件就不会出现在其中,而用来设计通信功能的控件MSComm 就不在其中。
由于、VC++.NET 、C#.NET 的串行通信组件MSComm 并不会主动出现在工具箱里中,当我们需要MSComm 控件时,首先要把它加入到工具箱中。
让MSComm 控件出现在工具箱中的步骤如下:
执行“工具”菜单下的“选择工具箱…”子菜单,在弹出的对话框中,选择
“COM 组件”选项卡,选中“MicrosoftCommunicationControlversion6.0”复选框,如图A-1所示,单击“确定”按钮后,在工具箱“组件”栏中就出现了一个形似“电话”的图标,它就是MSComm 控件,如图A-2所示。
工具箱中有了MSComm 控件,就可以选择
MSComm 控件的图标后将其加到程序窗体上,利
用该控件PC 机就可以通过、VC++.NET 、C#.NET
实现与串口设备的串口通信了。
如果打开的是以前的项目,项目中含有
MSComm 控件的引用记录,则项目会自动去搜寻
MSComm 控件,并将它载入,不需要以上的步
骤。
每个使用的MSComm 控件对应着一个串行端
口,如果应用程序需要访问多个串行端口,必须使
用多个MSComm 控件。
3.MSComm 控件的常用属性 MSComm 控件的属性很多,这里介绍串口编程中经常用到的几个重要属性。
1)CommPort 属性
语法:[=Value]
作用:设置或返回通信端口号。
CommPort 属性值value 可以设置为1到16之间的任何整数值(缺省值为1)表示串口COM1,COM2...。如果用PortOpen 属性打开一个并不存在的端口,MSComm 控件会产生错误68(设备无效)。
图A-1
添加MSComm 控件 图A-2工具箱中的MSComm 控件
注意:必须在打开端口之前设置CommPort属性。
例如:COM2上连接有一个调制解调器:=2
2)Input属性
语法:
作用:返回并删除接收缓冲区中的数据流。
InputLen属性确定被Input属性读取的字符数。设置InputLen为0,则Input属性读取缓冲区中全部的内容。
例如:如果希望从接收缓冲区获取数据,并将其显示在一个文本框中,可以使用下面的代码:=
该属性在设计时无效,在运行时为只读。
3)InputLen属性
语法:[=value]
作用:设置并返回Input属性从接收缓冲区读取的字符数。
Value是整型表达式,说明Input属性从接收缓冲区中读取的字符数。
说明:InputLen属性的缺省值是0。设置InputLen为0时,使用Input将使MSComm 控件读取接收缓冲区中全部的内容。若接收缓冲区中InputLen字符无效,Input属性返回一个零长度字符串("")。在使用Input前,用户可以选择检查InBufferCount属性来确定缓冲区中是否已有需要数目的字符。该属性在从输出格式为定长数据的机器读取数据时非常有用。如果读取以定长的数据块的形式格式化了的数据时,则需要将该属性设置为合适的值。
例如:=10'当程序执行该指令时,只会读取10个字符。
4)InputMode属性
语法:[=Value]
作用:设置或返回接收数据的数据类型。
InputMode属性的Value值可以设置为如下常数:
0-通过Input属性以文本方式取回传入的数据。
1-通过Input属性以二进制方式取回传入的数据。
例如:=1表示以二进制方式读取数据。
5)OutPut属性
语法:[=Value]
作用:向传输缓冲区写数据流。
Output属性可以传输文本数据或二进制数据。用Output属性传输文本数据,必须定义一个包含一个字符串的Variant;发送二进制数据,必须传递一个包含字节数组的Variant到Output属性。
正常情况下,如果发送一个ANSI字符串到应用程序,可以以文本数据的形式发送;如果发送包含嵌入控制字符、Null字符等数据,要以二进制形式发送。
可用Output属性发送命令、文字字符串或Byte数组数据。
例如:="ATDT551-5555"'发送AT命令串
="Thisisatextstring"'发送文本字符串
该属性在设计时无效,在运行时为只读。
6)PortOpen属性
语法:[=Value]
作用:设置或返回通信端口的状态。
设置PortOpen属性为True即打开端口,设置为False则关闭端口,并清除接收和传输缓冲区。当应用程序终止时,MSComm控件自动关闭串行端口。
在打开端口之前,确定CommPort属性设置为一个合法的端口。如果CommPort属性设置为一个非法的端口,则当打开该端口时,MSComm控件产生错误68(设备无效)。
串行端口设备必须支持Settings属性当前的设置值。如果Settings属性包含硬件不支持的通信设置值,硬件可能不会正常工作。
7)Settings属性
语法:[=Value]
作用:设置并返回通信参数。
值Value为String型,说明通信端口的设置值。
Settings属性可以用来指定波特率、奇偶校验、数据位数和停止位数。奇偶校验设置为了进行数据校验,通常是不用的,并设置为“N”。数据位数指定了代表一个数据块的比特数。停止位指出了何时接收到一个完整数据块。
例如:="9600,N,8,1"'表示传输速率为9600bps,没有奇偶校验位,8位数据位,1位停止位。
注:1)起始位:在通信线上,没有数据传送时处于逻辑“1”状态。当发送设备要发送一个字符数据时,首先发出一个逻辑“0”信号,这个逻辑低电平就是起始位。起始位通过通信线传向接收设备,当接收设备检测到这个逻辑低电平后,就开始准备接收数据位信号。因此,起始位所起的作用就是表示字符传送的开始。
2)数据位:当接收设备收到起始位后,紧接着就会收到数据位,数据位的个数可以是5、6、7或8位数据。在字符数据传送的过程中,数据位从最低有效位开始传送。
3)奇偶校验位:数据位发送完之后,就可以发送奇偶校验位。奇偶校验用于有限差错检验,通信双方在通信时约定一致的奇偶校验方式。就数据传送而言,奇偶校验位是冗余位,但它表示数据的一种性质,这种性质用于检错,虽然有限但很容易实现。
4)停止位:在奇偶校验位或者数据位(无奇偶校验位时)之后是停止位。它可以是1位、位或2位,停止位是一个字符数据的结束标志。
8)RThreshold属性
语法:[=value]
作用:OnComm事件发生之前,设置并返回接收缓冲区可接收的字符数。
Value是整型表达式,说明在产生OnComm事件之前要接收的字符数。
当接收字符后,若Rthreshold属性设置为0(缺省值)则不产生OnComm 事件;设置Rthreshold为1,接收缓冲区每收到一个字符都会使MSComm控件触发OnComm事件。
9)SThreshold属性
语法:[=value]
作用:OnComm事件发生之前,设置并返回发送缓冲区中允许的最小字符数。
Value是整形表达式,代表在OnComm事件产生之前在传输缓冲区中的最小字符数。
若设置SThreshold属性为0(缺省值),数据传输事件不会产生OnComm 事件;若设置Sthreshold属性为1,当传输缓冲区完全空时,MSComm控件产生OnComm事件。如果在传输缓冲区中的字符数小于value,CommEvent属性设置为comEvSend,并产生OnComm事件。
OnComm事件被用来监视和响应通信状态的变化。如果将Rthreshold和SThreshold属性的值都设置为零,就可以避免发生OnComm事件。如果将该值设置为非零的值(比如1),那么每当缓冲区中接收到一个字符时,就会产生OnComm事件。
10)DTREnable属性
语法:[=value]
作用:确定在通信时是否使DTR线有效。
DTR是计算机发送到调制解调器的信号,指示计算机在等待接收传输。当DTREnable 设置为True,当打开端口时,DTR线设置为高电平(开),当端口被关闭时,DTR线设置为低电平(关);当DTREnable设置为False,DTR线始终保持为低电平。
11)RTSEnable属性
语法:[=value]
作用:确定是否使RTS线有效。
通常由计算机发送RTS信号到调制解调器,以请求允许发送数据。当RTSEnable设置为True,且端口打开时,RTS线设置为高电平,端口关闭时,RTS线设置为低电平。当RTSEnable设置为False,RTS线始终保持为低电平。
12)OutBufferSize属性
语法:[=Value]
作用:设置或返回传输缓冲区大小。
值Value为Integer型,表示传输缓冲区的字节数,例如可选1024。
13)InBufferSize属性
语法:[=Value]
作用:设置或返回接收缓冲区大小。
值Value为Integer型,表示接收缓冲区的字节数,例如可选1024。
InBufferSize和OutBufferSize属性指定了为接收和发送缓冲区分配的内存数量。这两个值设置得越大,应用程序中可用的内存就越少。然而,如果缓冲区太小,就要冒缓冲区溢出的风险,除非采用握手信号。
由于现在大多数微机有更多的可用内存资源,缓冲区内存分配已不那么至关紧要了。换言之,可以把缓冲区的值设得高一些而不影响应用程序的性能。
14)Handshaking属性
语法:[=Value]
作用:设置或返回硬件握手协议。指的是PC机与MODEM之间为了控制流速而约定的内部协议。Value值:
0-comNone没有握手协议。不考虑流量控制。
1-comXOn/XOff,即在数据流中嵌入控制符来进行流量控制。
1-comRTS,即由信号线RTS自动进行流量控制。
1-comRTSXOnXOff,两者皆可。
注:实践中我们发现选用2(即comRTS)是很方便的。
说明:要保证数据传输成功,必须对接收和发送缓冲区进行管理,例如,要保证接收数
据的速度不超出缓冲区的限制。握手是指一种内部的通信协议,通过它将数据从硬件端口传输到接收缓冲区。当串行端口收到一个字符时,通信设备必须将它移入接收缓冲区中,使程序能够读到它。如果数据到达端口的速度太快,通信设备可能来不及将数据移入接收缓冲区,握手协议保证不会由于缓冲区溢出而导致丢失数据。
需要使用什么协议与连接的设备有关。如果将该值设置为comRTSXOnXOff,可以同时支持两种协议。
4.MSComm控件的OnComm事件
根据应用程序的用途和功能,在连接到其它设备过程中,以及接收或发送数据过程中,可能需要监视并响应一些事件和错误。
可以使用OnComm事件和commEvent属性捕捉并检查通信事件和错误的值。
commEvent属性返回最近的通信事件或错误,该属性在设计时无效,在运行时为只读。
在发生通信事件或错误时,将触发OnComm事件,CommEvent属性的值将被改变。因此,在发生OnComm事件的时候,如果有必要,可以检查CommEvent属性的值。由于通信(特别是通过电话线的通信)是不可预料的,捕捉这些事件和错误将有助于使应用程序对这些情况作出相应的反应。
MSComm控件把十七个事件归并为一个事件OnComm,用属性CommEvent的十七个值来区分不同的触发时机。
表A-1列出了几个可能触发OnComm事件的通信事件,对应的值将在发生事件时被写入CommEvent属性。
另外十个情况是可能发生的各种通信错误时触发,可参看有关资料。
通过事件的引发,借由CommEvent属性值的数值便可明确了解所发生的错误或事件,而程序中通常就以常数定义作为判断,一旦OnComm事件发生,连带地会引入CommEvent参数,用户可以在每一个相关的Case语句之后编写程序代码来处理特定的错误或事件。
5.MSComm控件通信步骤
通常我们以下面的步骤来使用MSComm控件作通信控制:
1)加入通信部件,也就是MSComm对象;
2)设置通信端口号码,即CommPort属性;
3)设置通信协议,即HandShaking属性;
4)设置传输速度等参数,即Settings属性;
5)设置其它参数,若必要时再加上其它的属性设置;
6)打开通信端口,即PortOpen属性设成True;
7)送出字符串或读入字符串,使用Input及Output属性;
8)使用完MSComm通信对象后,将通信端口关闭。即PortOpen属性设成False。
遵循以上的步骤,可以建构自己的串行通信传输系统了。
附录B串行通信控件SerialPort
在VisualStudio(、VC++.NET、C#.NET)平台下熟练使用SerialPort控件,可以很好地开发出串口通讯类程序,对于过去使用MSComm控件设计了一些通讯程序,也可以将MSComm控件替换为SerialPort控件,当然为了避免对以前的项目做大的改动,可以使用SerialPort控件设计一些与MSComm控件具有相同接口的类,在今后工业控制中,SerialPort控件将广泛地应用于串口通讯程序的设计中,发挥着与MSComm控件一样的作用。
SerialPort控件位于工具箱组件栏内,如图B-1所示。使用时将其添加到窗体上。
1.SerialPort控件的常用属性
1)BaseStream:获取SerialPort对象的基础Stream对象。
2)BaudRate:获取或设置串行波特率。
3)BreakState:获取或设置中断信号状态。
4)BytesToRead:获取接收缓冲区中数据的
字节数。
5)BytesToWrite:获取发送缓冲区中数据的
字节数。
6)CanRaiseEvents:获取一个指示组件是否
可以引发事件的值(从Component继承)。
7)CDHolding:获取端口的载波检测行的状
态。
8)Container:获取IContainer,它包含
Component。
9)CtsHolding:获取“可以发送”行的状态。
10)DataBits:获取或设置每个字节的标准数
据位长度。
11)DesignMode:获取一个值,用以指示
Component当前是否处于设计模式(从
图B-1工具箱中的SerialPort控件Component继承)。
12)DiscardNull:获取或设置一个值,该值指示Null字节在端口和接收缓冲区之间传输时是否被忽略。
13)DsrHolding:获取数据设置就绪(DSR)信号的状态。
14)DtrEnable:获取或设置一个值,该值在串行通信过程中启用数据终端就绪(DTR)信号。
15)Encoding:获取或设置传输前后文本转换的字节编码。
16)Events:获取附加到此Component的事件处理程序的列表(从Component继承)。
17)GenerateMember:是否生成当前控件的类变量,为Boolean型变量。
18)Handshake:获取或设置串行端口数据传输的握手协议。其枚举值为None、XOnXOff、RequestToSend、RequestToSendXOnXOff。
19)IsOpen:获取一个值,该值指示SerialPort对象的打开或关闭状态。
20)Modifiers:继承属性控制,其枚举值为Public、Protected、ProtectedFriend、Friend、Private
21)NewLine:获取或设置用于解释ReadLine和WriteLine方法调用结束的值。
22)Parity:获取或设置奇偶校验检查协议。其枚举值为None、Odd、Even、Mark、Space。
23)ParityReplace:获取或设置一个字节,该字节在发生奇偶校验错误时替换数据流中的无效字节。其值为字符的ASCII码。
24)PortName:获取或设置通信端口,包括但不限于所有可用的COM端口。对应MScomm控件中的CommPort。
25)Read:从缓冲区读数据。对应MScomm控件中的Input。
26)ReadBufferSize:获取或设置SerialPort输入缓冲区的大小。对应MScomm控件中的InBufferCount。
27)ReadTimeout:获取或设置读取操作未完成时发生超时之前的毫秒数。
28)ceivedBytesThreshold:获取或设置DataReceived事件发生前内部输入缓冲区中的字节数。接收缓冲区中接收到一个字符,就产生一次DataReceived 事件。
29)RtsEnable:获取或设置一个值,该值指示在串行通信中是否启用请求发送(RTS)信号。为Boolean型变量。
30)Site:获取或设置Component的ISite。
31)StopBits:获取或设置每个字节的标准停止位数。
32)Write:向缓冲区写数据。对应MScomm控件中的Output。
33)WriteBufferSize:获取或设置串行端口输出缓冲区的大小。对应MScomm控件中的OutBufferCount。
34)WriteTimeout:获取或设置写入操作未完成时发生超时之前的毫秒数
2.SerialPort控件的方法
1)Close:关闭端口连接,将IsOpen属性设置为false,并释放内部Stream 对象。
2)CreateObjRef:创建一个对象,该对象包含生成用于与远程对象进行通信的代理所需的全部相关信息(从MarshalByRefObject继承)。
3)DiscardInBuffer:丢弃来自串行驱动程序的接收缓冲区的数据。
4)DiscardOutBuffer:丢弃来自串行驱动程序的传输缓冲区的数据。
5)Dispose:释放SerialPort对象使用的非托管资源。
6)Equals:确定两个Object实例是否相等(从Object继承)。
7)Finalize:在通过垃圾回收将Component回收之前,释放非托管资源并执行其他清理操作(从Component继承)。
8)GetHashCode:用作特定类型的哈希函数。GetHashCode适合在哈希算法和数据结构(如哈希表)中使用(从Object继承)。
9)GetLifetimeService:检索控制此实例的生存期策略的当前生存期服务对象(从MarshalByRefObject继承)。
10)GetPortNames:获取当前计算机的串行端口名称数组。
11)GetService:返回一个对象,该对象表示由Component或它的Container提供的服务(从10)GetType:获取当前实例的Type(从Object继承)。
12)InitializeLifetimeService:获取控制此实例的生存期策略的生存期服务对象(从MarshalByRefObject继承)。
13)Open:打开一个新的串行端口连接。
14)Read:从SerialPort输入缓冲区中读取。
15)ReadByte:从SerialPort输入缓冲区中同步读取一个字节。
16)ReadChar:从SerialPort输入缓冲区中同步读取一个字符。
17)ReadExisting:在编码的基础上,读取SerialPort对象的流和输入缓冲区中所有立即可用的字节。
18)ReadLine:一直读取到输入缓冲区中的NewLine值。
19)ReadTo:一直读取到输入缓冲区中的指定value的字符串。
20)ReferenceEquals:确定指定的Object实例是否是相同的实例(从Object继承)。
21)ToString:返回包含Component的名称的String(如果有)。不应重写此方法(从Component继承)。
22)Write:将数据写入串行端口输出缓冲区。
23)WriteLine:将指定的字符串和NewLine值写入输出缓冲区(Component继承)。
3.SerialPort控件的事件
1)DataReceived事件
表示将处理SerialPort对象的数据接收事件的方法。
SerialPort控件中的DataReceived事件对应Mscomm控件中的OnComm事件,可以在此事件中对数据进行处理,是Serialport最主要的事件。
DataReceived事件在接收到了[ReceivedBytesThreshold]设置的字符个数或接收到了文件结束字符并将其放入了输入缓冲区时被触发。其中[]相当于MSComm控件的[Rthreshold]属性,该事件的用法与MsComm控件的OnComm 事件在CommEvent为comEvSend和comEvEof时是一致的。
数据接收的设计方法比较重要,采用轮询的方法比较浪费时间,采用延时方法一般会调用API并用DOEvents方法来处理,但程序不易控制,建议采用DataReceived事件触发的方法,合理的设置ReceivedBytesThreshold的值,若接收的是定长的数据,则将ReceivedBytesThreshold设为接收数据的长度,若接收数据的结尾是固定的字符或字符串则可采用ReadTo的方法或在DataReceived事件中判断接收的字符是否满足条件。
2)Disposed事件
添加事件处理程序以侦听组件上的Disposed事件(从Component继承)。
3)ErrorReceived事件
表示处理SerialPort对象的错误事件的方法。
4)PinChanged事件
表示将处理SerialPort对象的串行管脚更改事件的方法。
4.SerialPort控件的使用流程
在使用SerialPort控件进行串口通讯时,一般的流程是设置通讯端口号及波特率、数据位、停止位和校验位,再打开端口连接、发送数据、接收数据,最后关闭端口连接这样几个步骤。
5.SerialPort控件的代码例程
1)串口配置代码
SubPortStart()
=COMX'计算机串口设置,X是串口号。
=9600‘波特率设置
=8'数据位设置
='停止位设置
=
=True
=500'超时时间
=vbCrLf'行结束符合
EndSub
串口通讯最常用的参数就是通讯端口号及通讯格式(波特率、数据位、停止位和校验位),在MSComm中相关的属性是CommPort和Settings。SerialPort控件与MSComm有一些区别:
(1)通讯端口号。[PortName]属性获取或设置通信端口,包括但不限于所有可用的COM端口,请注意该属性返回类型为String,不是的short类型。通常情况下,PortName正常返回的值为COM1、COM2……,SerialPort类最大支持的端口数突破了CommPort控件中CommPort属性不能超过16的限止,大大方便了用户串口设备的配置。
(b)通讯格式。SerialPort控件分别用[BaudRate]、[Parity]、[DataBits]、[StopBits]属性设置通讯格式中的波特率、数据位、停止位和校验位,其中[Parity]和[StopBits]分别是枚举类型Parity、StopBits,Parity类型中枚举了
Odd(奇)、Even(偶)、Mark、None、Space,StopBits枚举了None、One、OnePointFive、Two。
2)串口打开代码
SubPortOpen()
Try
()
CallPortStart()
CatchexAsUnauthorizedAccessException
MsgBox("串口被占用或串口错误!",,"提示!")
EndTry
EndSub
3)串口关闭代码
SubPortOpen()
Try
()
CatchexAsException
MsgBox("串口未打开或串口异常!",,"提示!")
EndTry
EndSub
SerialPort控件是调用类的Open()和Close()方法打开和关闭串口。
4)串口读取数据代码
SubComRec()
DimRxstrAsString
Try
Rxstr=’读取一个新行
()
(Rxstr)‘读取到的数据添加到文本框中显示
CatcheAsTimeoutException’当超时以后,读取串口所有的数据
Rxstr=
(Rxstr)
()
EndTry
EndSub
5)发送数据代码
使用,将数据写入串行端口输出缓冲区。
(1)(String)。将参数字符串写入输出缓冲区中。
(2)(Byte[],Int32,Int32)。将指定数量的字节写入输出缓冲区中的指定偏移量处。
(3)(Char[],Int32,Int32)。将指定数量的字符写入输出缓冲区中的指定偏移量处。
SerialPort控件使用Write和WriteLine方法发送数据,其中WriteLine可发送字符串并在字符串末尾加入换行符,读取串口缓冲区的方法有许多,其中除了ReadExisting和ReadTo,其余的方法都是同步调用,线程被阻塞直到缓冲区有相应的数据或大于ReadTimeOut属性设定的时间值后,引发ReadExisting异常。