1、第十一章系统升级系统升级章节任务任务:升级更新系统任务:升级更新系统章节目标l了解组网、多线程及委托的知识l学习如何通过Winform访问 Internetl掌握套接字编程 系统做好之后,还需不断的维护。本章所做的升级程序能使用户方便地更新客户端系统,使维护更加方便。10.1 背景知识介绍1组网组网是将许多设备(如计算机、打印机和工作站)连接成一个网络以共享资源。如图所示,将一台打印机物理连接至某台计算机,然后将所有的计算机连接后组成一个网络。这样,每台计算机通过网络都可以共享这台打印机,从而减少了成本,节约了费用。在该网络中,直接连接打印机的计算机是服务器,其它计算机是客户端,二者是提供服务
2、和享有服务的关系。2统一资源标识符.NET框架使用统一资源标识符(URI)来标识图所请求的Internet资源和通讯协议。URI至少由三个(也可能是四个)片段组成:方案标识符(标识用于请求和响应的通讯协议)、服务器标识符(由域名系统(DNS)主机名或TCP地址组成,用于唯一标识Internet上的服务器)、路径标识符(定位服务器上请求的信息)以及可选的查询字符串(将信息从客户端传送到服务器)。3Internet应用程序Internet应用程序大体上分为两类:客户端应用程序和服务器应用程序。典型的Internet客户端-服务器应用程序是万维网,在万维网中,人们使用浏览器来访问世界各地的Web服务
3、器上存储的文档和其他数据。应用程序并不限于仅充当其中的一个角色;例如,大家所熟悉的中间层应用程序服务器通过请求其他服务器的数据来响应客户端的请求,在这种情况中,它既作为服务器,也作为客户端。客户端应用程序通过标识所请求的Internet资源以及用于该请求和响应的通讯协议来发出请求。如有必要,客户端还提供完成请求所需的任何附加数据,例如代理位置或身份验证信息(用户名、密码等)。只要构成了请求,就可以将该请求发送到服务器。4多线程(1)基本概念进程是指在系统中正在运行的一个应用程序。进程包括运行中的程序和程序所使用到的内存和系统资源,一个进程是由多个线程组成的。线程:线程是程序中的一个执行流,每个
4、线程都有自己的专有寄存器(栈指针、程序计数器等),但代码区是共享的,即不同的线程可以执行同样的函数。多线程:一个进程至少包括一个线程,通常将该线程称为主线程。一个进程从主线程的执行开始进而创建一个或多个附加线程,就是所谓基于多线程的多任务。(2)多线程的优劣优点:可以提高CPU的利用率。在多线程程序中,一个线程必须等待的时候,CPU可以运行其它的线程而不是等待,这样就大大提高了程序的效率。缺点:线程也是程序,所以线程需要占用内存,线程越多占用内存也越多;多线程需要协调和管理,所以需要CPU时间跟踪线程;线程之间对共享资源的访问会相互影响,必须解决竞用共享资源的问题;线程太多会导致控制太复杂,最
5、终可能造成很多Bug;(3)控制线程的类和方法在.NET中,多线程的功能定义在System.Threading命名空间中。要使用多线程,必须先声明引用此命名空间。具体使用的类是:System.Threading.Thread,Thread类的方法如下所列。Start():启动一个线程Sleep(int):静态方法,暂停当前线程指定的毫秒数Abort():通常使用该方法来终止一个线程Join():禁止调用线程,直到线程终止Interrupt():中止处于Sleep或者Join线程状态的线程Suspend():该方法并不终止未完成的线程,它仅仅挂起线程,以后还可恢复Resume():恢复被Susp
6、end()方法挂起的线程的执行(4)Thread.ThreadState属性使用线程的ThreadState属性可以确定线程当前的状态,这个状态将是ThreadState枚举中指定的一个值,如下所列。Aborted:线程已停止AbortRequested:线程的Thread.Abort()方法已被调用,但是线程还未停止Background:线程在后台执行Running:线程正在正常运行Stopped:线程已经被停止StopRequested:线程正在被要求停止Suspended:线程已经被挂起SuspendRequested:线程正在要求被挂起,但是未来得及响应Unstarted:未调用Thr
7、ead.Start()开始线程的运行WaitSleepJoin:线程因为调用了Wait(),Sleep()或Join()等方法处于封锁状态(5)线程的生命周期与人有生老病死一样,线程也同样要经历开始(等待)、运行、挂起、封锁和停止几种不同的状态。这几种状态都可以通过Thread类中的方法进行控制。下图是几种状态之间的转换和相关的方法。(6)线程的优先级在一个应用程序中可能存在多个线程。如果创建了多个线程并要执行这些线程,那操作系统如何知道先运行哪一个线程?解决办法是可以对每个线程都指定优先级。Thread类中有一个ThreadPriority属性,它用来设置优先级,但不能保证操作系统会接受该优
8、先级。线程的优先级由高到低分别是Highest,AboveNormal,Normal,BelowNormal,Lowest。系统默认为ThreadPriority.Normal。指定优先级的代码是:myThread.Priority=ThreadPriority.Lowest;(7)线程实例演示线程实例。程序启动后,开始运行主线程,接着启动子线程,然后让主线程休眠1ms后,终止子线程,主线程等待直到子线程结束。最后程序又重启终止的子线程,则产生异常。【例11-1】主、子线程运行实例。5Control.Invoke在多线程的WinForms程序中,通过非创建控件的线程调用控件的的属性和方法是非法
9、的,所有跨进程的调用必须被明确地排列至创建控件的线程中(通常为主线程)。因为从另外一个线程操作windows窗体上的控件(运行在主线程),就会和主线程产生竞争,造成不可预料的结果,甚至死锁。所以windowsGUI编程有一个规则,就是只能通过创建控件的线程来操作控件的数据。因此,.net为解决这个问题,由Control类提供了Invoke方法,实现了其它线程更新GUI界面控件的机制。这样,如果从线程外操作windows窗体控件,就可使用Invoke方法,通过一个委托把调用封送到控件所属的线程上执行。Invoke方法需要一个委托对象作为参数(委托是一个可以对方法进行引用的类)。调用者通过Invo
10、ke方法中的委托参数就可以把需要调用的函数地址封送给界面线程。这些方法里面如果包含了更改控件状态的代码,那么由于最终执行这个方法的是界面线程,从而避免了竞争条件,避免了不可预料的问题。与其他的类不同,委托类具有一个签名,并且它只能对与其签名匹配的方法进行引用。Invoke方法中不带参数和带参数的委托签名如下:Control.Invoke(DelegateMethod)Control.Invoke(DelegateMethod,paramsobjectargs)6tcp/ip协议和端口(1)TCP/IP协议TCP/IP协议是物理网上的一组完整的网络协议。协议的基本传输单位是数据包,TCP协议负责
11、把数据分成若干个数据包,并给每个数据包加上包头(就像给一封信加上信封),包头上有相应的编号,以保证在数据接收端能将数据还原为原来的格式,IP协议在每个包头上再加上接收端主机地址,这样数据找到自己要去的地方(就像信封上要写明地址一样),如果传输过程中出现数据丢失、数据失真等情况,TCP协议会自动要求数据重新传输,并重新组包。总之,IP协议保证数据的传输,TCP协议保证数据传输的质量。TCP/IP协议的核心部分是传输层协议(TCP、UDP),网络层协议(IP)和物理接口层,这三层通常是在操作系统内核中实现,用户一般不涉及。编程时,编程界面有两种形式:由内核直接提供的系统调用和以库函数方式提供的各种
12、函数。前者为核内实现,后者为核外实现。用户服务要通过核外的应用程序才能实现,这样就需要使用套接字(socket)。如图11-3是TCP/IP协议核心与应用程序关系图。(2)端口一般来说我们的计算机上运行着非常多的应用程序,它们可能都需要同远程主机打交道,所以远程主机就需要有一个ID来标识它想与本地机器上的哪个应用程序打交道,这里的ID就是端口。将端口分配给一个应用程序,那么来自这个端口的数据则总是针对这个应用程序的。在Internet中,TCP/IP使用一个网络地址和一个服务端口号来唯一标识设备。网络地址标识网络上的特定设备,端口号标识要连接到的该设备上的特定服务。11.2 .Net 框架中的
13、Internet访问1Net类的网络服务层次Microsoft.Net框架为应用程序访问Internet提供了分层的、可扩展的以及受管辖的网络服务,其名字空间System.Net和System.Net.Sockets包含丰富的类可以开发多种网络应用程序。.Net类采用的分层结构允许应用程序在不同的控制级别上访问网络,开发人员可以根据需要选择针对不同的级别编制程序,这些级别几乎囊括了Internet的所有需要-从socket套接字到普通的请求/响应,更重要的是,这种分层是可以扩展的,能够适应Internet不断扩展的需要。抛开ISO/OSI模型的7层构架,单从TCP/IP模型上的逻辑层面上看,.
14、Net类可以视为包含3个层次:请求/响应层、应用协议层、传输层。WebReqeust和WebResponse代表了请求/响应层,支持Http、Tcp和Udp的类组成了应用协议层,而Socket类处于传输层。如下图示。可见,传输层位于这个结构的最底层,当其上面的应用协议层和请求/响应层不能满足应用程序的特殊需要时,就需要使用这一层进行Socket套接字编程。2.NET框架中的请求和响应在.NET框架中,可使用特定类来访问Internet,如WebRequest-WebResponse、HttpWebRequest-HttpWebResponse、WebClient、TcpClient及Socke
15、t,其中前三者比较简单,后两者比较底层。对于简单的Internet访问,WebClient类可提供从Internet服务器上载、下载数据最简便的方法:可用来上传和下载文件、发送和接收流以及将数据缓冲区发送到服务器并接收响应。WebClient使用WebRequest和WebResponse类来建立与Internet资源的实际连接。对于复杂的Internet访问,客户端应用程序可使用WebRequest及其子类来请求服务器中的数据。WebRequest封装了连接到服务器、发送请求并接收响应的详细信息。由于WebRequest和WebResponse都是抽象基类,所以由其子类(例如HttpWebR
16、equestHttpWebResponse)实现其定义的属性和方法。对于不能使用请求/响应模型的应用程序而言,或者对于需要侦听网络并发送请求的应用程序而言,System.Net.Sockets命名空间提供TCPClient类、TCPListener类和UDPClient类。这些类处理使用不同的传输协议建立连接的详细信息,并且作为流向应用程序公开网络连接。3.NET网络访问命名空间WinForms网络编程中用到System.Net和System.Net.Sockets命名空间。System.Net命名空间主要处理高层的操作,例如下载和上载文件;System.Net.Sockets包含执行低层操作
17、的类,处理用于让计算机之间高效通信的代码(1)System.Net命名空间System.Net命名空间对System.Net.Sockets中的基础网络通信类库作了一些封装,使得对一些高端应用的编程更为简单、方便。System.Net命名空间中最为核心的类是WebRequest和WebResponse,这两个抽象类是协议实现的基础。Net命名空间核心类如下所列:IPAddress:描绘一个IP地址WebClient:发送或接收来自url的数据WebRequest:抽象类,封装与服务器连接、发送请求和接收响应的详细信息WebResponse:抽象类,通过WebRequest实例调用GetResp
18、onse()方法来创建该对象2System.Net.Sockets命名空间System.Net.Sockets封装了网络通信的基础类库,核心的类是Socket,它是最基础的网络编程接口。下面列出了本书涉及到的类。Socket:实现了Sockets编程接口,有大量属性和方法用于网络连接NetworkStream:由Stream派生,表示来自网络的数据流TcpClient:可以连接到服务器的TCP客户端封装类TcpListener:用于从TCP网络客户侦听TCP连接请求的服务器端封装类UdpClient:用于为UDP客户端创建连接的通信封装类,主要用于本地网络11.3.Net 框架中的Intern
19、et访问万维网是一个客户端/服务器应用程序,借助浏览器对世界各地的Web服务器上存储的数据进行访问。通过System.Web命名空间下的WebClient类,可以实现向Internet资源发送和接收数据。该类不能继承,可用来从URI标识的任何Internet资源请求并接收文件。11.4 使用webRequestwebResponse访问InternetWebClient是通用类,使用起来比较简单,主要用于处理发送请求和接收响应的协议。它不能处理任一协议的任何附加特性,如果想利用这些特性,就需要使用以WebRequest类和WebResponse类为基类的一系列类。WebRequest和WebR
20、esponse类都是抽象基类。在实际工作中,WebRequest和WebResponse更适合用来处理相对较为简单的带认证信息的HTTP请求。如果认证信息不是必需的,那么使用WebClient类要更好一些。如果需要发送一个HTTPPOS请求,那么HttpWebRequest和HttpWebResponse类通常是更好的选择。WebRequest类通过使用传递到其Create方法的URI值来确定要创建的特定派生类实例。通过调用WebRequest实例上的GetResponse方法来建立对Internet资源的请求。对于将数据发送到服务器的请求,WebRequest.GetRequestStrea
21、m方法提供要将数据发送到其中的网络流。GetResponse方法返回与WebRequest匹配的特定协议的WebResponse,如以下语句所示。WebRequestreq=WebRequest.Create();WebResponseresp=req.GetResponse();如果应用程序只需要WebResponse中返回的标头信息并忽略任何返回的数据,则不必获取响应流。下面的代码示例显示如何从Internet主机返回服务器标头信息。WebRequestwReq=WebRequest.Create();WebResponsewResp=wReq.GetResponse();stringse
22、rver=wResp.HeadersServer;wResp.Close();11.5 使用HttpWebRequest-HttpWebResponse访问Internet.NET框架使用HttpWebRequest和HttpWebResponse类来提供对HTTP协议的全面支持。每当静态方法WebRequest.Create遇到以“http”或“https”开头的URI时,在默认情况下将返回从WebRequest和WebResponse派生的类。多数情况下,WebRequest和WebResponse类提供生成请求所需的一切,但如果需要访问作为属性公开的HTTP特定功能,则可以将这些类的类型
23、转换为HttpWebRequest或HttpWebResponse。以下代码显示如何访问HTTP特定的属性,在这里是从Web服务器获取协议版本号。HttpWebRequestHttpWReq=(HttpWebRequest)WebRequest.Create();HttpWebResponseHttpWResp=(HttpWebResponse)HttpWReq.GetResponse();/从Web服务器获取http协议版本号Stringver=HttpWResp.ProtocolVersion.ToString();Console.Write(http协议的版本号是:+ver);HttpW
24、Resp.Close();11.6 SOCKET编程1套接字定义套接字(SOCKET)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。可以将套接字看作不同主机间的进程进行双向通信的端点,它构成了在单个主机内及整个网络间的编程界面,是WindowsSockets应用程序用来在网络上发送或接收数据包的对象。Socket作为tcpip网络协议接口,内部定义了许多的函数和例程。在网络通信中,两个主机或两个进程通过网络来传递数据,程序在网络对话的每一端都需要一个socket。根据通信性质分类,套接字有两种不同的类型:流套接字和数据报套接字。(1)流套接字流套接字提供双向的、有序的、无重复并
25、且无记录边界的数据流,即字节流。字节流能确保以正确的顺序无重复地被送达,它适用于处理大量数据。流套接字是面向连接的,通信双方进行数据交换之前,必须建立一条路径,这样既确定了它们之间存在的路由,又保证了双方都是活动的、可彼此响应的。(2)数据报套接字数据报套接字支持双向的数据流,但并不保证数据传输的可靠性、有序性和无重复性。也就是说,一个从数据报套接字接收信息的进程有可能发现信息重复,或者和发出时的顺序不同的情况。所以,数据报并不十分可靠,需有程序员负责管理数据报的排序和可靠性。2套接字编程概述谈起socket编程,大家也许会想起QQ和IE。还有许多网络工具如P2P、NetMeeting等在应用
26、层实现的应用程序,也是用socket来实现的。在.Net中,System.Net.Sockets命名空间为需要严密控制网络访问的开发人员提供了WindowsSockets接口的托管实现。System.Net命名空间中的所有其他网络访问类都建立在该套接字Socket实现之上,如TCPClient、TCPListener和UDPClient类封装有关创建到Internet的TCP和UDP连接的详细信息;NetworkStream类则提供用于网络访问的基础数据流等,常见的许多Internet服务都可以见到Socket的踪影,如Telnet、Http、Email、Echo等,这些服务尽管通讯协议Pro
27、tocol的定义不同,但是其基础的传输都是采用的Socket。所以,Socket象流Stream一样被视为一个数据通道,这个通道架设在客户端和远程服务器端之间,数据的读取和写入均针对这个通道来进行。使用socket开发程序时,通常使用或ukp两种协议。Tcp是面向连接的协议,提供了可靠的数据传输,使用tcp套接字进行通信首先让客户端连接到服务器,然后才可以进行通信;udp是面向无连接的协议。当数据被发送以后,不管数据是否到达,程序都不会重新发送。3基于TCP协议的socket编程(1)TCP编程类.NetFrameWork为Socket通讯提供了System.Net.Sockets命名空间,在
28、这个命名空间里包含了允许直接发送TCP网络请求或侦听特定端口上的TCP网络请求的相关类:TCPClient和TCPListener,应用程序可以通过这两个类使用TCP服务。TcpClient和TcpListener与套接字socket的关系如图所示从图中可以看出TcpClient和TcpListener对套接字进行了封装。TcpListener用于接受连接请求,而TcpClient则用于接收和发送流数据。TcpListener持续地保持对端口的侦听,一旦收到一个连接请求后,就可以获得一个TcpClient对象,而对于数据的发送和接收都由TcpClient去完成。此时,TcpListener并没
29、有停止工作,它始终持续地保持对端口的侦听状态。现在分别对TCPClient和TCPListener进行介绍1)TcpClient类:为TCP网络服务提供客户端连接。该类提供了一些简单的方法,通过网络来连接、发送和接收流数据。TcpClient类常用的方法及功能描述如下所示Close:关闭所有TCP连接并释放与TcpClient关联的资源Connect:将使用主机名和端口号将客户端连接至远程TCP主机GetStream:返回用于发送和接收数据的NetworkStream2)TCPListener类:具有侦听进入的TCP连接的方法,其中Start()方法用于开始侦听进入的连接请求,并且将把进入的连
30、接放置在队列中,直到调用Stop()为止。AcceptSocket()或AcceptTcpClient()方法可用于从进入的连接请求队列中提取连接,如下所列。AcceptSocket:返回与远程客户端通信的套接字AcceptTcpClient:接受暂挂的连接请求Start:开始侦听传入的连接请求Stop:关闭侦听器(2)实现过程及步骤服务端实现监听连接,客户端实现发送连接请求,建立连接后进行发送和接收数据的功能。在服务器端,首先建立服务器端socket,然后,用Listening方法侦听应用程序等待用户端的连接,当接收到来自用户端的连接请求时,以Accept方法建立与用户端的连接。接下来传送数
31、据,用Receive及Send方法接收及传送数据,最后以Close方法关闭服务器端的Socket。在客户端,创建的Socket以Connect方法建立与服务器的连接,当服务器端收到连接请求时,由服务器端的Accept方法建立此连接,接着用Receive及Send方法接收及传送数据,最后以Close关闭Socket连接服务器端与客户端的通信过程如下图所示演示【例11-7】设计一个客户端/服务器程序,客户端将信息发往服务器,服务器将信息倒序后,再返回到客户端。下面分两部分来做,先完成服务器端程序,以下是完成步骤。一、服务器程序二、客户端程序2基于udp协议的socket编程在应用程序中,当速度和性
32、能的需求比可靠性更重要时,开发人员可以使用UDP(r用户数据报协议)。UDP的优点是简单易用,但由于UDP协议是一个无连接协议,因此发送到远程终结点的UDP数据文报不一定能够到达,也不一定能够以发送的相同顺序到达。使用UDP的应用程序必须准备处理丢失的和顺序有误的数据文报。C#为UDP提供了相应的类:UDPClient。与TcpClient相比,UdpClient类的接口更小且更简单;UdpClient不包含返回网络流以进行读写的方法,因为UDP是无连接协议,所以与远程主机的连接是在发送和接收数据时进行的。UdpClient类提供了一些简单的方法,用于发送和接收无连接UDP数据报。可以使用Ud
33、pClient中提供的任何一种发送方法将数据发送到远程设备。使用Receive方法可以从远程主机接收数据,如图所示。UdpClient类常用的方法及描述如下所列。Connect()建立与远程主机的连接Receive()返回由远程主机回馈的UDP数据报Send()将UDP数据报发送到远程主机Close()关闭UDP连接演示演示【例11-8】在UDP模式下,不存在明显的服务器与客户端之分。本例要实现的功能是从A端到B端的点对点通信。综合案例为系统添加升级程序本部分案例开发系统的升级更新部分,对应的进入菜单如下图所示。鼠标单击图中的菜单“升级更新”,由此进入系统的升级客户端,代码如下。private
34、voidUpdateToolStripMenuItem_Click(objectsender,EventArgse)Processprocess=newProcess();process.StartInfo.=.UpdateClientobjReleaseUpdateClient.exe;process.Start();本系统的升级程序分为两部分:Server端和Client端,在此作整体架构介绍,具体实现的细节代码参看项目UpdateClient及UpdateServer。小结 本章讲述了在.NET中,实现网络编程的基本概念及几种访问方式,其中主要阐述了SOCKET编程,并掌握了端口侦听、网络连接申请、数据发送及数据接收的具体方法。而且本章还讲述了实现网络功能所必然要涉及到的如线程创建、线程销毁等实现方法。最后以一个综合实例阐述了通过Socket编程实现网络聊天的功能。此课件下载可自行编辑修改,供参考!感谢您的支持,我们努力做得更好!