《TCPIP协议分析》课程设计Word文档格式.docx
《《TCPIP协议分析》课程设计Word文档格式.docx》由会员分享,可在线阅读,更多相关《《TCPIP协议分析》课程设计Word文档格式.docx(15页珍藏版)》请在冰豆网上搜索。
在传递每个UDP报文时,该报文除了携带用户数据外,还携带目的端口号和源端口号,这使得目的机器上的UDP软件能够将报文交给正确的接收进程,而接受进程也能正确地返回应答报文。
UDP协议的主要作用是将网络数据流量压缩成数据包的形式。
一个典型的数据包就是一个二进制数据的传输单位。
每一个数据包的前8个字节用来包含报头信息,剩余字节则用来包含具体的传输数据。
UDP用来支持那些需要在计算机之间传输数据的网络应用。
包括网络视频会议系统在内的众多的客户/服务器模式的网络应用都需要使用UDP协议。
它主要用于不要求分组顺序到达的传输中,分组传输顺序的检查与排序由应用层完成,提供面向事务的简单不可靠信息传送服务。
UDP协议基本上是IP协议与上层协议的接口。
UDP协议适用端口分别运行在同一台设备上的多个应用程序。
UDP只提供数据的不可靠交付,它一旦把应用程序发给网络层的数据发送出去,就不保留数据备份(所以UDP有时候也被认为是不可靠的数据报协议)。
UDP在IP数据报的头部仅仅加入了复用和数据校验(字段)。
UDP使用底层的互联网协议来传送报文,同IP一样提供不可靠的无连接数据报传输服务。
它不提供报文到达确认、排序、及流量控制等功能。
因此,UDP报文可能会出现丢失、延迟或乱序到达的现象。
而且,报文到达的速率可能会大于接收进程能够处理的速率。
使用UDP的应用程序可根据自己的需求设计相应的可靠性机制。
例如,作为文件传输协议之一的简单文件传输协议就在应用层做这方面的工作。
1.3协议的发展历程
UDP协议从问世至今已经被使用了很多年,虽然其最初的光彩已经被一些类似协议所掩盖,但是即使是在今天,UDP仍然不失为一项非常实用和可行的网络传输层协议。
在选择使用协议的时候,选择UDP必须要谨慎。
在网络质量令人不十分满意的环境下,UDP协议数据包丢失会比较严重。
但是由于UDP的特性:
它不属于连接型协议,因而具有资源消耗小,处理速度快的优点,所以通常音频、视频和普通数据在传送时使用UDP较多,因为它们即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。
比如我们聊天用的ICQ和QQ就是使用的UDP协议。
2协议工作原理及流程
由于大多数网络应用程序都在同一台机器上运行,计算机上必须能够确保目的地机器上的软件程序能从源地址机器处获得数据包,以及源计算机能收到正确的回复。
这是通过使用UDP的“端口号”完成的。
例如,如果一个工作站希望在工作站128.1.123.1上使用域名服务系统,它就会给数据包一个目的地址128.1.123.1,并在UDP头插入目标端口号53。
源端口号标识了请求域名服务的本地机的应用程序,同时需要将所有由目的站生成的响应包都指定到源主机的这个端口上。
与TCP不同,UDP并不提供对IP协议的可靠机制、流控制以及错误恢复功能等。
由于UDP比较简单,UDP头包含很少的字节,比TCP负载消耗少。
UDP只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。
由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快。
协议各层的软件都要对相邻层的多个对象进行多路复用和多路分解操作。
UDP软件接收多个应用程序送来的数据报,把它们送给IP层进行传输,同时它接收从IP层送来的UDP数据报,并把它们送给适当的应用程序。
UDP软件与应用程序之间所有的多路复用和多路分解都要通过端口机制来实现。
实际上,每个应用程序在发送数据报之前必须与操作系统进行协商,以获得协议端口和相应的端口号。
当指定了端口之后,凡是利用这个端口发送数据报的应用程序都要把端口号放入UDP报文的源端口字段中。
在处理输入时,UDP从IP层软件接收了传入的数据报,根据UDP的目的端口号进行多路分解操作,如下图。
理解UDP端的最简单的方式是把它看成是一个队列。
在大多数实现中,当应用程序与操作系统协商,试图使用某个给定端口时,操作系统就创建一个内部队列来容纳收到的报文。
通常应用程序可以指定和修改这个队列的长度。
当UDP收到数据报时,先检查当前使用的端口是否就是该数据报的目的端口。
如果不能匹配,则发送一个ICMP端口不可达报文并丢弃这个数据报。
如果匹配,它就把这个数据报送到相应的队列中,等待应用程序的访问。
当然,如果端口已满也会出错,UDP也要丢弃传入的这个数据报。
图2-1UDP端口的多路分解
3协议格式分析
3.1UDP报文封装
在交给IP层之前,UDP给用户要发送的数据加上一个首部。
IP层又给从UDP接收到的数据报加上一个首部。
最后,网络接口层把数据报封装到一个帧里,最后转化为比特流在网络中投递。
封装UDP报文的IP数据报首部协议字段应设置为17,如图3-1所示。
帧的结构根据底层的网络技术来确定。
通常网络帧结构包括一个附加的首部。
在接收端,最底层的网络软件接收到一个分组后把它提交给上一层模块。
每一层都在向上送交数据之前剥去本层的首部,因此当最高层的协议软件把数据送到相应的接收进程的时候,所有附加的首部都被剥去了。
也就是说,最外层的首部对应的是最底层的协议,而最内层的首部对应的是最高层的协议。
研究首部的生成与剥除时,可从协议的分层原则得到启发。
当把分层原则具体的应用于UDP协议时,可以清楚地知道目的机上的由IP层送交UDP层的数据报就等同于发送机上的UDP层交给IP层的数据报。
同样,接收方的UDP层上交给用户进程的数掘也就是发送方的用户进程送到UDP层的数据。
在多层协议之间,职责的划分是清楚而明确的,IP层只负责在互联网上的一对主机之间进行数据传输,而UDP层只负责区分一台主机上的多个源端口或目的端口。
图3-1UDP报文的封装
3.2UDP报文的抓取步骤
抓取XX主页的UDP报文。
1、主机打开EtherPeekNX工具,点击过滤条件(udp),新建抓包窗口,开始捕获;
2、主机打开浏览器,进入XX搜索栏首页;
图3-2XX搜索栏主页
3、EtherPeekNX工具窗口停止捕获,进行分析捕获到的UDP报文。
图3-3UDP请求报文
图3-4UDP应答报文
本次实验验证了UDP协议的工作过程,从理论上讲,IP数据报的最大程度是65535字节,除去20字节的IP首部和8字节的UDP首部,UDP数据报中用户数据的最大长度应为65507字节,但大多数实现所提供的长度比这个最大值小。
例如,在SunOS4.1.3下使用回送接口的最大IP数据报长度是32767字节,所能接收的最大UDP报文长度为32747字节。
但在Solaris2.2下使用回送接口,最大可收发的IP数据报长度是65535字节,相应的最大UDP报文长度为65515。
显然,这种限制与具体操作系统的协议模块市县有关。
3.3UDP报文格式的分析
3.3.1报文格式
UDP报文又称为用户数据报,它分为首部和数据区两部分。
其中“源端口”和“目的端口”包含了16比特的UDP端口号,用于在各个等待接收报文的应用之间对数据报进行多路分解操作。
其中“源端口”字段可选,若选用,则指定了应答报文应该发往的目的端口;
若不选用,值为0。
“报文长度”字段指明以字节为单位的UDP首部和UDP数据的长度,最小值为8,即UDP首部的长度。
UDP报文首部的“校验和”字段是可选的。
如果该字段值为0,说明未进行校验。
设计者把这个字段作为可选项的目的,是为了尽量减少在可靠性很好的局域网上使用UDP的程序开销。
但IP对数据报中的数据部分并不计算校验和,所以UDP的校验和字段提供了唯一保证UDP报文无差错的途径。
3.3.2UDP信息包
UDP信息包由UDP标题和数据组成。
UDP的标题结构如图3-5所示,它由5个域组成:
源端端口(SourcePort)、目的地端口(DestinationPort)、用户数据包的长度(Length)和检查和(Checksum)。
其中,前4个域组成UDP标题(UDPheader),
每个域由4个字节组成;
检查和域占据2个字节,它用来检测传输过程中是否出现了错误;
用户数据包的长度包括所有5个域的字节数。
图3-5UDP的标题结构
以下是对使用检查和检测错误的举例说明。
假设从源端A要发送下列3个16位的二进制数:
word1,word2和word3到终端B,检查和计算如下。
图3-6UDP的检查计算
从发送端发出的4个16位二进制数之和为1111111111111111,如果接收端收到的这4个16位二进制数之和也是全“1”,就认为传输过程中没有出差错。
许多链路层协议都提供错误检查,包括流行的以太网协议。
由于链路层以下的协议在源端和终端之间的某些通道可能不提供错误检测,UDP虽然提供有错误检测,但检测到错误时,UDP不做错误校正,只是简单地把损坏的消息段扔掉,或者给应用程序提供警告信息,所以UDP也要提供检查和。
3.3.3UDP的伪首部
UDP校验和覆盖的内容超出了UDP数据报本身的范围。
为了计算校验和,UDP把伪首部引入数据报中,在伪首部中有一个值为0的填充八位组用于保证整个数据报的长度为16比特的整数倍,这样才好计算校验和。
填充八位组和伪首部并不随着UDP数据报一起传输,也不计算在数据报长度之内。
为了计算校验和,要先把校验和字段置为0,然后对整个对象,包括伪首部、UDP的首部和用户数据报,计算一个16比特的二进制反码和。
使用伪首部的目的是检验UDP数据报已到达正确的目的地。
正确的目的地包括了特定的主机和机器上特定的协议端口。
UDP报文的首部仅仅指定了使用的协议端口号。
因此为了确保数据报能够正确到达目的地,发送UDP数据报的机器在计算校验和时把目的机的IP地址和应有的数据都包括在内。
在最终的接收端,UDP协议软件对校验和进行检验时要用到携带UDP报文的IP数据报首部中的lP地址。
如果校验和正确,说明UDP数据报到达了正确主机的正确端口。
在UDP校验和的计算过程中用到的伪首部长度为12个八位组,其结构如下图所示。
图3-7UDP的伪首部
伪首部的源IP地址字段和目的IP地址字段记录了发送UDP报文时使用的源IP地址和目的IP地址。
协议字段指明了所使用的协议类型代码(UDP是17),而长度字段是UDP数据报的长度。
接收方进行正确性验证的时候,必须要把这些字段的信息从IP报文的首部中抽取出来,以伪首部的格式进行装配,然后再重新计算校验和。
4协议应用
4.1UDP协议应用
UDP是一种不可靠的网络协议,但是在有些情况下UDP协议可能会变得非常有用。
因为UDP具有TCP所望尘莫及的速度优势。
虽然TCP协议中植入了各种安全保障功能,但是在实际执行的过程中会占用大量的系统开销,无疑使速度受到严重的影响。
反观UDP由于排除了信息可靠传递机制,将安全和排序等功能移交给上层应用来完成,极大降低了执行时间,使速度得到了保证。
关于UDP协议的最早规范是RFC768,1980年发布。
尽管时间已经很长,但是UDP协议仍然继续在主流应用中发挥着作用。
包括视频电话会议系统在内的许多应用都证明了UDP协议的存在价值。
因为相对于可靠性来说,这些应用更加注重实际性能,所以为了获得更好的使用效果(例如,更高的画面帧刷新速率)往往可以牺牲一定的可靠性(例如,会面质量)。
根据不同的环境和特点,两种传输协议都将在今后的网络世界中发挥更加重要的作用。
4.2UDP协议的几个特性
(1)UDP是一个无连接协议,传输数据之前源端和终端不建立连接,当它想传送时就简单地去抓取来自应用程序的数据,并尽可能快地把它扔到网络上。
在发送端,UDP传送数据的速度仅仅是受应用程序生成数据的速度、计算机的能力和传输带宽的限制;
在接收端,UDP把每个消息段放在队列中,应用程序每次从队列中读一个消息段。
(2)由于传输数据不建立连接,因此也就不需要维护连接状态,包括收发状态等,因此一台服务机可同时向多个客户机传输相同的消息。
(3)UDP信息包的标题很短,只有8个字节,相对于TCP的20个字节信息包的额外开销很小。
(4)吞吐量不受拥挤控制算法的调节,只受应用软件生成数据的速率、传输带宽、源端和终端主机性能的限制。
(5)UDP使用尽最大努力交付,即不保证可靠交付,因此主机不需要维持复杂的链接状态表。
(6)UDP是面向报文的。
发送方的UDP对应用程序交下来的报文,在添加首部后就向下交付给IP层。
既不拆分,也不合并,而是保留这些报文的边界,因此,应用程序需要选择合适的报文大小。
虽然UDP是一个不可靠的协议,但它是分发信息的一个理想协议。
例如,在屏幕上报告股票市场、在屏幕上显示航空信息等等。
UDP也用在路由信息协议RIP(RoutingInformationProtocol)中修改路由表。
在这些应用场合下,如果有一个消息丢失,在几秒之后另一个新的消息就会替换它。
UDP广泛用在多媒体应用中,例如,ProgressiveNetworks公司开发的RealAudio软件,它是在因特网上把预先录制的或者现场音乐实时传送给客户机的一种软件,该软件使用的RealAudioaudio-on-demandprotocol协议就是运行在UDP之上的协议,大多数因特网电话软件产品也都运行在UDP之上。
我们经常使用“ping”命令来测试两台主机之间TCP/IP通信是否正常,其实“ping”命令的原理就是向对方主机发送UDP数据包,然后对方主机确认收到数据包,如果数据包是否到达的消息及时反馈回来,那么网络就是通的。
4.3UDP技术优缺点
互联网通信协议分为TCP和UDP两种.UDP和TCP协议的主要区别是两者在如何实现信息的可靠传递方面不同。
TCP协议中包含了专门的传递保证机制,当数据接收方收到发送方传来的信息时,会自动向发送方发出确认消息;
发送方只有在接收到该确认消息之后才继续传送其它信息,否则将一直等待直到收到确认信息为止。
与TCP不同,UDP协议并不提供数据传送的保证机制。
如果在从发送方到接收方的传递过程中出现数据报的丢失,协议本身并不能做出任何检测或提示。
因此,通常人们把UDP协议称为不可靠的传输协议。
相对于TCP协议,UDP协议的另外一个不同之处在于如何接收突法性的多个数据报。
不同于TCP,UDP并不能确保数据的发送和接收顺序。
例如,一个位于客户端的应用程序向服务器发出了以下4个数据报
D1
D22
D333
D4444
但是UDP有可能按照以下顺序将所接收的数据提交到服务端的应用:
事实上,UDP协议的这种乱序性基本上很少出现,通常只会在网络非常拥挤的情况下才有可能发生。
TCP是面向连接的,有比较高的可靠性,一些要求比较高的服务一般使用这个协议,如FTP、Telnet、SMTP、HTTP、POP3等,而UDP是面向无连接的,使用这个协议的常见服务有DNS、SNMP、QQ等。
5协议实现
5.1编写UDPServer程序
5.1.1编写步骤
(1)使用socket()来建立一个UDPsocket,第二个参数为SOCK_DGRAM。
(2)初始化sockaddr_in结构的变量,并赋值。
sockaddr_in结构定义:
structsockaddr_in{
uint8_tsin_len;
sa_family_tsin_family;
in_port_tsin_port;
structin_addrsin_addr;
charsin_zero[8];
};
这里使用“8888”作为服务程序的端口,使用“INADDR_ANY”作为绑定的IP地址即任何主机上的地址。
(3)使用bind()把上面的socket和定义的IP地址和端口绑定。
这里检查bind()是否执行成功,如果有错误就退出。
这样可以防止服务程序重复运行的问题。
(4)进入无限循环程序,使用recvfrom()进入等待状态,直到接收到客户程序发送的数据,就处理收到的数据,并向客户程序发送反馈。
这里是直接把收到的数据发回给客户程序。
5.1.2程序内容
#defineMAXLINE80
#defineSERV_PORT8888
voiddo_echo(intsockfd,structsockaddr*pcliaddr,socklen_tclilen)
{intn;
socklen_tlen;
charmesg[MAXLINE];
for(;
;
)
{
len=clilen;
/*waitingforreceivedata*/
n=recvfrom(sockfd,mesg,MAXLINE,0,pcliaddr,&
len);
/*sentdatabacktoclient*/
sendto(sockfd,mesg,n,0,pcliaddr,len);
}
intmain(void)
intsockfd;
structsockaddr_inservaddr,cliaddr;
sockfd=socket(AF_INET,SOCK_DGRAM,0);
/*createasocket*/
/*initservaddr*/
bzero(&
servaddr,sizeof(servaddr));
servaddr.sin_family=AF_INET;
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
servaddr.sin_port=htons(SERV_PORT);
/*bindaddressandporttosocket*/
if(bind(sockfd,(structsockaddr*)&
servaddr,sizeof(servaddr))==-1)
perror("
binderror"
);
exit
(1);
do_echo(sockfd,(structsockaddr*)&
cliaddr,sizeof(cliaddr));
return0;
5.2UDPClient程序
5.2.1编写UDPClient程序的步骤
(1)初始化sockaddr_in结构的变量,并赋值。
这里使用“8888”作为连接的服务程序的端口,从命令行参数读取IP地址,并且判断IP地址是否符合要求。
(2)使用socket()来建立一个UDPsocket,第二个参数为SOCK_DGRAM。
(3)使用connect()来建立与服务程序的连接。
与TCP协议不同,UDP的connect()并没有与服务程序三次握手。
上面说了UDP是非连接的,实际上也可以是连接的。
使用连接的UDP,kernel可以直接返回错误信息给用户程序,从而避免由于没有接收到数据而导致调用recvfrom()一直等待下去,看上去好像客户程序没有反应一样。
(4)向服务程序发送数据,因为使用连接的UDP,所以使用write()来替代sendto()。
这里的数据直接从标准输入读取用户输入。
(5)接收服务程序发回的数据,同样使用read()来替代recvfrom()。
(6)处理接收到的数据,这里是直接输出到标准输出上。
5.2.2udpclient.c程序内容:
#defineMAXLINE80
#defineSERV_PORT8888
voiddo_cli(FILE*fp,intsockfd,structsockaddr*pservaddr,socklen_tservlen)
{intn;
charsendline[MAXLINE],recvline[MAXLINE+1];
/*connecttoserver*/
if(connect(sockfd,(structsockaddr*)pservaddr,servlen)==-1)
{perror("
connecterror"
}
while(fgets(sendline,MAXLINE,fp)!
=NULL)
{/*readalineandsendtoserver*/
write(sockfd,sendline,strlen(sendline));
/*receivedatafromserver*/
n=read(sockfd,recvline,MAXLINE);
if(n==-1)
{
readerror"
recvline[n]=0;
/*terminatestring*/
fputs(recvline,stdout);
intmain
(intargc,char**argv)
structsockaddr_insrvaddr;
/*checkargs*/
if(argc!
=2)
{printf
("
usage:
udpclient\n"
/*initservaddr*/
servaddr,sizeof(servaddr));
if(inet_pton(AF_INET,argv[1],&
servaddr.sin_addr)<
=0)
{printf("
[%s]isnotavalidIPaddress\n"
argv[1]);
sockfd=socket(AF_INET,SOCK_DGRAM,0);
do_cli(stdin,sockfd,(structsockaddr*)&