📄 016.txt
字号:
16.1 网络基础知识
Windows的网络通信建立在TCP/IP协议的基础上,在开始Windows的网络编程之前,应该首先了解TCP/IP协议的相关知识并且了解其中重要协议的工作方式,这样对正确理解WinSock程序的结构大有好处。在这一节中,将对一些网络基础知识进行一次快速的复习,有经验的读者可以直接跳过这一节。
16.1.1 TCP/IP协议
TCP/IP是Transmission Control Protocol/Internet Protocal(传输控制协议/国际协议)的缩写,它最初是在20世纪70年代初期由美国国防部出资为美国高级研究项目局(简称ARPA)开发的,经过了多年以后,以TCP/IP协议为基础构建的ARPA网已经演变成了今天的Internet。
1. TCP/IP模型的结构
在网络方面,最著名的结构模型就是开放系统互联模型(OSI模型),如图16.1左图所示,OSI模型的体系结构分为7层,其中应用程序所在的最高层通过多个层次最终调用网络硬件所在的物理层。OSI模型的分层结构有利于各层次的分工协作,只要每个层次都严格遵守边界协定,那么它对于其他层次来说就可以看成是一个“黑匣子”,结果就是开发人员能够致力于本层次的开发和提高,而不必担心能否和其他层次合作。
TCP/IP协议采用和OSI模型类似的概念性模型,但是将层次的划分减少到了4层。TCP/IP协议的每一层在功能上和OSI模型的一层或多层相对应。如图16.1的中间所示,TCP/IP模型分为应用层、传输层、Internet层和网络访问层。
TCP/IP模型的最底层是网络访问层(也叫网络接口层),它负责向网络的传输介质发送数据包以及从其中接收数据包。TCP/IP协议被设计为可以在不同类型的网络上传输,它并不依赖于某种特定的网络硬件,也不依赖于某种特定的数据帧格式和传输介质,网络访问层的作用是将上层的协议和网络硬件隔离开来,它通过不同的驱动程序来支持各种类型的网络硬件和组网方式,包括Ethernet(以太网),Token Ring(令牌网),Frame Relay(帧中继)和ATM等。
图16.1 TCP/IP协议组模型的结构
Internet层位于网络访问层的上层,它主要负责数据包的寻址、包装和路由功能,运行于这一层上的协议主要有:
● IP协议(网际协议)——是一个路由协议,负责IP寻址、数据包的分裂和重组任务。
● ARP协议(地址解析协议)——负责网络接口层地址和Internet层地址之间的解析,比如将一台主机的IP地址解析成其网卡的MAC地址。
● ICMP协议(网际控制消息协议)——提供诊断功能,用于报告IP数据包传送中的错误信息,Ping程序就是用ICMP协议检测某台主机的典型例子。
● IGMP协议(Internet组管理协议)——负责IP多点传送组的管理。
传输层位于Internet层的上层,主要负责提供对话和信息包通信服务。传输层的核心协议是TCP协议和UDP协议:
● TCP协议——提供一对一有连接导向的通信服务,提供连接的确认,数据包发送/接收顺序的控制,及出错重传等机制,以保证数据在传输中的正确性。
● UDP协议(用户数据报协议)——提供一对一或者一对多的通信服务,它不提供连接确定,数据包顺序控制,及出错重传等机制,所以传输的数据有可能是不可靠的。
应用层是TCP/IP模型的最上层,它为应用程序访问其他层次提供服务,应用层中定义了很多利用下层协议来交换数据的应用型协议,比如下面列出的协议最终是利用下层的TCP协议来交换数据的:
● HTTP(超文本传输协议)——用来传送Web网页文件。
● FTP协议(文件传输协议)——用于交互式文件传送。
● SMTP协议(简单邮件传输协议)——用于邮件的发送。
● POP3协议(邮局协议)——用于接收邮件。
● Telnet协议(远程登录协议)——用于终端登录操作。
而其他一些协议则建立于UDP协议的基础上,如:
● DNS(域名系统)——用于将域名解析成IP地址。
● RIP协议(路由信息协议)——用于供路由器在IP网络上交换路由信息。
● SNMP协议(简单网络管理协议)——用于网络管理控制台和网络设备(路由器、智能集线器等)之间的通信,或者用来收集和交换网络管理信息。
应用程序可以遵循这些协议定义的规范与其他程序进行数据交换。另外,一些接口也在应用层上为应用程序提供服务,如本章中要介绍的WinSock接口是一个标准的用于Windows网络编程的应用程序接口,WinSock接口由Microsoft提供;而NetBIOS是一个工业标准,它提供诸如对话、数据包交换和名字解析等服务,这些接口都是通过调用传输层或者Internet层协议来完成的。
2. 常用协议和RFC文档
TCP/IP的技术标准是公开的,正是这样才使Internet发展成全世界最大的网络,但技术上的公开性并不意味着技术标准可以由任何人随意规定,事实上,Internet的技术标准是由4个组织来负责维护的,它们是:
● Internet协会(ISOC,Internet SOCiety)
● Internet体系结构委员会(IAB,Internet Architecture Board)
● Internet工程专门小组(IETF,Internet Engineering Task Force)
● Internet研究专门小组(IRIF,Internet Research Task Force)
所有由这些组织公布的技术标准都是以RFC(Request for Comment)文档的形式出版的,表16.1列出了一些RFC文档的编号,它们定义了一些常见的协议。
表16.1 一些常用协议的RFC文档编号
协议缩写
协议名称
对应的RFC文档
UDP
User Datagram Protocol(用户数据报协议)
RFC 768
IP
Internet Protocol(网际协议)
RFC 791
TCP
Transmission Control Protocol(传输控制协议)
RFC 793
SMTP
Simple Mail Transfer Protocol(简单邮件传输协议)
RFC 821
ARP
Ethernet Address Resolution Protocol(以太网地址解析协议)
RFC 826
Telnet
Telnet Protocol(远程登录协议)
RFC 854,RFC 855
RARP
Reverse Address Resolution Protocol(逆地址解析协议)
RFC 903
FTP
File Transfer Protocol(文件传输协议)
RFC 959
DNS
Domain Name System(域名系统)
RFC 1034,RFC 1035
SNMP
Simple Network Management Protocol(简单网络管理协议)
RFC 1157
DHCP
Dynamic Host Configuration Protocol(动态主机配置协议)
RFC 1541
PPP
The Point-to-Point Protocol(点对点协议)
RFC 1661
POP3
Post Office Protocol V3(邮局协议V3)
RFC 1939
HTTP1.0
Hypertext Transfer Protocol 1.0(超文本传输协议1.0版本)
RFC 1945
IGMP
Internet Group Management Protocol(Internet组管理协议)
RFC 2236
HTTP 1.1
Hypertext Transfer Protocol 1.1(超文本传输协议1.1版本)
RFC 2616,RFC 2617
RFC文档的原文是英文版的,可以很方便地从互联网中获取它们,获得任意一份RFC或者已发布的所有RFC的最简单的方法就是访问ISOC提供的站点:
http://www.rfc-editor.org/rfc.html
如果希望查阅中文版的RFC文档,可以访问China-Pub网站的中文RFC文档翻译计划,网址是:
http://www.china-pub.com/computers/eMook/emooknew/RFC/rfc.asp
但是RFC文档中包含的仅是枯燥的技术规范及说明,并没有实现的具体步骤及方法示范。如果希望详细了解这些协议的方方面面,最权威的书籍莫过于W.Richard Stevens的遗作:3卷中译本的《TCP/IP详解》,它们是:
● 卷1:协议——TCP/IP协议指南,描述了属于每一层的各个协议以及它们如何在不同操作系统中运行。
● 卷2:实现——以约500个图例、15 000行实际操作的C代码来介绍TCP/IP协议是如何实现的。
● 卷3:TCP事务协议、HTTP、NNTP和UNIX域协议——主要内容包括TCP协议的扩展应用。
这3本书是网络编程资料中当之无愧的经典之作,惟一的遗憾是书的内容是以UNIX操作系统为背景的,但由于书中的例子代码是以标准C写的,所以对Windows的网络编程同样有很大的参考价值。
3. 数据包的封装
当应用层上的程序与其他计算机进行通信时,它所发送的数据包在TCP/IP模型的各个层次中逐渐下降,最后到达位于最底层的网络访问层中,网络访问层通过网络介质将数据包传送到目标主机后,数据包再逐渐上升到位于应用层的应用程序中,这个过程和数据在堆栈中的传送方式很相似,所以一般也把TCP/IP模型称为TCP/IP栈。
各种协议在实现的时候都需要互相交换信息,如IP协议需要交换地址信息,TCP协议需要交换控制信息,所以,不同的协议都会对要处理的数据进行适当的封装。
以通过HTTP协议访问一个网站为例,如图16.2所示,应用程序在用户数据的前面加上HTTP首部,组成一个数据包后准备通过TCP栈发送到目标网站,当数据包到达传输层的时候,TCP协议需要为数据包加上源端口和目标端口、数据包序号和应答字段等内容,以便实现连接应答与出错重传等TCP协议中的各种特征,这些数据当做TCP首部被加在原来数据包的前面,由此形成一个新的数据包后再交给Internet层的IP协议,这个被封装后的数据包就被称为TCP报文段(TCP Segment)。
图16.2 数据包的封装
IP协议负责寻址,它需要为TCP段加上目标IP地址,为了能让对方知道数据包是从哪里发过来的,也需要加上自己的IP地址,为了让目标主机的Internet层在处理数据包后能知道往传输层的哪个协议中送,还需要标出数据包是由传输层的哪个协议送下来的,这些数据形成一个IP首部后被附加在TCP报文段的前面,形成一个新的被称为IP数据报(IP Datagram)的新数据包。
现在IP数据报到了网络访问层的网卡驱动程序中,在这里驱动程序根据目标IP地址查出目标设备的MAC地址,在数据报的头部加上源MAC地址和目标MAC地址,同时为数据报加上一个尾部,所有这些数据形成一个数据帧(Frame)后被发送到网络介质上。
当数据帧到达目标主机后,网络访问层将以太网首部和尾部数据去除以恢复成IP数据报,并将IP数据报传递到上层的IP协议中;IP协议分析IP首部数据,并根据IP首部中的传输层协议类型将恢复的TCP报文段交到上层的TCP协议中;TCP协议再根据TCP首部中的数据判断数据包的序号,检测有无丢包,并根据情况决定是否要求发送方重传,当完成这些纠错任务后,将正确的数据交到应用层的应用程序中;这时的数据包中包含HTTP首部和用户数据,应用程序最后处理HTTP首部并得到正确的原始数据,一次数据包的传输就完成了。
当使用不同的协议时,各种协议将为数据包加上自己的首部,这些协议首部的数据定义各不相同,长度也各不相同,比如TCP首部的长度为20个字节,而UDP首部的长度只有8个字节。
正是由于每个层次的协议都对数据包进行封装,所以,在TCP/IP模型的不同层次进行编程的时候,数据的处理方法可能是完全不同的,比如实现一个Ping功能,如果在应用层上调用Icmp.dll中的相关函数,那么寥寥几句就可以完成,但是通过WinSock接口在Internet层上实现,那就要自己去处理ICMP协议首部和IP协议首部了。
16.1.2 一些重要概念
1. IP地址和子网掩码
要在计算机之间使用TCP/IP协议进行通信,这些计算机必须能够互相寻址,TCP/IP协议使用IP地址寻址方式,所以,对于一个IP网络来说,网络上的设备之间要进行通信的话,每个设备必须具有惟一的IP地址,否则将无法正确地进行寻址,同理,要让整个Internet范围内的计算机都能够互相通信,Internet上的所有设备也必须具有惟一的IP地址。
IP地址是一个32位的二进制数,为了用人们熟悉的10进制数表示,通常将它分为4个8位的二进制数,每个8位二进制数被转换成10进制,中间用小数点隔开,就得到了IP地址的10进制字符串格式,图16.3中的IP地址11000000 10101000 00000001 01100100,以10进制方式表示就是192.168.1.100。
图16.3 IP地址的两种表示格式
从理论上说,网络中的计算机之间要进行通信,只要有双方的IP地址就可以了,但是由于网络结构的关系,在实际使用中还需要将IP地址划分成网络号和结点号两部分。这是因为对一个小网络来说,所有的计算机都挂在同样的传输介质上,如果计算机A向计算机B发送IP数据报,A计算机的网卡将向传输介质发送一个封装有这个IP数据报的数据帧,数据帧头部的目标地址是B计算机的网卡MAC地址,实际上,这时网络上的任一台计算机都可以“听”到这个数据帧,只不过只有B计算机发现数据帧的目标MAC地址和自己符合而进行处理罢了。
如果让整个Internet的通信都以这种方式寻址,那么每台计算机发送的数据帧就要被传遍全世界才能保证被目标计算机“听”到,这显然是不现实的,所以一般来说要将整个网络划分成一个个小网络(子网),仅同一个子网中的计算机进行通信时才对目标MAC地址进行寻址,不同子网之间的IP数据报通过网关来转发,网关一般由路由器或者有路由功能的计算机来担任。
当计算机A向不属同一子网的计算机B发送数据时,它将以网关的MAC地址当做目标地址发送数据帧,由网关负责选择向其他最合适的子网转发。为了让计算机知道何时通过网关转发,必须能够分辨目标计算机是否在同一个子网上。
如何分辨目标计算机是否属于同一个子网呢,这就是子网掩码的作用。子网掩码用来将IP地址划分成两个部分:网络号和结点号。如果当前主机的IP地址和目标主机的IP地址的网络号相同,那么就说明它们同属一个子网。
假如需要在当前子网保留256个地址(结点),可以将IP地址中的最后8位视为结点号(因为8位二进制位可以表示256个不同的数),将剩下的24位视为网络号。为了划分网络号和结点号,可以使用一个高24位为1的32位二进制数去和IP地址进行and运算,这样得到的结果就是网络号,用这个数取反后和IP地址进行and运算,得到的就是结点号,用来进行and运算的数就是子网掩码。
以192.168.1.100地址为例,如图16.4所示,二进制IP地址11000000 10101000 00000001 01100100和子网掩码11111111 11111111 11111111 00000000进行and运算以后,得到网络号11000000 10101000 00000001,一般习惯在网络号后面用0补足32位并用10进制IP地址的形式来表达,这样就得到了网络号192.168.1.0。IP地址中余下的8位就是结点号。这个掩码用10进制IP地址的方式表示就是255.255.255.0。
图16.4 IP地址和子网掩码例一
再举一个例子,当子网里面的计算机不到16台的时候,可以只用4位来表示结点号。这时可以将掩码的全1数据位扩展到28位,如图16.5所示,前28位为1的子网掩码用IP地址方式表示就是255.255.255.240,因为最后8位11110000等于10进制数240。而网络号用0补足32位以后就是192.168.1.96,因为最后8位01100000等于10进制数96。当然,也可以在其他任何位置划分结点号和网络号,比如用16位来表示结点号的话,那么掩码就是255.255.0.0。
图16.5 IP地址和子网掩码例二
有了子网掩码以后,源计算机将目标计算机的IP地址和自身的子网掩码进行and运算,如果得到的网络号和自身所属的网络号不同的话,就意味着目标计算机不在同一个子网中。这时为数据帧设置目标主机的MAC地址是无法让它“听”到的,于是计算机将数据帧的目标MAC地址设置为网关的MAC地址,这样路由器将接收到这个数据帧,路由器一般用来连接多个子网,它以同样的方法判断目标计算机是否位于其中一个子网上,是的话则向这个子网以目标主机的MAC地址发送数据帧,否则根据路由表的设置将数据帧发送到另一个合适的路由器上,由此传递一直到找到目标主机为止。
2. 端口
曾经有人问过这样一个问题:如果开了两个浏览器窗口去浏览同一个网站的不同页面,那么这两个浏览器窗口的发送方IP地址和接收方的IP地址都是一样的,计算机如何分辨数据是属于哪个浏览器窗口的呢?这就涉及协议复用的问题,如果协议不能复用的话,那么它在同一时刻就只能为一个进程服务。
为此,TCP/IP协议提出了协议端口的概念,协议端口用于标识通信的进程,这样就可以让使用同一个IP地址的不同进程通过不同的端口号对IP地址进行复用,协议端口是在传输层的TCP和UDP协议中实现的,这样就使传输层提供了同时为不同进程提供通信的能力,在其他层次的其他协议中并没有端口的概念。
端口号用一个16位的整数来表示,所以从理论上讲,可以同时有65 536个进程使用同一IP地址进行通信,由于传输层的TCP协议和UDP协议是两个完全独立的模块,两者的工作是互不相干的,所以TCP和UDP各自的端口号也相互独立,一个进程使用TCP协议的某个端口号并不影响另一进程使用UDP协议的同名端口号,但是同一协议的同一端口号无法被两个进程同时使用。
大部分应用层上的协议都定义了自己使用的默认端口号(但这并不意味着必须使用这个端口号),另外,一些服务程序(如SQL Server,Oracle数据库与Windows的终端服务等)也使用固定的端口号。表16.2中列出了一些常用协议和服务程序使用的端口号,详尽的已分配端口号列表可以参考RFC 1700。
表16.2 常用协议和应用程序使用的默认端口号
协议或应用程序
TCP端口号
UDP端口号
FTP
21
Telnet
23
SMTP
25
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -