《c#网络编程(实例)课件.pdf》由会员分享,可在线阅读,更多相关《c#网络编程(实例)课件.pdf(112页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、C#与 VB.NET网络通信开发实战第 1 章:套接字编程编写网络应用程序是程序设计中最有趣的领域之。眼看着自己编写的程序成功地通过网络实现了通信,这是特别令人振奋的。在这一章里,我们将使用TCP/IP建立一个类似于Windows LiveMessenger(sK lC Q)的聊天程序。通过这个聊天程序,你将学会如何在.NET中进行网络编程,并了解建立多用户聊天程序时会遇到的种种挑战。第 2 章:串行通信串行通信是设备之间相互通信最古老的机制之一。从 IBM PC及其兼容机开始,几乎所有的计算机都配备了一个或多个串行端口和一个并行端口。顾名思义,串行端口(serial port)每 次 1位地
2、连续收发数据,而并行端口(parallel p o rt)则使用8 条独立的数据线每次收发8位数据。尽管串行端口传输速度相对低于并行端口,但串行通信仍然是设备连接的流行选项,因为它简单而且成本较低。虽然当今的消费产品正在使用USB连接取代串行连接,但是仍有大量的设备把串行端口作为它们与外部世界连接的唯一途径。这一章将介绍怎样使用.NET Framework 2.0 和.NET Compact Framework 2.0 里新的SerialPort类实现与其他串行设备的通信。我们将建立3 个项目,用实例说明怎样使用串行通信。第一个项目是一个聊天程序,它允许(使用串行数据线或者蓝牙互相连接的)两台
3、计算机进行通信。你可以以此程序为基础,对其进行扩展来实现与手机之类的其他外部串行设备的通信。你将学会如何通过一个串行的蓝牙连接使用AT命令通过程序来控制你的移动电话。第二个项目是一个Pocket PC 聊天程序,与前一个项目十分类似。第三个项目展示了怎样与GPS接收器通信,并从中提取有用的数据用于在地图上显示当前位置。第 3 章:将指纹识别纳入.NET程序生物特征识别是确认个体身份最可靠的方式之一。现在,应该有很多人已经熟悉了微软指纹阅读器(Microsoft Fingerprint Reader)o使用微软指纹阅读器,你只需把手指放在读取器上,就能登录你的电脑。你也可以使用指纹阅读器提供的应
4、用程序来为要求身份认证的网站保存用户ID 和密码。随后你就可以将指纹作为钥匙,取 出 ID 和密码,安全地登录那些站点。微软指纹读取器把需要为不同网站记住不同密码的烦恼一扫而尽。在这一章,我们将说明如何使用GrFinger Fingerprint SDK将微软指纹阅读器集成到你的.NET2.0 Windows应用程序中。我们将建立一个来访者鉴别系统,访问办公室的用户可以使用它在接待处登记。登记以后,下一次他再访问办公室时,只需简单地扫描一下指纹,系统就会记录他的来访。学校也可以改编这个程序用于考勤,比如在大型的阶梯教室等场合,考勤必须快速而有效地实施。第 4 章:红外线编程在流行的如WiFi(
5、Wireless Fidelity,基于IEEE 802.1 lb 标准的无线局域网)、蓝牙和其他无线技术的喧哗声中,有一种最简单而又最普遍的无线通信形式很容易被忽略它就是红外线通信。其实只要用过遥控器就已经用过这种通信形式。红外线通信使用超出光谱中可见光红光的不可见波段。你可以在应用程序中利用它进行短程的、点到点的数据传输。因为使用了光,所以光路是使用红外线通信的必要条件。尽管有此限制,红外线还是在数码相机、PDA和笔记本电脑等设备中日益流行。在这一章里,我们将讲解如何建立允许两台设备(及计算机)使用红外线进行无线通信的应用程序。你可以将这一章中阐述的编程技术改造并应用到其他编程任务中,如编
6、写无线的网络游戏等。第 5 章:RFID编程射频识别(Radio Frequency Identifications,R FID)是近来在IT 行业大力宣传的一项技术。RFID系统是一种识别系统,通过无线电波从称为电子标签(tag)或应答器(transponder)的设备中接收数据。RF1D应用在日常生活中随处可见一一超市、图书馆、书店等。RFID提供了一种快速而有效的方式来收集信息,如仓库的库存盘点、物品下落的追踪等。在这一章,我们将介绍如何构建利用RFID技术进行数据采集的Windows应用程序。我们将使用2 个 RFID阅读器并分析它们各自的优缺点。第 6 章:与外围设备交互摄像头是当今
7、大多数人都可以轻易购置的普通外围设备,经常用于视频会议。但是,除了视频会议以外,还可以用摄像头做些什么呢?对于.NET开发人员来说,答案非常多。而且你会高兴地看到,将摄像头集成到Windows应用程序中并不像想象中那么难。除了将摄像头集成到应用程序以外,还可以将Windows应用程序连接到诸如传感器这样的外围设备,以监视周围环境的变化。在这一章,我们通过将Windows程序与外围的传感器和摄像头接口,构建一个可以监视有害活动的安全系统。你可以探测到入侵者,并用摄像头记录入侵者的行动。目录第 1 章 套 接 字 编 程 11 1 套接字编程介绍11 2 创建自己的多用户聊天应用程序2121为网络
8、通信使用TcpClient和TcpListener 类 3122构建服务器7123构 建 客 户 16124测试聊天应用程序231 3 构建高级的多用户聊天应用程序24131定义自己的通信协议24132协议描述24133功能一览25134构建服务器28135构建客户43136测试应用程序651 4 小结66第 2 章串行通信672 1 串行通信基础682 2 使用串行端口聊天69221硬件需求702 2 2 构建聊天应用程序72223创建SerialPort类的实例732 2 4 列举所有可用的串口名732 2 5 打开串口 752 2 6 断开串口连接772 2 7 使用串口发送数据7822
9、8接收串口上的数据79229测试应用程序802210 传输 Unicode 字符 812211连接到其他串行设备822 3 在 Pocket P C 上使用串口聊天852 3 1 硬件需求862 3 2 构建应用程序862 33编写程序代码872 4 用 G PS接收器和微软虚拟地球创建地图程序91241构建应用程序94242创建包含虚拟地球地图的HTML文 件 94243编写程序代码962 4 4 显示地图的坐标100245连接到G PS接 收 器 1032 5 绘制保存的路径1122 6 小 结 118第 3 章将指纹识别纳入N E T程 序 11931 使用 GrFingerSDK120
10、3 2 创建应用程序120321编写程序代码123322连接所有控件125323测试应用程序1423 3 小 结 144第 4 章 红外线编程17141 IrDA 介绍 1714 2 创建Windows移动设备之间的红外线通信1724 2 1 你所需要的1724 2 2 创 建 项 目 1734 2 3 编写程序代码1744 24接 收 消 息 1754 2 5 显示接收到的消息1794 2 6 发 送 消 息 1804 27编译并部署应用程序1834 3 建立桌面上的红外线通信1844 3 1 你所需要的1844 3 2 创 建 项 目 1854 3 3 导入命名空间1864 3 4 声明常
11、量和成员变量1874 35编写Form_Load()事件代码187436 编写 ReceiveLoop()子程序 188437 编写 ReceiveMessage。函数 1894 3 8 编写代理以及UpdateTextBox()和 UpdateStatus()子程序 191439 编写 SendMessage()子程序 1914310编写Send按钮控件的代码1944311测试应用程序1954 4 小 结 195第 5 章 RFID编 程 19751 RFID 介绍 1975 2 构建考勤应用程序199521 RFID 阅读器1:Parallax RFID阅读器模块199522 R FID
12、电子标签2005 2 3 阅读器的设置200524构建应用程序用户界面202525编写程序代码207526测试应用程序220527 RFID 阅读器 2:PhidgetRFID221528 R FID 电子标签221529构建示例应用程序2225210 PhidgetRFID API 2245211编写程序代码2245212测试应用程序2305213两种R FID 阅读器的比较2315 3 小结231第 6 章 与外围设备交互2336 1 所使用的组件2336 11传感器234612摄像头2346 2 连接传感器到PC235621连接P1NG传感器236622 PIN G 传感器编程2376
13、2 3 与 P C 集成2406 3 摄像头的编程2466 4 小结2551.1套接字编程介绍第 1 章套接字编程编写网络应用程序是程序设计中最有趣的领域之一。眼看着自己编写的程序成功地通过网络实现了通信,这是特别令人振奋的。在这一章里,我们将使用TCP/IP建立一个类似于Windows Live Messenger(或 ICQ)的聊天程序。通过这个聊天程序,你将学会如何在.NET中进行网络编程,并了解建立多用户聊天程序时会遇到的种种挑战。1.1 套接字编程介绍套接字(socket)是网络计算机与应用程序之间发送和接收数据的方式的一种抽象描述。它描述了(可能在不同的计算机上,也可能在同一台计算
14、机内的)两个通信点之间的连接。在实际操作中,套接字编程往往与TCP/IP和 UDP/IP通信相结合(关于TCP/IP和 UDP/IP的更多信息参见下面的“理解IP、TCP和 UDP”)。论及套接字编程时.,以下3 类信息是很重要的:协、议(如 TCP/IP 或 UDP/IP),IP 地 址(例如 127.0.0.1)。端 口 号(例如端口 80)。举例来说,对于http/这样的地址,你应该比较熟悉,这个地址用来指示 W eb浏览器加载位于的主页。http指定了使用的应用协议(HTTP使用TCP/IP传输数据),指定了地址(名 称 将会被DNS服务器解析成一个IP地址)。由于HTTP使用端口 8
15、0进行通信,端口号80被隐式地指明,故没有出现g 地址里。如 图 1-1所示,通信的双方都必须拥有IP地址。_ _ _ _ _ _ _ _ _ _ _HTTPfTCPIP”HTTP(TCPIP)-1.2.34 (69.19.150.101)*端口80,端口城 成 就 孽 想(点击查看大图)图 1-1 Web浏览器和网络服务器之间的通信尽管有TCP/IP这样的协议负责把数据从一个点传输到另一个点,但所传输数据的内容则需由诸如HTTP这样的应用协议来指定。在:.NET Framework里,套接字通信由Socket类来实现(该类位于System.Net.Sockets命名空间)。理解IP、TCP和
16、 UDP对于网络编程来说,深入地理解当下正在使用的一些常见网络协议是很重要的。首先是网际协议(Internet Protocol,IP)。IP指定了从一个点传送到另一个点的数据分组(如数据报 datagrams)的格式和寻址方案。假设IP是一种邮递系统,你可以通过它把邮件从一个地方寄到另一个地方。你只需写上收件者地址并把邮件丢进邮箱里。随后邮局会试图把邮件投递给收件人。但是,你不能确定你的邮件肯定会到达目的地,也不会知道它究竟何时到达。为了确保邮件被正确地投递,你必须使用额外的服务,比如挂号信。与上述情形类似,我们需要将其他协议与IP联合使用,以保证数据分组传送无误。传输控制协议(Transm
17、issionControl Protocol,TCP)正是这样一种协议。TCP是一种面向连接的网络协议,它(通过应答机制)保证数据分组可靠并有序地传送。作为流行的网络协议,与 IP 协同工作的TCP已被 Web浏览器和电子邮件客户这样的应用程序广泛采用。T C P确保了传送的正确性,但它也有不便的地方。正如要花更多的钱来寄送的挂号信一样,T C P 给被发送的数据分组加上了额外的报头,增大了分组的尺寸。因此,开发人员有时会将用户数据报协议(User Datagram Protocol,UDP)与IP联用。UDP是一种无连接的网络协议,同样把数据分组从一点发送到另一个点,只有一个例外它并不提供可
18、靠的、有保障的传送。由于UDP不对传送提供保障,数据分组将包含更多的有效信息并能更快地传送。使用UDP的开发人员必须建立自己的逻辑以确保数据分组的正确传送。这也与邮寄的例子很相似:你可以自己给收件人打电话,看他们是否已经收到你寄的邮件。如果他们没有收到,你可能需要重新寄。对于那些传送小数据分组且不需要数据精确组装的应用程序来说,UDP是非常有用的。这类程序包括简单文件传输协议(Trivial File Transfer Protocol,T FT P)、域名系统(Domain Name System,D N S)以及语音 IP(Voice over IP,V oIP)。1.2 创建自己的多用户
19、聊天应用程序1.2 创建自己的多用户聊天应用程序在本章的这一部分,我们将首先建立一个简单的聊天程序,它允许连接到中央服务器的任何人互相进行通信。这样可以让你探索套接字通信的基本原理,并学习如何向所有已连接的用户广播消息。图 1-2展示了本章的这部分将要的建立的应用程序。(点击查看大图)怪I 1-2 即将创建的聊天程序1.2.1 为 网络通信使用TcpClient和 TcpListener类创建聊天程序通常涉及套接字编程创建个客户和服务器之间的连接,使客户和服务器都能发送和接收消息。System.Net.Sockets命名空间提供套接字编程所需的功能。在这个项目我们将使用System.Net.S
20、ockets命名空间里的2 个类:TcpClient和 T卬Listener。TcpClient类实现了使用TCP发送和接收数据的套接字。因为与远程设备的连接被表示为流,数据可以使用.NET Framework的流处理技术来读取和写入。TcpListener类以阻塞同步模式提供用于监听和接受外来连接请求的简单方法。下面的示例代码实现了一个简单的等待外来连接的服务器(一个控制台应用程号)oclass Program(/-p o rt number to use for listening-const in t portNo-SOO;static void Main(string args)(Sy
21、stem.Net.IPAddress localAdd=System.Net.IPAddress.Parse(n127.O.O.lM);/-lis te n at the local address-TcpListener listener=new TcpListener(loca1Add,portNo);51cmMm/-Accepts a pending connection request-TcpClient tcpClient=listener.AccetTcptlienfO;:/-use a Networkstream object to send and receive/dataNe
22、tworkStream ns=tcpClient.GetStream();byte data=new bytetcpClient.ReceiveBufferSize;/-read incoming stream;Read。is a blocking c a ll-int numBytesRead ns.ReadCdata,0,System.Convert.ToInt32(tcpClient.ReceiveBufferSize);/-display data received-Console.WriteLine(Received Encoding.ASCII.GetString(data,0,n
23、umfiytesRead);/-prevent the console window from closing/immediately-Console.ReadLineO;51CT0.COm技 术 成 就 梦 想要连接到服务器并向它发送一个字符串,客户代码(一个控制台应用程序)将是下面这样的:2005using System;using System.Collections.Generic;j$ing System.Text;using System.Net.Sockets;lamespace ClientCSclass Programconst in t portNo-500;static
24、void Main(string(args)TcpClient tcpclient new TcpClient();/-connect to the server-*tcpclient.Connect(*127.0.0.1,portNo);/-use a Networkstream object to send and receive/d a ta-Networkstream ns=tcpclient.GetStream();byte data Encoding.ASCII.GetBytes(Hello*);/-se n d the te x t-ns.Write(data,0,data.Le
25、ngth);U lulUsvUIII)牯*喏M拈 柿,-connect to the s e rv e r-tcpclient.Connect(127.0.0.1,portNo)-use a NetworkStream object to send and receive data-Dim ns As Networkstream=tcpclient.CetStreamDim data As Byte()Encoding.ASCII.GetBytes(Hello)send the text i P f i mns.Write(data,0,data.Length)End Sub*中 秒,、二:打
26、End Module注意,NetworkStream对象操作字节数组,因而需要使用来自System.Text命名空间的Encoding.ASCH.GetStringO和 Encoding.ASCILGetBytes。方法来将字节数组转换成字符串,反之亦然。上面的例子是比较简单的它包含了服务器代码和客户代码。服务器在127.0.0.1使用端口 5 0 0 打开一个套接字并监听外来T C P 连 接。当连接建立起来以后,由一个NetworkStream对象读取客户发来的数据。到达的数据随后显示在控制台上。另一方面,客户 在 127.0.0.1打开个连接,然后使用NetworkStream对象向服务
27、器发送个字符串。但是,当服务器需要同时与多个客户通信并能同时发送和接收消息时,问题就会变得复杂得多。为了实现这些,必须满足以下几条。服务器必须能够与多个客户建立连接。服务器必须能够从客户异步读取数据并能在任何时刻向客户发送消息。客户必须能够从服务器异步读取数据并能在任何时刻向服务器发送消息。接下来的几节将解决这3个问题。1.2.2 构建服务器(1)聊天程序有两个部件服务器和客户,我们来首先构建服务器。用Vistual Studio 2005创建个控制台程序项目,将该项目命名为Server。在默认的Module!.vb/Program.cs文件里,首先导入System.Net.Socket命名空
28、间,它包含这个项目将要用到的所有相关的类。接下来,声明一个常量来存储这个应用程序使用的端口号。对这个程序,我们使用端口号500-Visual Basic 2005Module ModulelConst portNo As Integer=500C#2005lass Program UaCOIl1 const i O菽”提示如果你在服务器(或者客户)上安装了防火墙,请确保打开端口 5 0 0,以便这个应用程序运行。我们还需要定义所要监听的本地地址,然后创建一个TcpListener类的实例,用来监听来自T C P客户的连接。_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
29、_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _Visual Basic 2005Sub Main()Dim localAdd As System.Net.IPAddress _System.Net.IPAddress.Par$e(127.0.0.1)Dim listener As New TcpListener(localAdd,portNo)Of 2005static void M ain(string args)System.Net.IPAddress localAdd=Sy stem.Net.I PAddress.P
30、ar se(12 7.0 ,TcpListener listener=new TcpListener(localAddj portNo);在Main。函数里,使 用 来 自 类TcpListener的Strait。方法来开始监听外来连接请求。AcceptTcpQientO方法是一个阻塞式的调用,直到连接建立起来以后程序才会继续执行。因为这个示例里的服务器需要同时为多个客户提供服务,我们将为每一个用户创建一个ChatClient类(稍后将定义)的实例。服务器将会无限地循环检查,若有客户请求连接,则接受。Visual Hasic 2005Sub Main()Dim localAdd As Syst
31、em.Net.IPAddress=_SystemNet.IPAddress.Parse(127.0.0.1*)Dim listener As New TcpListener(localAdd,portNo)listener.Start()While TrueDim user As New ChatClient(listener.AcceptTcpClient)End WhileEnd SubC#2005static void Hain(string args)51CTSystem.Net.IPAddress localAdd Systera.Net.IPAddress.Parse(127/(!
32、r.0:i,yrTcplistener listener=new TcpListener(localAdd,portNo);listener.Start。;while(true)ChatClient user=newcomChatClient(listener.AcceptTcpClient();)技 术 成 就 梦 想完整的Modulel.vb源文件如下所示。Dim user As New ChatClient(listener.AcceptTcpClient)End WhileEnd SubEnd ModuleC2005using Systetn;using System.Collecti
33、ons.Generic;using System.Text;using System.Met.Sockets;namespace server-CSclass Programconst in t portNo-SOO;static void M ain(string args)System.Het.IPAddress localAdd=System.Net.IPAddress.Parse(*127.0.0.1*);Tcplistener listener newlistener.S tart();while(true)TcpListener(locaLAdd,portNo);技 术 成 就 梦
34、 想C h a tC lie n t user newC h a tC lie n t(lis te n e r.A c c e p tT c p C lie n t();Sl dl kconi0大K t r蓟WB接下来定义ChatClient类。我们使用ChatClient类来表示连接到该服务器的每个客户的信息。在 Visual Studio 2 0 0 5 中 为 项 目 添 加 一 个 新 的 类,并 将 其 命 名 为ChatClienl.vb/ChatClient.cs。照例,第一步是导入 System.Net.Sockets 命名空间(对于代码的C#版本,还需要导入System.C
35、ollections命名空间)。V isual Basic 2005Imports System.Net.SocketsC#2005o w U I UB VU IIIjsing.StemeNet.Socke-U;jsinSyktem.CoI ted?io他1.2.2构建服务器(2)在 ChatClient类中,首先定义各种私有成员(它们的用途在代码注释中会有说明)。同时声明一个HashTable对 象(AllClients),用来保存所有连接到该服务器的用户的列表。将它声明为共享成员的原因是,确保ChatClient类的所有实例都能够获得当前连接到该服务器的所有客户的列举_ _ _ _ _ _
36、 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _C2005class ChatClientr/-contains a lis t of a ll the clientspublic static Hashtable AllClients=new Hashtable();/-information about the client-private TcpClient-client;private string c lie n t;private string _client
37、Nick;/-used for sending/receiving data-private byte(data;/-is the nickname being sentA-rprivate bool ReceiveNick true;当一个客户连接到服务器时,服务器将创建一个ChatClient类的实例,并将变量T叩Client(client)传递给类的构造函数。同时:我们取得客户的I P 地址并将它用作索引来标识HashTable对象中的客户。BeginRead。方法将在独立的线程中启动一个从Networkstream对象(client.GetStream)的异步读取。这样可以使服务器保持
38、响应能力并继续接受来自其他客户的新连接。读取完成以后,控制将被转移到ReceiveMessage。函数(此函数稍后将会定义)。.com02 0 0 5public ChatC1ie n t(TcpClient clie n t)-c lie n t=clie n t;/get the clie n t IP address_clientIP=c lie n t.Client.RemoteEndPoint.ToStringO;/add the current clie n t to the hash tableAllClients.Add(_clientIP,th is);/start read
39、ing data from the clie n t in a/separate threaddata-new byte(_client.ReceiveBufferSize;client.GetStream(),BeginRead(d3ta,0System.Convert.Tolnt32(_client.ReceiveBufFerSlteQ,ReceiveMessage,n u ll);在ReceiveMessage。函数中,首先调用EndRead。方法来处理异步读取的结尾。在这里,我们将检查读取的字节数是否小于1。如果是,则意味着客户已经断开连接,那么我们需要从HashTable对象中(使用
40、客户的IP地址作为表中的索引)删除该客户,同时使用Broadcast()函 数(此函数稍后定义)向所有客户广播消息,告知这特定客户已经离开了聊天。为了简单起见,假设客户会在第一次连接到服务器时发送他的昵称。此后,只需向所有人广播该客户发出的所有信息。一旦完成,服务器将再次执行从该客户的异步读取。BroadcastC-dientNick&_ has le ft the chat.)End TryEnd Sub2005public void ReceiveMessage(lAsyncResult ar)(/-read from c lie n t-in t bytesRead;try(lock(c
41、lient.GetStream()(一bytes Read _c 1 i ent.Get St ream().EndRead(ar).s ij U/-c lie n t has disconnected-i f (bytesRead 1)(AllClients.Remove(clientIP);Broadcast(_clientNick.*has le ft the chat.);return;)else(/-g e t the message s e n t-string messageReceived=System.Text.Encoding.ASCII.GetString(data,0,
42、bytesRead);/-c lie n t is sending its nickname-i f (ReceiveNick)(-dientN ick=messageReceived;/-te ll everyone client has entered the/chatBroadcast(_clientNick has joined the chat.);ReceiveNick-false;.com/-broadcast the message to everyone-Broadcast(-clientNick+messageReceived);)/-continue reading fr
43、om clie n t-lock(client.GetStream()(_client.GetStream().BeginReaci(data,0,System.Convert.Tolnt32(.clie n t ReceiveBufferSize),ReceiveMessage,n u ll);)catch(Exception ex)(AllClients.Remove(_clientIP);Broadcast(c lie n t Nick+ha 多*eft the c h k m il 技 术 成 就 梦 想i上面的代码里需要注意的一个问题是,需要使用SyncLock(C#中的lock)语
44、句来阻止多个线程同时使用Networkstream对象。当服务器连接到多个客户而且它们全都在同时刻试图访问Networkstream对象时,这一情况就可.能会出现。SendMessage()函数允许服务器向客户发送消息。C#2005public void SendMessage(string message)try/-send the text-System.Net.Sockets.Networkstream ns;lock(-client.GetStream()(ns-1ien t.GetStream();byte bytesToSend System.Text.Encoding.ASCII
45、.GetBytes(message);ns.Write(bytesToSend,0,bytesToSend.Length);ns.Flush();)catch(Exception ex)R1ATA nnmConsole.WriteLine(ex.ToStringO);最后,Broadcast。函数向存储在AllClients HashTabla对象中的所有客户发送消息。Visual Basic 2005Public Sub Broadcast(ByVai message As String)-log it loca lly-Console.WriteLine(message)Dim c As
46、DictionaryEntryFor Each c In AllClients,-broadcast message to a ll users-CType(c.Value,.ChatC1ient).SendMessage(message&vblf)NextEnd SubC#2005public void Broadcast(string message)/log it loca lly-L C O H lConsole.WritelinetiBessaggri.才 二 相foreach(D ic tio n a ry E n tIn/-broadcast message to a ll us
47、ers-(ChatClient)(c.Value).message Enviro.*ssage);技 术 成 就 替 翅/-s en d the t e x t-ns.W rite(data,0,data,Length);ns.Flush();catch(Exception ex)MessageBox.Show(ex.ToS tringO);ReceiveMessage。子程序在一个独立的线程里异步读取从服务器发来的数据。收到数据时,它把数据显示在txtMessageHistory控件里。因为Windows控件不是线程安全的,你需要使用一个代理(delUpdateHistory()来更新该控件
48、。线程安全默认情况下,W indows应用程序使用单个的执行线程。而当你有多个执行线程(正如使 用ReceiveMessage()子程序在这里所做的一样)并试图更新来自不同线程的U I时,情况会变得稍稍复杂一些。应该记住的是,我们无法直接访问独立线程(相对于所在的主线程而言)里W indows控件的属性,因为Windows控件不是线程安全的。试图这么做将会引发运行时错误,这是VisualStudio 2005新加入的个有用的特性。相反,我们应该使用代理,并且使用要更新的控件/窗体的Invoke()/BeginInvoke()方法来调用它。C*2005public void ReceiveMes
49、sage(lAsyncResult ar)(try(int bytesRead;/-read the data from the server-bytesRead=client.GetStream().EndRead(ar);i f (bytesRead 1)(return;else(/-invoke the delegate to display the/received dataobject口 para System.Text.Encoding.ASCII.GetString(data,0,bytesRead);this.Invoke(new dell)pdateHistory(Updat
50、eHistory),para);)/-continue reading.-client.GetStream().BeginRead(data,0,System.Convert.ToInt32(client.Receive8ufferSize),ReceiveMessage,null);)catch(Exception ex)R1PTA nnm/-ignore the error;fired wtm a user signs)丁*献赫娱使用代理delUpdateHistory。来调用主线程里的UpdateHistoryO函数。52005/-delegate and subroutine to u