




已阅读5页,还剩106页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
C#网络通信开发实战第1 章:套接字编程编写网络应用程序是程序设计中最有趣的领域之一。眼看着自己编写的程序成功地通过网络实现了通信,这是特别令人振奋的。在这一章里,我们将使用TCP/IP建立一个类似于Windows LiveMessenger(或ICQ)的聊天程序。通过这个聊天程序,你将学会如何在.NET中进行网络编程,并了解建立多用户聊天程序时会遇到的种种挑战。第2 章:串行通信串行通信是设备之间相互通信最古老的机制之一。从IBM PC及其兼容机开始,几乎所有的计算机都配备了一个或多个串行端口和一个并行端口。顾名思义,串行端口(serial port)每次1位地连续收发数据,而并行端口(parallel port)则使用8条独立的数据线每次收发8位数据。尽管串行端口传输速度相对低于并行端口,但串行通信仍然是设备连接的流行选项,因为它简单而且成本较低。虽然当今的消费产品正在使用USB连接取代串行连接,但是仍有大量的设备把串行端口作为它们与外部世界连接的唯一途径。这一章将介绍怎样使用.NET Framework 2.0和.NET Compact Framework 2.0里新的SerialPort类实现与其他串行设备的通信。我们将建立3个项目,用实例说明怎样使用串行通信。第一个项目是一个聊天程序,它允许(使用串行数据线或者蓝牙互相连接的)两台计算机进行通信。你可以以此程序为基础,对其进行扩展来实现与手机之类的其他外部串行设备的通信。你将学会如何通过一个串行的蓝牙连接使用AT命令通过程序来控制你的移动电话。第二个项目是一个Pocket PC聊天程序,与前一个项目十分类似。第三个项目展示了怎样与GPS接收器通信,并从中提取有用的数据用于在地图上显示当前位置。第3 章:将指纹识别纳入.NET 程序生物特征识别是确认个体身份最可靠的方式之一。现在,应该有很多人已经熟悉了微软指纹阅读器(Microsoft Fingerprint Reader)。使用微软指纹阅读器,你只需把手指放在读取器上,就能登录你的电脑。你也可以使用指纹阅读器提供的应用程序来为要求身份认证的网站保存用户ID和密码。随后你就可以将指纹作为钥匙,取出ID和密码,安全地登录那些站点。微软指纹读取器把需要为不同网站记住不同密码的烦恼一扫而尽。在这一章,我们将说明如何使用GrFinger Fingerprint SDK将微软指纹阅读器集成到你的.NET2.0 Windows应用程序中。我们将建立一个来访者鉴别系统,访问办公室的用户可以使用它在接待处登记。登记以后,下一次他再访问办公室时,只需简单地扫描一下指纹,系统就会记录他的来访。学校也可以改编这个程序用于考勤,比如在大型的阶梯教室等场合,考勤必须快速而有效地实施。第4 章:红外线编程在流行的如WiFi(Wireless Fidelity,基于IEEE 802.11b标准的无线局域网)、蓝牙和其他无线技术的喧哗声中,有一种最简单而又最普遍的无线通信形式很容易被忽略它就是红外线通信。其实只要用过遥控器就已经用过这种通信形式。红外线通信使用超出光谱中可见光红光的不可见波段。你可以在应用程序中利用它进行短程的、点到点的数据传输。因为使用了光,所以光路是使用红外线通信的必要条件。尽管有此限制,红外线还是在数码相机、PDA和笔记本电脑等设备中日益流行。在这一章里,我们将讲解如何建立允许两台设备(及计算机)使用红外线进行无线通信的应用程序。你可以将这一章中阐述的编程技术改造并应用到其他编程任务中,如编写无线的网络游戏等。第5 章:RFID 编程射频识别(Radio Frequency Identifications,RFID)是近来在IT行业大力宣传的一项技术。RFID系统是一种识别系统,通过无线电波从称为电子标签(tag)或应答器(transponder)的设备中接收数据。RFID应用在日常生活中随处可见超市、图书馆、书店等。RFID提供了一种快速而有效的方式来收集信息,如仓库的库存盘点、物品下落的追踪等。在这一章,我们将介绍如何构建利用RFID技术进行数据采集的Windows应用程序。我们将使用2个RFID阅读器并分析它们各自的优缺点。第6 章:与外围设备交互摄像头是当今大多数人都可以轻易购置的普通外围设备,经常用于视频会议。但是,除了视频会议以外,还可以用摄像头做些什么呢?对于.NET开发人员来说,答案非常多。而且你会高兴地看到,将摄像头集成到Windows应用程序中并不像想象中那么难。除了将摄像头集成到应用程序以外,还可以将Windows应用程序连接到诸如传感器这样的外围设备,以监视周围环境的变化。在这一章,我们通过将Windows程序与外围的传感器和摄像头接口,构建一个可以监视有害活动的安全系统。你可以探测到入侵者,并用摄像头记录入侵者的行动。目 录第1 章 套接字编程 111 套接字编程介绍 112 创建自己的多用户聊天应用程序2121 为网络通信使用TcpClient 和TcpListener 类 3122 构建服务器 7123 构建客户 16124 测试聊天应用程序 2313 构建高级的多用户聊天应用程序24131 定义自己的通信协议 24132 协议描述 24133 功能一览 25134 构建服务器 28135 构建客户 43136 测试应用程序 6514 小结66第2 章 串行通信6721 串行通信基础6822 使用串行端口聊天69221 硬件需求 70222 构建聊天应用程序 72223 创建SerialPort 类的实例 73224 列举所有可用的串口名 73225 打开串口 75226 断开串口连接 77227 使用串口发送数据 78228 接收串口上的数据 79229 测试应用程序 802210 传输Unicode 字符 812211 连接到其他串行设备 8223 在Pocket PC 上使用串口聊天85231 硬件需求 86232 构建应用程序 86233 编写程序代码 8724 用GPS 接收器和微软虚拟地球创建地图程序91241 构建应用程序 94242 创建包含虚拟地球地图的HTML文件 94243 编写程序代码 96244 显示地图的坐标 100245 连接到GPS 接收器 10325 绘制保存的路径11226 小结118第3 章 将指纹识别纳入NET 程序11931 使用GrFinger SDK12032 创建应用程序120321 编写程序代码 123322 连接所有控件 125323 测试应用程序 14233 小结144第4 章 红外线编程17141 IrDA 介绍17142 创建Windows 移动设备之间的红外线通信172421 你所需要的 172422 创建项目 173423 编写程序代码 174424 接收消息 175425 显示接收到的消息 179426 发送消息 180427 编译并部署应用程序 18343 建立桌面上的红外线通信184431 你所需要的 184432 创建项目 185433 导入命名空间186434 声明常量和成员变量187435 编写Form_Load()事件代码187436 编写ReceiveLoop()子程序188437 编写ReceiveMessage()函数189438 编写代理以及UpdateTextBox()和UpdateStatus()子程序191439 编写SendMessage()子程序1914310 编写Send 按钮控件的代码1944311 测试应用程序19544 小结195第5 章 RFID 编程19751 RFID 介绍19752 构建考勤应用程序199521 RFID 阅读器1: Parallax RFID阅读器模块199522 RFID 电子标签200523 阅读器的设置200524 构建应用程序用户界面202525 编写程序代码207526 测试应用程序220527 RFID 阅读器2: PhidgetRFID221528 RFID 电子标签221529 构建示例应用程序2225210 PhidgetRFID API 2245211 编写程序代码2245212 测试应用程序2305213 两种RFID 阅读器的比较23153 小结231第6 章 与外围设备交互23361 所使用的组件233611 传感器234612 摄像头23462 连接传感器到PC235621 连接PING 传感器236622 PING 传感器编程237623 与PC 集成24063 摄像头的编程24664 小结2551.1套接字编程介绍第1章 套接字编程编写网络应用程序是程序设计中最有趣的领域之一。眼看着自己编写的程序成功地通过网络实现了通信,这是特别令人振奋的。在这一章里,我们将使用TCP/IP建立一个类似于Windows Live Messenger(或ICQ)的聊天程序。通过这个聊天程序,你将学会如何在.NET中进行网络编程,并了解建立多用户聊天程序时会遇到的种种挑战。1.1套接字编程介绍套接字(socket)是网络计算机与应用程序之间发送和接收数据的方式的一种抽象描述。它描述了(可能在不同的计算机上,也可能在同一台计算机内的)两个通信点之间的连接。在实际操作中,套接字编程往往与TCP/IP和UDP/IP通信相结合(关于TCP/IP和UDP/IP的更多信息参见下面的“理解IP、TCP和UDP”)。论及套接字编程时,以下3类信息是很重要的:协议(如TCP/IP或UDP/IP)。IP地址(例如)。端口号(例如端口80)。举例来说,对于http/这样的地址,你应该比较熟悉,这个地址用来指示Web浏览器加载位于的主页。http指定了使用的应用协议(HTTP使用TCP/IP传输数据),指定了地址(名称将会被DNS服务器解析成一个IP地址)。由于HTTP使用端口80进行通信,端口号80被隐式地指明,故没有出现在地址里。如图1-1所示,通信的双方都必须拥有IP地址。(点击查看大图)图1-1Web浏览器和网络服务器之间的通信尽管有TCP/IP这样的协议负责把数据从一个点传输到另一个点,但所传输数据的内容则需由诸如HTTP这样的应用协议来指定。在.NET Framework里,套接字通信由Socket类来实现(该类位于System.Net.Sockets命名空间)。理解IP、TCP和UDP对于网络编程来说,深入地理解当下正在使用的一些常见网络协议是很重要的。首先是网际协议(Internet Protocol,IP)。IP指定了从一个点传送到另一个点的数据分组(如数据报datagrams)的格式和寻址方案。假设IP是一种邮递系统,你可以通过它把邮件从一个地方寄到另一个地方。你只需写上收件者地址并把邮件丢进邮箱里。随后邮局会试图把邮件投递给收件人。但是,你不能确定你的邮件肯定会到达目的地,也不会知道它究竟何时到达。为了确保邮件被正确地投递,你必须使用额外的服务,比如挂号信。与上述情形类似,我们需要将其他协议与IP联合使用,以保证数据分组传送无误。传输控制协议(Transmission Control Protocol,TCP)正是这样一种协议。TCP是一种面向连接的网络协议,它(通过应答机制)保证数据分组可靠并有序地传送。作为流行的网络协议,与IP协同工作的TCP已被Web浏览器和电子邮件客户这样的应用程序广泛采用。TCP确保了传送的正确性,但它也有不便的地方。正如要花更多的钱来寄送的挂号信一样,TCP给被发送的数据分组加上了额外的报头,增大了分组的尺寸。因此,开发人员有时会将用户数据报协议(User Datagram Protocol,UDP)与IP联用。UDP是一种无连接的网络协议,同样把数据分组从一点发送到另一个点,只有一个例外它并不提供可靠的、有保障的传送。由于UDP不对传送提供保障,数据分组将包含更多的有效信息并能更快地传送。使用UDP的开发人员必须建立自己的逻辑以确保数据分组的正确传送。这也与邮寄的例子很相似:你可以自己给收件人打电话,看他们是否已经收到你寄的邮件。如果他们没有收到,你可能需要重新寄。对于那些传送小数据分组且不需要数据精确组装的应用程序来说,UDP是非常有用的。这类程序包括简单文件传输协议(Trivial File Transfer Protocol,TFTP)、域名系统(Domain Name System,DNS)以及语音IP(Voice over IP,VoIP)。1.2创建自己的多用户聊天应用程序1.2创建自己的多用户聊天应用程序在本章的这一部分,我们将首先建立一个简单的聊天程序,它允许连接到中央服务器的任何人互相进行通信。这样可以让你探索套接字通信的基本原理,并学习如何向所有已连接的用户广播消息。图1-2展示了本章的这一部分将要的建立的应用程序。(点击查看大图)图1-2即将创建的聊天程序1.2.1为网络通信使用TcpClient和TcpListener类创建聊天程序通常涉及套接字编程创建一个客户和服务器之间的连接,使客户和服务器都能发送和接收消息。System.Net.Sockets命名空间提供套接字编程所需的功能。在这个项目我们将使用System.Net.Sockets命名空间里的2个类:TcpClient和TcpListener。TcpClient类实现了使用TCP发送和接收数据的套接字。因为与远程设备的连接被表示为流,数据可以使用.NET Framework的流处理技术来读取和写入。TcpListener类以阻塞同步模式提供用于监听和接受外来连接请求的简单方法。下面的示例代码实现了一个简单的等待外来连接的服务器(一个控制台应用程序)。要连接到服务器并向它发送一个字符串,客户代码(一个控制台应用程序)将是下面这样的:注意,NetworkStream对象操作字节数组,因而需要使用来自System.Text命名空间的Encoding.ASCII.GetString()和Encoding.ASCII.GetBytes()方法来将字节数组转换成字符串,反之亦然。上面的例子是比较简单的它包含了服务器代码和客户代码。服务器在使用端口500打开一个套接字并监听外来TCP连接。当连接建立起来以后,由一个NetworkStream对象读取客户发来的数据。到达的数据随后显示在控制台上。另一方面,客户在打开一个连接,然后使用NetworkStream对象向服务器发送一个字符串。但是,当服务器需要同时与多个客户通信并能同时发送和接收消息时,问题就会变得复杂得多。为了实现这些,必须满足以下几条。服务器必须能够与多个客户建立连接。服务器必须能够从客户异步读取数据并能在任何时刻向客户发送消息。客户必须能够从服务器异步读取数据并能在任何时刻向服务器发送消息。接下来的几节将解决这3个问题。1.2.2构建服务器(1)聊天程序有两个部件服务器和客户,我们来首先构建服务器。用Vistual Studio 2005创建一个控制台程序项目,将该项目命名为Server。在默认的Module1.vb/Program.cs文件里,首先导入System.Net.Socket命名空间,它包含这个项目将要用到的所有相关的类。接下来,声明一个常量来存储这个应用程序使用的端口号。对这个程序,我们使用端口号500。提示如果你在服务器(或者客户)上安装了防火墙,请确保打开端口500,以便这个应用程序运行。我们还需要定义所要监听的本地地址,然后创建一个TcpListener类的实例,用来监听来自TCP客户的连接。在Main()函数里,使用来自类TcpListener的Strart()方法来开始监听外来连接请求。AcceptTcpClient()方法是一个阻塞式的调用,直到连接建立起来以后程序才会继续执行。因为这个示例里的服务器需要同时为多个客户提供服务,我们将为每一个用户创建一个ChatClient类(稍后将定义)的实例。服务器将会无限地循环检查,若有客户请求连接,则接受。完整的Module1.vb源文件如下所示。接下来定义ChatClient类。我们使用ChatClient类来表示连接到该服务器的每个客户的信息。 在Visual Studio 2005中为项目添加一个新的类,并将其命名为ChatClient.vb/ChatClient.cs。照例,第一步是导入System.Net.Sockets命名空间(对于代码的C#版本,还需要导入System. Collections命名空间)。1.2.2构建服务器(2)在ChatClient类中,首先定义各种私有成员(它们的用途在代码注释中会有说明)。同时声明一个HashTable对象(AllClients),用来保存所有连接到该服务器的用户的列表。将它声明为共享成员的原因是,确保ChatClient类的所有实例都能够获得当前连接到该服务器的所有客户的列表。当一个客户连接到服务器时,服务器将创建一个ChatClient类的实例,并将变量TcpClient(client)传递给类的构造函数。同时,我们取得客户的IP地址并将它用作索引来标识HashTable对象中的客户。BeginRead()方法将在独立的线程中启动一个从NetworkStream对象(client.GetStream)的异步读取。这样可以使服务器保持响应能力并继续接受来自其他客户的新连接。读取完成以后,控制将被转移到ReceiveMessage()函数(此函数稍后将会定义)。在ReceiveMessage()函数中,首先调用EndRead()方法来处理异步读取的结尾。在这里,我们将检查读取的字节数是否小于。如果是,则意味着客户已经断开连接,那么我们需要从HashTable对象中(使用客户的IP地址作为表中的索引)删除该客户,同时使用Broadcast()函数(此函数稍后定义)向所有客户广播消息,告知这一特定客户已经离开了聊天。为了简单起见,假设客户会在第一次连接到服务器时发送他的昵称。此后,只需向所有人广播该客户发出的所有信息。一旦完成,服务器将再次执行从该客户的异步读取。上面的代码里需要注意的一个问题是,需要使用SyncLock(C#中的lock)语句来阻止多个线程同时使用NetworkStream对象。当服务器连接到多个客户而且它们全都在同一时刻试图访问NetworkStream对象时,这一情况就可能会出现。SendMessage()函数允许服务器向客户发送消息。最后,Broadcast()函数向存储在AllClients HashTable对象中的所有客户发送消息。1.2.3构建客户(1)现在服务器已经构建起来,接下来构建客户。使用Visual Studio 2005创建一个新的Windows应用程序(将它命名为WinClient),并在默认窗体上放置如图1-3所示的控件。设置txtMessage History控件的MultiLine和ReadOnly属性为True,并设置其ScrollBars属性为Vertical。同时,设置btnSend控件的Enabled属性为False。(点击查看大图)图1-3在Windows窗体上放置控件客户应用程序的逻辑与服务器类似,不过更加直接。双击表单切换到编辑窗口,导入以下命名空间。在类Form1里定义下列常量和变量。当用户登录时,程序会首先连接到服务器并使用SendMessage()子程序发送用户的昵称,然后开始从服务器异步读取数据并将按钮的名称改为Sign Out。当用户从聊天应用程序退出时,调用Disconnect()子程序。1.2.3构建客户(2)用户点击Send按钮时,程序向服务器发送消息。加入SendMessage()子程序,它允许客户向服务器发送消息。ReceiveMessage()子程序在一个独立的线程里异步读取从服务器发来的数据。收到数据时,它把数据显示在txtMessageHistory控件里。因为Windows控件不是线程安全的,你需要使用一个代理(delUpdateHistory())来更新该控件。线程安全默认情况下,Windows应用程序使用单个的执行线程。而当你有多个执行线程(正如使用ReceiveMessage()子程序在这里所做的一样)并试图更新来自不同线程的UI时,情况会变得稍稍复杂一些。应该记住的是,我们无法直接访问独立线程(相对于所在的主线程而言)里Windows控件的属性,因为Windows控件不是线程安全的。试图这么做将会引发运行时错误,这是Visual Studio 2005新加入的一个有用的特性。相反,我们应该使用代理,并且使用要更新的控件/窗体的Invoke()/BeginInvoke()方法来调用它。使用代理delUpdateHistory()来调用主线程里的UpdateHistory()函数。最后,Disconnect()子程序断开客户与服务器之间的连接。窗体关闭时,调用Disconnect()子程序来断开客户与服务器之间的连接。对于代码的C#版本,需要将以下代码中的黑体部分添加到Form1.Designer.cs(在Solution Explorer中,调用Show All Files按钮,你将在Form1.cs下面找到这个文件)中,为窗体的FormClosing事件绑定处理程序。1.2.4测试聊天应用程序要测试这个应用程序,首先在Visual Studio 2005里按下F5以运行服务器。需要装载客户的多份副本以测试服务器的多线程能力,可以在WinClient项目的bin目录下找到客户的.exe文件。运行WinClient.exe的多个副本,登录并同时聊天(见图1-4)。注解简单起见,假设数据在同一个块里是通过TCP流发送和接收的。但是,这并不总是正确的。通过TCP流发送的数据并不保证立即到达,你可能在当前的读取循环里收到消息的一部分而在下一个循环里收到另一部分,或者几个消息会在同一时候被读到。下一节的项目将会告诉你怎样处理这一问题。(点击查看大图)图1-4测试多用户聊天应用程序1.3构建高级的多用户聊天应用程序在上一节你已经看到了怎样构建一个多用户聊天程序,实现多个用户同时聊天。尽管该程序很有意思,但它不太灵活,因为你不能选择用户与他私下沟通,所有的信息都广播给聊天中的每个人。在接下来的几节里,在前面几节所建立的基础上,我们将增强这个应用程序,以允许与选定的用户私聊。我们还将在程序中加入FTP支持,实现用户之间的文件传输。1.3.1定义自己的通信协议开始增强聊天程序时,你会意识到必须为种种不同的功能定义自己的应用程序协议。比如,当你想要与某人聊天时,你需要向服务器指出用户名,以便只有发往该用户的消息才能到达他那里。类似地,当你需要完成文件传输时,必须有几个握手环节以确保接收者明确地接受了文件传输,只有那时才能开始发送文件。程序将使用下面几节中定义和描述的协议。1.3构建高级的多用户聊天应用程序在上一节你已经看到了怎样构建一个多用户聊天程序,实现多个用户同时聊天。尽管该程序很有意思,但它不太灵活,因为你不能选择用户与他私下沟通,所有的信息都广播给聊天中的每个人。在接下来的几节里,在前面几节所建立的基础上,我们将增强这个应用程序,以允许与选定的用户私聊。我们还将在程序中加入FTP支持,实现用户之间的文件传输。1.3.1定义自己的通信协议开始增强聊天程序时,你会意识到必须为种种不同的功能定义自己的应用程序协议。比如,当你想要与某人聊天时,你需要向服务器指出用户名,以便只有发往该用户的消息才能到达他那里。类似地,当你需要完成文件传输时,必须有几个握手环节以确保接收者明确地接受了文件传输,只有那时才能开始发送文件。程序将使用下面几节中定义和描述的协议。1.3.3功能一览在开始学习怎样编写聊天应用程序之前,我们先来看看本章的这一部分将要构建的应用程序是什么样的。登录到服务器时,在线用户的列表将会出现在ListBox控件里(见图1-5的左侧)。要与一个用户聊天,简单地选择你想要交谈的用户,单击Send按钮以发送消息(见图1-6)。要与多个用户聊天,按下Ctrl键并单击ListBox控件里的用户名(见图1-7)。要向另一个用户发送文件,选择接收者的名称,点击Send File按钮,然后选择想要传输的文件并点击Open(见图1-8)。在接收者那端,他将会得到一个请求下载文件的提示框。如果他点击了Yes,文件即被下载(见图1-9)。当文件下载时,状态栏将显示当前已收到的字节数(见图1-10)。(点击查看大图)图1-10显示下载进度1.3.4构建服务器(1)这个聊天应用程序有两个组件:服务器和客户。我们首先构建服务器。使用Visual Studio 2005创建一个控制台程序项目,将它命名为Server。在默认的Module1.vb文件里,输入以下代码。使用真实的IP地址如果仔细看过代码,你会发现这次使用了一个真实的IP地址(并且不是本地服务器地址)。在这里使用的IP地址是由路由器分配的,你的计算机通常会有一个不同的IP地址。之所以使用真实IP地址,是因为要测试这个项目的FTP功能需要至少两台计算机。一台计算机上同时承载服务器和客户,而另一台则专门承载客户。因为FTP功能会直接使用每个客户的IP地址,用本地服务器地址将会发生错误。同时,如果服务器与客户不在同一台计算机上,你也需要使用服务器的真实IP地址。你自己测试时,请务必使用服务器计算机的真实IP地址。下一步是定义ChatClient类。我们使用ChatClient类来表示每个连接到服务器的客户的信息。在Visual Studio 2005中向项目中加入一个新的类,并将其命名为ChatClient.vb。首先导入以下命名空间。在ChatClient类中,首先定义各种私有成员(它们的用途在代码的注释中说明)。同时声明一个HashTable对象(AllClients),用来保存所有连接到该服务器的用户的列表。将它声明为共享成员的原因是,确保ChatClient类的所有实例都能够获得当前连接到该服务器的所有客户的列表。当一个客户连接到服务器时,服务器将创建一个ChatClient类的实例,并将变量TcpClient(client)传递给类的构造函数。同时,我们取得客户的IP地址并将它用作索引来标识HashTable对象中的客户。BeginRead()方法将在独立的线程中启动一个从NetworkStream对象(client. GetStream)的异步读取。这样可以使服务器保持响应能力并继续接受来自其他客户的新连接。读取完成以后,控制将被转移到ReceiveMessage()函数(此函数稍后将会定义)。1.3.4构建服务器(2)SendMessage()函数允许服务器向客户发送消息。Broadcast()函数向存储在AllClients HashTable对象中的所有客户发送消息。1.3.4构建服务器(3)注解发送给客户的所有消息都以换行符(Visual Basic里的vbLf,C#里的n)结束。在ReceiveMessage()函数中,首先调用EndRead()方法来处理异步读取的结尾。在这里,我们将检查读取的字节数是否小于。如果是,则意味着客户已经断开连接,我们需要从HashTable对象中(使用客户的IP地址作为表中的索引)删除该客户,同时使用Broadcast()函数(此函数稍后定义)向所有客户广播消息,告知这一特定客户已经离开了聊天。在这个ReceiveMessage()函数中,我们检查发送自客户的不同的消息格式并采取相应的动作。比方说,客户发起一个FTP请求,则需要将消息重新打包(如前面1.3.2节所述)并将它发给文件的接收者。必须注意,发送过来的数据可能并不是在一次全部到达请求可能会被打破并被单独收到,或者多个请求会同时到达。下面的“接收传入的数据”讨论了3种可能的情况。接收传入的数据有3种可能的情景。情景 1第一种情景是理想的。在这里,客户发来的字符串被完整地接收到。下面的插图展示了由User1向User2和User3发起的一个交谈请求。该请求以LF字符结束,而字节数组的剩余部分包含空字符(0)。情景 2第二种情景在一个请求被打破并分别被收到时发生。在下面的图解里,由User1发往User2和User3的请求被打破成两个部分。只有请求的第二部分以LF字符结束。情景 3第三种情景在两个单独的请求一起被收到时发生,如下图所示。在这里,第一个请求与第二个请求以一个LF字符分隔。1.3.5构建客户(1)现在服务器已经构建起来,接下来构建客户。使用Visual Studio 2005创建一个新的Windows应用程序(将它命名为WinClient),并在默认窗体上放置如图1-11所示的控件。设置txtMessage History控件的MultiLine和ReadOnly属性为True,并设置其ScrollBars属性为Vertical。另外,设置lstUsers的SelectionMode属性为MultiExtended。(点击查看大图)图1-11在Windows窗体上放置各种控件双击窗体以切换到代码视图,导入以下命名空间。 在类Form1里定义以下变量和常量。当用户登录时,客户首先连接到服务器并使用SendMessage()子程序(稍后定义)发送用户的昵称。然后开始从服务器异步读取数据并将Sign In按钮的文字改为Sign Out。它将请求当前在线的用户的列表。当用户从聊天应用程序退出时,调用Disconnect()子程序(稍后定义)。1.3.5构建客户(2)Send按钮向服务器发送消息。注意,在左边选择用户以后,你需要在ListBox控件里选择用户,才能发送消息。前面代码使用的SendMessage()子程序允许客户向服务器发送消息。1.3.5构建客户(3)ReceiveMessage()子程序在一个独立的线程里异步读取从服务器发来的消息。收到数据时,它把数据显示在txtMessageHistory控件里。因为Windows控件不是线程安全的,你需要使用一个代理delUpdateHistory()来更新该控件。像前面一样,需要特别注意到请求可能不是整体到达的。使用代理delUpdateHistory()调用主线程里的UpdateHistory()函数。1.3.5构建客户(4)在UpdateHistory()子程序里,我们检查消息格式并执行适当的操作。比如说,如果用户结束了聊天(通过Left消息),我们必须将它的用户名从ListBox里删除。1.3.5构建客户(5)当用户点击SendFile按钮,选择接收用户,然后发送文件。FTP_Send()子程序通过TCP端口501向接收者发送一个文件。它以大小为8 192字节(缓冲区最大尺寸)的块发送文件。1.3.5构建客户(6)FTP_Receive()子程序通过TCP端口501接收外来的文件,将收到的文件保存到C:temp目录里。注解简单起见,请确保运行客户的计算机上已经创建了C:temp文件夹。当用户关闭窗体时(通过点击窗口上的X按钮),断开客户与服务器之间的连接。最后,Discount()子程序断开客户与服务器之间的连接。1.3.6测试应用程序要测试这个应用程序,首先在Visual Studio 2005里按下F5以运行服务器。需要装载客户的多份副本以测试服务器的多线程能力,可以将Apress网站()上Source Code/Download栏目所提供的代码文件编译成一个.exe文件。运行这个应用程序的多个副本,登录并同时聊天。测试应用程序的FTP功能时,请确保客户在不同的计算机上运行。1.4小结在本章里,你看到了怎样使用TcpClient类来实现两台计算器之间的异步通信。本章开发的两个聊天应用程序以实例说明了如何设计自己的通信协议,这将为建立更加复杂的聊天应用程序打下基础。现在,先去玩一下你的聊天应用程序吧。第2章 串行通信串行通信是设备间通信的最古老的机制之一。从IBM PC及其兼容机开始,几乎所有的计算机都配备了一个或多个串口和一个并口。顾名思义,串口每次1位地连续收发数据,而并口则使用8条独立的数据线每次收发8位数据。提示为了让串行通信工作,最少只需要3条线:1条发送线、1条接收线和1条信号地线。并行通信则需要8条线。尽管传输速度相对低于并口,但串行通信仍然是设备连接的流行选项,因为它简单而且成本较低。图2-1展示了几个用串口连接到计算机的设备。使用串口,你可以连接到调制解调器、鼠标或者网桥/路由器之类用于配置目的的设备。图2-1一些常见的串行设备调制解调器、鼠标和路由器虽然当今的消费产品正在使用USB连接取代串行连接,但是仍有大量的设备把串口作为它们与外部世界连接的唯一途径。本章将介绍怎样使用.NET Framework 2.0和.NET Compact Framework 2.0里新的SerialPort类实现与其他串行设备的通信。我们将建立3个项目,用实例说明怎样使用串行通信。第一个项目是一个聊天程序,它允许(使用串行数据线或者蓝牙互相连接的)两台计算机进行通信。你可以以此程序为基础,对其进行扩展来实现与移动电话之类的其他外部串行设备的通信。你将学会如何通过一个串行的蓝牙连接使用AT命令以程序控制移动电话。第二个项目是一个Pocket PC聊天程序,与前一个项目十分类似。第三个项目展示了怎样与GPS接收器通信,并从中提取有用的数据用于在地图上显示当前位置。2.1串行通信基础如前所述,串行设备每次发送和接收一位数据。一些设备能够同时发送和接收数据,称为全双工(full-duplex)设备。另外一些设备在某一时刻只能发送或者接收数据,称为单双工(single-duplex)。为了发起传送,设备首先发送一个开始位(start bit),随后是数据位(data bit)。数据位的个数可以是5、6、7或者8,这取决于具体的协议。发送和接收的双方都必须设置相同的数据位数,以保证通信的正确进行。数据位发送以后,停止位(stop bit)随即被发送。停止位可以是1位、1.5位或者2位。波特率(baud rate)是从一个设备到另一个设备的数据传输速度,通常以位每秒(bits per second,bit/s)来衡量。注解大多数串行设备以7个或者8个数据位进行传输。为了检测数据传输的正确性,数据位中可以包含一个可选的奇偶校验位(parity bit)。奇偶校验位可以是以下之一:奇、偶、符号、空格或者没有(符号和空格是最常用的)。使用奇偶校验位可以提供基本的检测数据讹误的机制,但是并不能保证收到的数据是没有错误的。尽管如此,奇偶校验位在改善数据发送的完整性上还是非常有用的。大多数串行端口支持RS232C标准,该标准定义了25针或者9针的连接器(见图2-2)。多数串行设备使用9针连接器。图2-225针和9针的串行连接器2.2使用串行端口聊天本章将创建的第一个应用程序是一个聊天应用程序。该聊天应用程序允许使用串行连接的两台计算机进行通信。提示注意这里说的是串行连接,而不是串行电缆。这是因为两个使用蓝牙连接的用户也可以使用这个程序进行通信我们可以使用蓝牙建立起两台计算机之间的串行连接。最普遍的情况是使用一条零调制解调器电缆(null modem cable)连接两台计算机(见图2-3)。图2-3零调制解调器电缆图2-4展示了完成的项目。选择对应连接到远程计算机的串口的COM号码。点击Connect按钮,即可开始聊天。 图2-4选择端口号开始聊天2.2.1硬件需求为了测试串行通信,有以下几种选择。计算机到计算机:如前所述,使用零调制解调器电缆连接两台计算机。单计算机:使用零调制解调器电缆连接同一计算机的两个串行端口。如果计算机只有一个串口,也可以用USB-串口转换器将一个USB端口转换成一个串行端口来使用(更详细的内容参见下面的小节)。蓝牙连接:在两台蓝牙配对的计算机之间创建串行连接。1. USB-串口转换器除非拥有两台计算机,否则不能测试串行通信。不过我们可以使用零调制解调器电缆连接一台计算机上的两个串口来模拟通过串口进行通信的两台计算机。但是当今大多数的计算机都最多只有一个串口(某些笔记本电脑甚至一个都没有)。一个好的解决方案是使用USB-串口适配器来将USB口转换成串口。这样一来,如果你的计算机根本没有串口,你需要一对USB-串口适配器和一条零调制解调器电缆(如图2-5)。然后,将每个USB-串口适配器连接到一个USB口。图2-5USB-串口适配器与零调制解调器电缆USB-串口适配器附带它自己的驱动程序。驱动程序安装以后,右击桌面上的“我的电脑”,选择“属性”,在系统属性对话框里单击“硬件”选项卡,点击“设备管理器”按钮。展开Ports(COM&LPT)项,找到新加入的两个COM端口。图2-6找到新加入的串口2. 蓝牙适配器除了使用零调制解调器电缆连接两个串口以外,还可以使用蓝牙来将两台计算机配对。这需要为每台计算机安装蓝牙适配器(见图2-7)。图2-7USB蓝牙适配器注解请参考蓝牙适配器所附带的说明文档来学习怎样在两台蓝牙配对的计算机之间建立串行连接。2.2.2构建聊天应用程序使用Visual Studio 2005创建一个新的Windows应用程序,命名为SerialCommChat。参考图2-8在默认窗体Form1上放置控件。图2-8在默认的Form1放置各种控件设置各控件的属性如表2-1所示。表2-1设置各控件的属性控件属性值Form1TextSerial ChatForm1AcceptButtonbtnSendlblMessageBorderStyleFixedSingletxtDataReceivedScrollBarsVerticaltxtDataReceivedMultiLineTruetxtDataToSendMultiLineTrue在.NET 2.0里,有一个新的SerialPort Windows Forms控件,位于工具栏的Components选项卡里。这一SerialPort控件封装了为使用串行通信而需访问的所有功能。可以拖放一个SerialPort控件到项目里面,也可以在代码里创建它的实例(我们将在此项目里使用这种方法),见图2-9。图2-9工具箱里的SerialPort控件切换到Form1的代码视图,开始编写程序代码。2.2.3创建SerialPort类的实例首先,声明成员变量serialPort,代表想要使用的串口。注解你可以使用前面提到过的SerialPort控件,或者使用IO.Ports.SerialPort类,两者是相同的。需要注意的是,对于Visual Basic 2005,声明它的时候需要使用WithEvents关键字。这是因为SerialPort类拥有DataReceive事件,当数据到达串口时该事件触发,而那时你需要处理这一事件以接收数据。对于C# 2005,DataReceived事件的处理函数将在Form1_Load事件里加入。2.2.4列举所有可用的串口名窗体首次加载时,我们将获取计算机上所有可用的串口名称并将这些名称添加到ComboBox控件里。双击窗体以切换到代码,Form1_Load事件处理函数会自动显示。为该事件编写如下代码。注解在本章的后面,要使得Visual Sudio 2005自动为一个控件的默认事件(如窗体的Load事件和按钮的Click事件)创建处理函数,双击该控件即可。C#里的事件处理在Form1_Load事件的C#版本里,我们同时为SerialPort类的DataReceived事件添加了事件处理函数。该事件将会在数据到达串口时触发。在Visual Basic 2005中我们无须绑定这一事件处理函数,因为可以使用Handl
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 部门级安全培训课件
- 部门安全日常培训内容课件
- 避免革命的改革课件
- 交通韧性评估国际标准对比-洞察及研究
- 基于循环经济的2-氨基-4-氯苯酚生产废料资源化利用模型
- 国际面粉切割标准与本土饮食习惯差异的适配性研究
- 国际标准对接中凹凸管流体力学性能测试方法与ISO认证路径探索
- 可变拓扑结构分装设备应对突发性订单波动的响应机制
- 双螺杆减速与柱塞泵协同传动的能量损耗耦合优化策略
- 双相钢热处理工艺参数与齿轮副接触应力场的动态匹配难题
- 日本语入门课件
- 出租车安全驾驶培训课件
- 信息录入及管理办法
- 消控室委托管理协议合同
- 低空经济产业学院
- 幼儿园视频宣传工作计划
- 家政服务业信用管理办法
- 股癣的护理查房
- DB41∕T 2716-2024 农村公路承灾体灾害调查技术规程
- 宣传用品库存管理办法
- 楼盘进企业活动方案
评论
0/150
提交评论