700 likes | 919 Views
C# 网络编程技术教程. 第五章 C# 网络编程方法概述. 学习目标. 了解 TCP/IP 结构及其基本概念。 掌握 .NET 网络编程基础知识。 掌握套接字编程的基本原理。 掌握 C# 中的多线程编程方法。. 本章内容. 5.1 TCP/IP 概述 5.2 .NET 网络编程基础 5.3 套接字编程 5.4 多线程编程 5.5 基于多线程的编程实例. 5.1 TCP/IP 概述. 5.1.1 OSI 参考模型与 TCP/IP 模型. 1 . OSI 参考模型
E N D
C#网络编程技术教程 第五章 C#网络编程方法概述
学习目标 • 了解TCP/IP结构及其基本概念。 • 掌握.NET网络编程基础知识。 • 掌握套接字编程的基本原理。 • 掌握C#中的多线程编程方法。
本章内容 5.1 TCP/IP概述 5.2 .NET网络编程基础 5.3 套接字编程 5.4 多线程编程 5.5 基于多线程的编程实例
5.1 TCP/IP概述 5.1.1 OSI参考模型与TCP/IP模型 1.OSI参考模型 在计算机网络产生之初,每个计算机厂商都有一套自己的网络体系结构的概念,它们之间互不兼容。为此,国际标准化组织(ISO)在1979年成立了一个分委员会来专门研究一种用于开放系统互连的体系结构(Open Systems Interconnection,OSI)。其中“开放”这个词表示:只要遵循OSI标准,一个系统可以和位于世界上任何地方的、也遵循OSI标准的其他任何系统进行连接。这个分委员会提出了开放系统互连,即OSI参考模型,它定义了连接不同类型计算机的标准框架。 OSI参考模型将计算机网络通信定义为一个七层框架模型,如图5.1所示。这七层分别是物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。 图5.1 OSI参考模型
5.1 TCP/IP概述 5.1.1 OSI参考模型与TCP/IP模型 各层的主要功能及其相应的数据单位如下: (1)物理层(Physical Layer) 要传递信息就要利用一些物理媒体,如双绞线、同轴电缆等,但具体的物理媒体并不在OSI的七层之内,有人把物理媒体当作第0层,物理层的任务就是为它的上一层提供一个物理连接,以及它们的机械、电气、功能和过程特性。如规定使用电缆和接头的类型,传送信号的电压等。在这一层,数据还没有被组织,仅作为原始的位流或电气电压处理,单位是比特。 (2)数据链路层(Data Link Layer) 数据链路层负责在两个相邻结点间的线路上,无差错地传送以帧为单位的数据。每一帧包括一定数量的数据和一些必要的控制信息。和物理层相似,数据链路层负责建立、维持和释放数据链路的连接。在传送数据时,如果接收点检测到所传数据中有差错,就要通知发送方重发这一帧。 (3)网络层(Network Layer) 在计算机网络中进行通信的两个计算机之间可能会经过很多个数据链路,也可能还要经过很多通信子网。网络层的任务就是选择合适的网间路由和交换结点,以确保数据及时传送。网络层将数据链路层提供的帧组成数据包,包中封装有网络层包头,其中含有逻辑地址信息(源站点和目的站点地址的网络地址)。
5.1 TCP/IP概述 5.1.1 OSI参考模型与TCP/IP模型 (4)传输层(Transport Layer) 传输层的任务是根据通信子网的特性来最佳地利用网络资源,并以可靠和经济的方式,为两个端系统(也就是源站和目的站)的会话层之间,提供建立、维护和取消传输连接的功能,并负责可靠地传输数据。在这一层,信息的传送单位是报文。 (5)会话层(Session Layer) 会话层也称为会晤层或对话层,在会话层及以上的高层次中,数据传送的单位不再另外命名,都统称为报文。会话层不参与具体的传输,它提供包括访问验证和会话管理在内的建立和维护应用之间通信的机制。如服务器验证用户登录便是由会话层完成的。 (6)表示层(Presentation Layer) 表示层主要解决用户信息的语法表示问题。它将欲交换的数据从适合于某一用户的抽象语法,转换为适合于OSI系统内部使用的传送语法。即提供格式化的表示和转换数据服务。数据的压缩和解压缩,加密和解密等工作都由表示层负责。
5.1 TCP/IP概述 5.1.1 OSI参考模型与TCP/IP模型 (7)应用层(Application Layer) 应用层确定进程之间通信的性质以满足用户需要以及提供网络与用户应用软件之间的接口服务。 当然,OSI参考模型只是一个框架,它的每一层并不执行某种功能。在这个OSI七层模型中,每一层都为其上一层提供服务,并为其上一层提供一个访问接口或界面。不同主机之间的相同层次称为对等层。如主机A中的表示层和主机B中的表示层互为对等层,主机A中的会话层和主机B中的会话层互为对等层等。对等层之间互相通信需要遵守通信协议,主要通过软件来实现。每一种具体的协议一般都定义了OSI模型中的各个层次具体实现的技术要求,主机正是利用这些协议来接收和发送数据的。
5.1 TCP/IP概述 5.1.1 OSI参考模型与TCP/IP模型 2.TCP/IP模型 OSI参考模型的提出是为了解决不同厂商、不同结构的网络产品之间互连时遇到的不兼容性问题。但是该模型的复杂性阻碍了其在计算机网络领域的实际应用。与此相反,由技术人员自己开发的传输控制协议/网际协议(Transfer Control Protocol/Internet Protocol,TCP/IP)协议栈模型都获得了更为广泛的应用,成为因特网的基础。实际上,TCP/IP协议也是目前因特网范围内运行的唯一一种协议。TCP/IP模型和OSI参考模型的对比示意图,如图5.2所示。 TCP/IP模型是美国国防部高级研究计划局计算机网(Advanced Research Projects Agency Network,ARPANET)和其后继因特网使用的参考模型。ARPANET是由美国国防部(U.S.Department of Defense,DoD)赞助的研究网络。最初,它只连接了美国境内的四所大学。但在随后的几年中,它通过租用的电话线连接了数百所大学和政府部门。最终ARPANET发展成为全球规模最大的互连网络—因特网。
5.1 TCP/IP概述 5.1.1 OSI参考模型与TCP/IP模型 从名字上看,TCP/IP包括两个协议,即传输控制协议(Transfer Control Protocol,TCP)和网际协议(Internet Protocol,IP),但实际上TCP/IP是一系列协议的代名词,它包括上百个各种功能的协议,如:地址解析协议(ARP)、Internet控制消息协议(ICMP)、文件传输协议等,而TCP协议和IP协议只是保证数据完整传输的两个重要协议。通常讲TCP/IP,但实际上指的是因特网协议系列,而不仅仅是TCP和IP两个协议,所以也常称为TCP/IP协议族。该协议族分为四个层次:链路层、网络层、传输层和应用层。其各层所包含的主要协议如图5.3所示,具体各层所负责的功能如下。 图5.2 OSI参考模型与TCP/IP模型对比 图5.3 TCP/IP协议族
5.1 TCP/IP概述 5.1.1 OSI参考模型与TCP/IP模型 (1)链路层 链路层是TCP/IP协议族的最低层,有时也被称作数据链路层或网络接口层,通常包括操作系统中的设备驱动程序和计算机中对应的网络接口卡,它们一起处理与电缆(或其他任何传输媒体)的物理接口。该层负责接收IP数据报并通过网络发送到网络传输媒体上,或者从网络上接收物理帧,抽出IP数据报交给IP层。实际上,TCP/IP模型并没有真正描述这一层的实现,只是要求能够提供给其上层(网络层)一个访问接口,以便在其上传递IP分组。由于这一层次未被定义,所以其具体的实现方法也随着网络类型的不同而不同。 (2)网络层 网络层是整个TCP/IP协议栈的核心,有时也被称为互联网层或IP层。该层的主要功能是把分组发往目标网络或主机。同时,为了尽快发送分组,可能需要沿不同的路径同时进行分组传递。因此,分组到达的顺序和发送的顺序可能不同,这就需要上层对分组进行排序。网络层除了完成上述功能外,还完成将不同类型的网络(异构网)进行互连的功能。除此之外,网络层还需要完成拥塞控制的功能。 在TCP/IP协议族中,网络层协议包括IP协议(网际协议)、ICMP协议(因特网控制报文协议)和IGMP协议(因特网组管理协议)。
5.1 TCP/IP概述 5.1.1 OSI参考模型与TCP/IP模型 (3)传输层 传输层主要为两台主机上的应用程序提供端到端的数据通信,它分为两个协议:TCP(传输控制协议)和UDP(用户数据报协议)。TCP提供有质量保证的端到端的数据传输。若传输层使用TCP协议,则该层负责数据的分组、质量控制和超时重发等,对于应用层来说,就可以忽略这些工作。UDP则只负责简单地把数据报从一端发送到另一端。若传输层使用UDP协议,则数据是否到达、是否按时到达、是否损坏都必须由应用层来控制。这两种协议各有用途,前者可用于面向连接的应用,后者则在及时性服务中有着重要的用途,如网络多媒体通信等。 (4)应用层 应用层负责处理实际的应用程序细节,主要包括超文本传输协议(HTTP)、简单网络管理协议(SNMP)、文件传输协议(FTP)、简单邮件传输协议(SMTP)、域名系统(DNS)、远程登录协议(Telnet)等。其中,有些应用层协议是基于TCP来实现的,例如FTP、HTTP等,有些则是基于UDP来实现的,如SNMP等。
5.1 TCP/IP概述 5.1.1 OSI参考模型与TCP/IP模型 3.TCP/IP工作原理 由上述OSI参考模型可知,在因特网上源主机的协议层与目的主机的同层通过下层提供的服务实现对话。TCP/IP协议族模型也是按照这一原则来工作的。它们之间的对话实际上是在源主机上从上到下传递然后穿越网络到达目的主机后再从下到上到达相应层。 下面以图5.4中的客户机A(信源)和服务器B(信宿)之间采用应用层协议HTTP协议提交数据请求为例,说明TCP/IP的工作原理。
5.1 TCP/IP概述 5.1.1 OSI参考模型与TCP/IP模型 图5.4中的逻辑传输线路表明了数据传输的方向,以及信源和信宿,实际传输线路则表明了请求数据的真实传输链路。请求数据从信源传输到目的信宿的过程可描述如下: (1)在信源上,利用应用层协议(HTTP)将需传输的请求数据流传送给信源上的传输层(TCP)。 (2)信源上的传输层将应用层的请求数据流截成若干分组,并加上TCP首部形成TCP段,送交信源上的网络层(IP)。 (3)信源的网络层给TCP段加上包括源、目的主机IP地址的IP首部,生成一个IP数据报,并将IP数据报送交信源的链路层。 (4)信源的链路层在其MAC帧的数据部分装上IP数据报,再加上源、目的主机的MAC地址和MAC帧头,并根据其目的MAC地址,将MAC帧发往信宿或中间路由器,例如路由器R。 (5)路由器是一个具有多个接口的网络互连设备,可以把数据从一个网络转发到另一个网络。当数据传输到路由器后,路由器将根据数据包中的目的地址进行传输路径的选择,并根据所选择的传输路径进行数据传输。通常,路由器只处理链路层和网络层的数据。在本实例中,路由器接收客户机A发送过来的IP数据报,并将该数据报转发给服务器B。
5.1 TCP/IP概述 5.1.1 OSI参考模型与TCP/IP模型 (6)当数据传输到信宿,链路层将MAC帧的帧头去掉,并将IP数据报送交信宿的网络层。 (7)信宿的网络层检查IP数据报首部,假如首部中校验和与计算结果不一致,则丢弃该IP数据报;若校验和与计算结果一致,则去掉IP首部,将TCP段送交信宿的传输层。 (8)信宿的传输层检查顺序号,判定是否是正确的TCP分组,然后检查TCP首部数据。若正确,则向信源发确认信息;若不正确或丢包,则向信源要求重发信息。 (9)信宿的传输层去掉TCP首部,将排好顺序的分组组成应用数据流送给信宿上相应的应用程序。这样信宿接收到的来自信源的字节流,就像是直接接收到来自信源的字节流一样。
5.1 TCP/IP概述 5.1.2 TCP/IP基本概念 1.IP地址 IP 地址是进行TCP/IP协议通信的基础,IP地址是对连接在因特网中的设备进行唯一性标识的设备编码,与日常生活中寄信时所用的信箱号类似,以便设备之间能根据IP地址来识别。在因特网中,根据TCP/IP协议规定,在IPv4中,IP地址由32位二进制数组成,其地址空间是0~232-1。为了便于记忆,将这32位二进制数分成四段,每段8位,中间用小数点隔开,将每八位二进制数转换成一位十进制数,这样就形成了点分十进制的表示方法。例如:192.168.0.181。一个简单的IP地址的格式为:IP地址 = 网络地址 + 主机地址,包含了网络地址和主机地址两部分重要的信息。由于IPv4定义的有限地址空间将被耗尽,地址空间的不足必将影响因特网的进一步发展。所以在最新出台的IPv6中IP地址升至128位。 IP地址共分五类:A类、B类、C类、D类和E类。其中A类、B类和C类为基本类;D类用于多播传送;E类属于保留类,暂未使用。它们的格式如下所示,其中“*”代表网络号位数。
5.1 TCP/IP概述 5.1.2 TCP/IP基本概念 A类地址的最高位必须是“0”,其第一个字节为网络地址,后三个字节为主机地址。因此A类地址可拥有126个网络地址数,其中每个网络最多可以包含的主机数目为224-2(主机地址全1和全0都属于特殊地址),即有16777214台主机。因此,A类地址适用于超大规模的网络。 B类地址的最高两位必须是“10”,前两个字节为网络地址,后两个字节为主机地址。B类IP地址中网络地址长度为14位,有16384个网络,其中每个网络最多可以包含的主机数目为216−2,即有65534台主机。因此,B类地址适用于中等规模的网络。
5.1 TCP/IP概述 5.1.2 TCP/IP基本概念 C类地址的最高三位必须是“110”,前三个字节为网络地址,最后一个字节为主机地址。因此,C类地址的网络数目为221,即有2907152个网络,其中每个网络可以包含的主机数目为28−2,即有254台主机。因此,C类地址适用于小规模的局域网络。 D类地址与前三类地址不同,它是一种特殊的IP地址类,应用于多播通信,因此也被称为多播地址。地址前面有4个引导位“1110”,其余的28位表示多播地址,因此其地址范围为:224.0.0.0~239.255.255.255。D类地址只能作为目的地址,不能作为源地址。 E类地址是一般不用的实验性地址,前面包含4个引导位“1111”,因此其地址范围为:240.0.0.0~255.255.255.255。
5.1 TCP/IP概述 5.1.2 TCP/IP基本概念 除上述几类地址外,还有几个特殊的地址。 网络地址:IP地址中主机地址为0的地址表示网络地址。这类地址不指派给任何主机,它只保留用来定义某个网络的地址。例如,某主机的IP地址为175.22.10.48,它是一个B类地址,则该主机所在网络的地址为175.22.0.0。 广播地址:在A、B、C三类地址中,主机号全为“1”的地址为广播地址。这类地址用来同时向指定网络的所有主机发送信息。例如,如果某台主机使用175.22.255.255为目标地址发送数据报时,则网络地址为175.22.0.0的网络中的所有主机都能收到该数据报。 回送地址:在IP地址中,首字节数值为“127”的地址是一个保留地址,称为回送地址。如:127.0.0.1即为一个回送地址。该类地址用于网络测试或本机进程间通信。发送到这种地址的数据报不输出到线路上,而是立即被返回,又当作输入数据报在本机内部进行处理。例如,常用的“ping”命令,就是发送一个将回送地址作为目的地址的数据报,以测试IP软件能否接受和处理数据报。
5.1 TCP/IP概述 5.1.2 TCP/IP基本概念 2.子网与掩码 如上所述,IP地址最初采用的是网络地址和主机地址两级结构,然而在实际组网过程中,常常会出现使用C类地址时,主机编址空间不够,而使用A类或B类地址时,又会造成大量IP地址浪费的现象。为此,IP地址现在多采用三级结构,即IP地址=网络地址+子网地址+主机地址。把每个网络的主机地址空间根据需要再进一步划分成若干个子网,则原来两级地址结构中的主机地址又细分为子网地址和主机地址,子网地址位数根据子网的实际规模来确定。具体三级结构地址的确定需要借助子网掩码来实现。 子网掩码是一个32位地址掩码,对应于网络地址和子网地址的地址掩码位设置为“1”,而对应于主机地址的地址掩码位设置为“0”。子网掩码用于屏蔽IP地址的一部分以区别网络标识和主机标识,并说明该IP地址是在局域网上,还是在远程网上。 确定子网掩码的过程也就是划分子网的过程,通常划分步骤如下: (1)确定网络地址,划出网络标识和主机标识。 例如:申请到的网络号为“202.195.a.b”,该网络地址为C类IP地址,网络标识为“202.195”,主机标识为“a.b”。 (2)根据需求确认子网个数。 在确认子网个数时应当考虑将来的扩展情况。例如:现在需要12个子网,将来可能需要16个子网,则至少需要用第三个字节的前四位来确定子网掩码,而后四位仍然用于主机地址。所以将前四位都置为“1”,后四位全置为“0”,即第三个字节为“11110000”。
5.1 TCP/IP概述 5.1.2 TCP/IP基本概念 (3)得出子网掩码。 对应于网络地址和子网地址的地址掩码位设置为“1”,而对应于主机地址的地址掩码位设置为“0”。则子网掩码的二进制形式为:“11111111.11111111.11110000.00000000”,即为 “255.255.240.0”。 3.端口号 按照TCP/IP模型的描述,应用层所有的应用进程(应用程序)都可以通过传输层再传送到IP层,传输层从IP层收到数据后必须交付给指明的应用进程,因此必须给应用层的每一个应用程序赋予一个非常明确的标志。由于在因特网上使用的计算机的操作系统种类很多,不同的系统会使用不同的进程标识符,因此无法采用计算机中的进程标识符来作为标志,必须采用统一的方法对TCP/IP体录的应用进程进行标志。为了标识通信实体中进行通信的进程,TCP/IP协议提出了协议端口(protocol port,简称端口)的概念。 端口是一种抽象的软件结构(包括一些数据结构和I/O缓冲区)。应用程序通过系统调用与某端口绑定(binding)后,传输层传给该端口的数据都被相应的进程所接收,相应进程发给传输层的数据也通过该端口输出。类似于文件描述符,每个端口都拥有一个叫端口号的整数描述符,用来区别不同的端口。TCP/IP协议使用一个16位的整数来标识一个端口,它的范围是0~65535。由于TCP协议和UDP协议是两个完全独立的软件模块,因此各自的端口号也相互独立。如TCP有一个255号端口,UDP也可以有一个255号端口,两者并不冲突。
5.1 TCP/IP概述 5.1.2 TCP/IP基本概念 端口号的分配通常有以下两种方法: (1)全局分配 这是一种集中分配方式,由一个公认权威的机构根据用户需要进行统一分配,并将结果公布于众。 (2)本地分配 本地分配又称动态连接,即进程需要访问传输层服务时,向本地操作系统提出申请,操作系统返回本地唯一的端口号,进程再通过合适的系统调用,将自己和端口连接起来。 TCP/IP端口号的分配综合了以上两种方式,将端口号分为两部分,少量的作为保留端口,以全局方式分配给服务进程。每一个标准服务器都拥有一个全局公认的端口,即使在不同的机器上,其端口号也相同。剩余的为自由端口,以本地方式进行分配。TCP和UDP规定,小于256的端口才能作为保留端口。具体讲,TCP/IP端口号分为如下两类。 (1)服务器端使用的端口号。 服务器端的端口号又分为两类,最重要的一类叫公认端口号(well-known port number)或系统端口号,从0~1023,它们紧密绑定于一些服务。通常这些端口的通信明确表明了某种服务的协议。例如,对于每个TCP/IP实现来说,FTP服务器的TCP端口号都是21,每个Telnet服务器的TCP端口号都是23,每个TFTP(简单文件传送协议)服务器的UDP端口号都是69,HTTP通信的端口号实际上总是80端口等。
5.1 TCP/IP概述 5.1.2 TCP/IP基本概念 另一类叫注册端口号(Registered Ports),从1024~49151。它们松散地绑定于一些服务。也就是说有许多服务绑定于这些端口,这些端口同样用于许多其他目的。例如,许多系统处理动态端口从1024左右开始。使用这类端口号必须在IANA按照规定的手续登记,以防重复。 (2)客户端使用的端口号。 这类端口通常又称为动态和/或私有端口(Dynamic and/or Private Ports),从49152~65535。理论上,不应为服务分配这些端口。这类端口号是留给客户进程选择暂时使用的。当服务器进程收到客户进程的报文时,就知道了客户进程所使用的端口号,因而可以把数据发送给客户进程。通信结束后,刚才已经使用过的客户端口号就不复存在。这个端口号就可以供其他客户进程以后使用。实际上,机器通常从1024开始分配动态端口。 4.地址解析 地址解析(Address Resolution)就是将计算机中的协议地址翻译成物理地址(或称MAC地址,即媒体映射地址)。 地址解析技术可分为如下3种。 (1)表查询(Table-Lookup)。该方法适用于广域网,通过建立映射数组(协议地址↔物理地址)的方法解决。当需要进行地址解析时,由软件通过查询找到物理地址。
5.1 TCP/IP概述 5.1.2 TCP/IP基本概念 (2)相近形式计算(Closed-Form Computation)。该方法适用于可以自行配置的网络,IP地址和物理地址相互对应。通常分配给计算机的协议地址是根据其物理地址经过仔细挑选的,使得计算机的物理地址可以由它的协议地址经过基本的逻辑和算术运算计算出来。 例如: 202.195.50.1→ XXXl 202.195.50.2→ XXX2 可通过这种算法得到物理地址:物理地址 = 协议地址 & 0xFF。 (3)信息交换(Message Exchange)。该方式适用于LAN,是基于分布式的处理方式,即主机发送一个解析请求,以广播的形式发出,并等待网络内各个主机的响应。 TCP/IP协议包含了地址解析协议(Address Resolution Protocol,ARP)。ARP标准定义了两种基本信息类型:请求与响应。当一台主机要求转换一个IP地址时,它广播一个含有该IP地址的ARP请求,如果该请求与一台机器的IP地址匹配,则该机器发出一个含有所需物理地址的响应。响应是直接发给广播该请求的机器的。 在使用ARP的计算机上都保留了一个高速缓存,用于存放最近获得的IP地址到物理地址的绑定,在发送分组时,计算机先到缓存中寻找所需的绑定,如没有,则发出一个ARP请求。接收方在处理ARP分组之前,先更新它们缓存中发送方的IP地址到物理地址的绑定信息,再进行响应或抛弃。
5.1 TCP/IP概述 5.1.2 TCP/IP基本概念 5.域名系统 在Internet上,既可以使用主机名标识一台主机,也可以使用IP地址来标识。但是在TCP/IP中,点分十进制的IP地址记起来总是不如名字那么方便,人们更愿意使用便于记忆的主机名标识符,所以,就采用了域名系统(Domain Name System,DNS)来管理名字和IP地址的对应关系。一个系统的全域名由主机名、域名和扩展名三部分组成,各部分间使用“.”分隔,例如www.sina.com.cn。在TCP/IP应用中,域名系统是一个分布的数据库,由它来提供IP地址和主机名之间的映射信息,可以通过在程序中调用标准库函数来编程实现域名与IP地址之间的相互转换,这一转换过程称为“域名解析”。通过从域名地址到IP地址的映射,使得在日常的网络应用中,可以使用域名这种便于记忆的地址表示形式。所有的网络应用程序理论上都应该具有内嵌的域名解析机制。
5.1 TCP/IP概述 5.1.2 TCP/IP基本概念 域名解析的流程由以下几步构成: (1)客户机提出域名解析请求,并将该请求发送给本地的域名服务器。 (2)当本地的域名服务器收到请求后,就先查询本地的缓存,如果有该记录项,则本地的域名服务器就直接把查询的结果返回。 (3)如果本地的缓存中没有该记录,则本地域名服务器就直接把请求发给根域名服务器,然后根域名服务器再返回给本地域名服务器一个所查询域(根的子域)的主域名服务器的地址。 (4)本地服务器再向上一步返回的域名服务器发送请求,然后接受请求的服务器查询自己的缓存,如果没有该记录,则返回相关的下级域名服务器的地址。 (5)重复第四步,直到找到正确的记录。 (6)本地域名服务器把返回的结果保存到缓存,以备下一次使用,同时还将结果返回给客户机。
5.1 TCP/IP概述 5.1.2 TCP/IP基本概念 当主机通过网络向其他设备传输数据时,首先要对数据进行打包,这一打包的过程就称为数据封装。在TCP/IP模型中,为了实现通信并交换信息,每一层都有各自的协议数据单元(Protocol Data Units,PDU),通过封装使每个PDU附加到数据上。每个PDU都有其特定的名称,如:链路层-数据帧,网络层-数据包,传输层-数据段。这种PDU信息只能由接收方设备中的对等层读取,在读取之后,报头就被剥离,然后把数据交给上一层。数据的封装过程如图5.5所示。解封装则是数据封装的逆过程,当目的主机收到一个以太网数据帧时,数据就开始从协议栈中由底向上升,同时去掉各层协议加上的报文首部。每层协议都要去检查报文首部中的协议标识,以确定接收数据的上层协议。这个过程称为解封装。
5.2 .NET网络编程基础 5.2.1 .NET中的网络组件 C#和C++的差异之一,就是它本身没有类库,C#所使用的类库是.Net框架中的类库—.Net Framework SDK。因此了解并掌握.Net框架为网络编程提供的类库是学习C#网络编程的前提。.Net框架为网络开发提供了两个顶层命名空间:System.Net和System.Web,同时它们又包含多个子命名空间,C#就是通过这些命名空间中封装的类和方法实现网络通信编程、Web应用编程以及Web Service编程的。具体命名空间及其所含类的功能概述如表5.1 所示。
5.2 .NET网络编程基础 5.2.1 .NET中的网络组件
5.2 .NET网络编程基础 5.2.1 .NET中的网络组件
5.2 .NET网络编程基础 5.2.1 .NET中的网络组件
5.2 .NET网络编程基础 5.2.1 .NET中的网络组件
5.2 .NET网络编程基础 5.2.2 网络编程中的常用类 1.IP地址类 与IP地址相关的类有IPAddress类、IPHostEntry类、IPEndPoint类等。IPAddress类是一个描述IP地址的类,主要用来存储IP地址。IPAddress类的属性和方法如下表所示。
5.2 .NET网络编程基础 5.2.2 网络编程中的常用类 IPHostEntry类是为Internet主机地址信息提供容器的类,它将DNS主机名与一个别名数组和匹配的IP地址数组相关。通常IPHostEntry类作为Dns类的辅助类使用。该类有如下几个属性。 Aliases属性:获取或设置与主机相关的别名清单。 AddressList属性:获取或设置与主机相关的IP地址。其值为IPAddress类型的数组,其中包含的IP地址用于解析Aliases属性中的主机名。 HostName属性:获取或设置主机的DNS名。包含服务器的基础主机名,如果服务器的DNS项定义了附加别名,则可通过Aliases属性使用它们。 IPEndPoint类以IP地址和端口号的形式代表一个网络终端。该类中包含应用程序连接到主机服务时需要的主机和端口信息,通过组合主机的IP地址和端口号构成服务的一个连接点。IPEndPoint类的属性和方法如下表所示。
5.2 .NET网络编程基础 5.2.2 网络编程中的常用类 2.域名解析类 Dns类是一个静态类,它提供了有关域名解析的操作。它将从网络主机域名系统中获取IP地址和主机名、WWW域名的对应关系。它返回一个IPHostEntry对象以保存结果。如果返回值是多个信息,IPHostEntry将返回主机的多个地址和别名。Dns类的方法如下表所示。
5.2 .NET网络编程基础 5.2.2 网络编程中的常用类 DnsPermission类控制对网络DNS服务器的访问。默认情况下,所有本地和Internet域中的应用程序都能访问DNS服务,并且对Internet应用程序无DNS许可。DnsPermission类的方法如下表所示。
5.2 .NET网络编程基础 5.2.2 网络编程中的常用类 3.类使用实例 以上介绍的IP地址类和域名解析类是网络编程中常用的基础类。下面用一个获取主机名和IP地址的实例来说明上述类的使用方法。 using System; using System.Collections.Generic; using System.Text; using System.Net; namespace IPDnsTest { class Program { static void Main(string[] args) { string strHostName; //获取本地计算机名称 strHostName = Dns.GetHostName( ); Console.WriteLine("本地计算机名:" + strHostName); //由本地计算机名称获取本机IP地址 IPHostEntry ipEntry = Dns.GetHostEntry(strHostName); IPAddress[] addr = ipEntry.AddressList; //显示本机IP地址 for (int i = 0; i < addr.Length; i++) { Console.WriteLine("IP地址[{0}]:{1}", i, addr[i].ToString( )); Console.WriteLine("地址类型[{0}]:{1}",i,addr[i].AddressFamily.ToString( )); } Console.ReadKey( ); } } }
5.3 套接字编程 5.3.1 套接字简介 套接字(Socket)的概念首先是由BSD UNIX提出的。当时在UNIX编程中,引入了文件描述符(file descriptor)的概念。一个文件描述符提供了到一个文件对象的编程接口。因为UNIX操作系统中几乎所有的对象都定义成文件,文件描述符可以被用来在UNIX系统中收发数据,这些数据可以包含很多对象。因为不需要考虑所操作的文件(或设备)的类型,因此在UNIX中,用一个套接字表示一个网络文件描述符,编程就显得简便的多。在此基础上加利福尼亚大学Berkeley学院为UNIX开发了网络通信编程接口。但是最初它只能运行在UNIX操作系统,不支持DOS和Windows操作系统。随着Windows操作系统的日益推广,20世纪90年代初,微软和第三方厂商共同制定了一套标准,即Windows Sockets规范,简称WinSock。 Windows Sockets以UNIX中流行的Socket接口为范例定义了一套Microsoft Windows网络编程接口。Windows Sockets规范旨在提供给应用程序开发人员一套简单的API,并让各家网络软件供应商共同遵守。Windows Sockets 1.1和Berkeley Sockets都是基于TCP/IP协议的;Windows Sockets 2从Windows Sockets 1.1发展而来,与协议无关并向下兼容,可以使用任何底层传输协议提供的通信能力,来为上层应用程序完成网络数据通信,而不用关心底层网络链路通信的情况,真正实现了底层网络通信对应用程序的透明。
5.3 套接字编程 5.3.1 套接字简介 Windows Sockets规范定义并记录了如何使用API与Internet协议族(IPS,通常是指TCP/IP)连接,尤其要指出的是,所有的Windows Sockets实现都支持流套接接口和数据报套接接口,应用程序调用Windows Sockets的API实现相互之间的通信。Windows Sockets又利用下层的网络通信协议功能和操作系统调用实现实际的通信工作。它们之间的关系如下图所示。 套接字是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。套接字存在于通信域中,Windows Sockets只支持一个通信域:网际域(AF-INET),这个域被使用网际协议族通信的进程所使用。 套接字有两种不同的类型:流套接字和数据报套接字。
5.3 套接字编程 5.3.1 套接字简介 TCP/IP的Socket则提供3种类型的套接字。 1.流式套接字(SOCK_STREAM) 提供面向连接、可靠的数据传输服务,数据无差错、无重复的发送,且按发送顺序接收。内设流量控制,避免数据流超限;数据被看作是字节流,无长度限制。文件传输协议(FTP)即使用流式套接字。 2.数据报式套接字(SOCK_DGRAM) 提供无连接服务。数据包以独立包形式发送,不提供无差错保证,数据可能丢失或重复,并且接收顺序混乱。网络文件系统(NFS)使用数据报式套接字。 3.原始套接字(SOCK_RAW) 该接口允许对较低层协议,如IP、ICMP直接访问。常用于检验新的协议实现或访问现有服务中配置的新设备。
5.3 套接字编程 5.3.2 套接字编程原理 1.C/S编程模式 在TCP/IP网络中软硬件资源、运算能力和信息通常都是不均等的,为了能够对这些资源进行共享,需要一种机制在希望通信的进程间建立联系,为二者的数据交换提供服务,这种机制即为通信进程间的作用模式。通常,通信的两个进程间相互作用的主要模式是客户机/服务器模式(client/server)。在一个具有多台计算机的网络中,那些在其上运行的应用程序是为了请求另一台计算机上的服务(如访问数据库)的计算机称为客户端(Client),而处理这些服务请求(例如对数据库进行检索,将结果返回)的计算机称为服务器(Server)。客户机/服务器模式就是客户机向服务器提出请求,服务器接收到请求后,提供相应服务的一种作用模式。 客户机/服务器模式工作时要求有一套为客户机和服务器所公认的协议来保证服务能被提供(或接受)。根据不同的情况,协议可以是非对称的也可以是对称的。在对称的协议中,每一方都有可能扮演主从角色;在非对称协议中,一方被不可改变的认为是主机,而另一方则是从机。 服务器软件既包括遵循OSI或其他网络结构的网络软件,又包括由该服务器提供给网络上的应用程序或服务软件。在服务器上执行的计算通常被称为后端处理。服务器端程序通常在一个众所周知的地址监听对服务的请求。也就是说,服务进程一直处于休眠状态,直到一个客户对这个服务的地址提出了连接请求。在这个时刻,服务程序被“唤醒”并且为客户提供服务。因此服务器方一般都是先启动的。
5.3 套接字编程 5.3.2 套接字编程原理 服务器端程序执行步骤如下。 (1)打开一个通信通道并告知本地主机,它愿意在某一地址和端口上接收客户请求。 (2)等待客户请求到达该端口。 (3)接收到重复服务请求,处理该请求并发送应答信号。接收到并发服务请求,激活一个新的进程(或线程)来处理这个客户请求。新进程(或线程)处理此客户请求,并不需要对其他请求作出应答。服务完成后,关闭此新进程与客户的通信链路,并终止。 (4)返回第二步,等待另一客户请求。 (5)关闭服务器。 与服务器端相对应,客户机执行的计算通常被称为前端处理。客户机端软件一般由网络接口软件、支持用户需求的应用程序以及实现某些网络功能的实用程序(如电子邮件等)组成。应用程序软件执行具体的任务,如字处理,电子表格和数据库查询等。实用程序软件通常执行几乎所有网络用户都要求的标准任务。网络接口软件提供各种数据传输服务,其执行步骤如下。 (1)打开一个通信通道,并连接到服务器所在主机的特定端口。 (2)向服务器发服务请求报文,等待并接收应答;继续提出请求。 (3)请求结束后关闭通信通道并终止。
5.3 套接字编程 5.3.2 套接字编程原理 2.Socket编程的通信方式 在利用Socket进行编程时要先了解以下几个概念,同步(Synchronous)、异步(Asynchronous)、阻塞(Block)和非阻塞(Unblock)。其中,同步、异步是属于通信模式的概念,而阻塞、非阻塞则属于套接字模式的概念。 (1)同步方式 通信的同步,指客户端在发送请求后,必须在服务端有回应后才能发送下一个请求。所以这个时候的所有请求将会在服务端得到同步。 (2)异步方式 通信的异步,指客户端在发送请求后,不必等待服务端的回应就可以发送下一个请求,这样对于所有的请求动作来说将会在服务端得到异步,这条请求的链路就像是一个请求队列,所有的动作在这里不会得到同步。 (3)阻塞方式 阻塞套接字是指执行此套接字的网络调用时,所调用的函数只有在得到结果之后才会返回,在调用结果返回之前,当前线程会被挂起,即此套接字一直阻塞在网络调用上。比如调用StreamReader类的ReadLine( )方法读取网络缓冲区的数据,如果调用的时候没有数据到达,那么此ReadLine( )方法将一直挂在调用上,直到读到一些数据,此函数才返回。
5.3 套接字编程 5.3.2 套接字编程原理 (4)非阻塞方式 非阻塞和阻塞的概念相对应,非阻塞套接字是指在执行此套接字的网络调用时,即使不能立刻得到结果,该函数也不会阻塞当前线程,而会立刻返回。对于非阻塞套接字,同样调用StreamReader类的ReadLine( )方法读取网络缓冲区的数据,不管是否读到数据都立即返回,而不会一直挂在此函数调用上。 对象是否处于阻塞模式和函数是不是阻塞调用有很强的相关性,但是并不是一一对应的。阻塞对象上可以有非阻塞的调用方式,可以通过一定的API去轮询状态,在适当的时候调用阻塞函数,就可以避免阻塞。而对于非阻塞对象,调用特殊的函数也可以进入阻塞调用。函数select就是这样的一个例子。 在Windows网络通信软件开发中,最常用的方法就是异步非阻塞套接字。客户端/服务器结构的软件采用的方式就是异步非阻塞模式。在利用C#进行网络编程时,由于.NET Framework SDK对阻塞和非阻塞的工作机制进行了封装,因此不需要深入了解同步、异步、阻塞、非阻塞的原理。 3.套接字工作原理 套接字可以像Stream流一样被视为一个数据通道,这个通道架设在客户端应用程序和服务器端程序之间,数据的读取(接收)和写入(发送)均针对这个通道来进行。因此要通过网络进行通信,就至少需要一对套接字,其中一个运行于客户端,称之为客户端套接字(ClientSocket),另一个运行于服务器端,称之为服务器端套接字(ServerSocket)。当创建了这两个套接字对象之后,将这两个套接字连接起来就可以实现数据传送了。
5.3 套接字编程 5.3.2 套接字编程原理 根据连接启动的方式以及本地套接字要连接的目标,套接字之间的连接过程可以分为三个步骤:服务器监听,客户端请求,连接确认。 (1)服务器监听 服务器监听时服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态。 (2)客户端请求 客户端请求是指由客户端的套接字发出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后再向服务器端套接字提出连接请求。 (3)连接确认 连接确认是指当服务器端套接字监听到(或接收到)客户端套接字的连接请求时,它就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,连接就建立好了。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。 在TCP/IP网络中,IP网络交互分为两大类:面向连接的交互和无连接的交互。下面给出这两种交互的套接字编程流程。分别如图5.7和图5.8所示。
5.3 套接字编程 5.3.2 套接字编程原理 图5.7面向连接的套接字编程流程
5.3 套接字编程 5.3.2 套接字编程原理 图5.8面向无连接的套接字编程流程
5.3 套接字编程 5.3.3 .NET中的Socket类 针对Socket编程,.NET框架的System.NET.Sockets命名空间为需要严密控制网络访问的开发人员提供了WinSock接口的托管实现。其中Socket类是WinSock32 API提供的套接字服务的托管代码版本,为实现网络编程提供了大量的方法。在大多数情况下,Socket类方法只是将数据封送到它们的本机Win32副本中并处理任何必要的安全检查。 Socket类用于实现Berkeley套接字接口。 1.Socket类的构造函数 Socket类的构造函数原型如下: public Socket( AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType ); 构造函数使用3个参数来定义创建的Socket实例。AddressFamily用来指定网络类型;SocketType用来指定套接字类型(即数据连接方式);ProtocolType用来指定网络协议。3个参数均是在命名空间System.Net.Sockets中定义的枚举类型。但它们并不能任意组合,不当的组合反而会导致无效套接字。如对于常规的IP通信网络,AddressFamily只能使用AddressFamily.InterNetwork,此时可用的SocketType、ProtocolType组合如表5.9所示。
5.3 套接字编程 5.3.3 .NET中的Socket类 表5.9IP套接字定义组合 表5.10Socket类的公共属性
5.3 套接字编程 5.3.3 .NET中的Socket类 2.Socket类的常用方法 (1)Bind(EndPoint address) 在服务器端,当一个套接字被创建后,需要将它绑定到系统的一个特定地址。可以使用Bind( )方法来完成,其参数为一个IPEndPoint实例(包含IP地址和端口信息)。 (2)Listen(int con_num) 服务器端的套接字完成了与地址的绑定后,就使用Listen( )方法监听客户发送的连接请求。其参数con_num为一整型值,该值表示服务器可以接受的最大连接数目。超过这个数目的连接都会被拒绝。con_num数值的设定会影响到服务器的运行,因为每个接受的连接都要使用TCP缓冲区,如果连接的数目过大,收发数据的缓存将减少。 (3)Accept( ) 在服务器进入监听状态时,如有从客户端发来的连接请求,服务器将使用Accept( )方法来接受连接请求。Accept( )返回一个新的套接字,该套接字包含所建立的连接的信息并负责处理本连接的所有通信。而服务器刚开始创建的套接字仍然负责监听,并在需要时调用Accept( )接受新的连接请求。 (4)Send( ) 当服务器接受了来自客户端的连接请求后,服务器和客户端双方就可以利用Send( )方法来发送数据。Send( )有四种重载方法,如表5.11所示。
5.3 套接字编程 5.3.3 .NET中的Socket类 表5.11Send()、Receive( )重载方法