Wireshark抓包实验
1、实验名称
网络中不同层次里相关协议的分析与验证
2、实验目的
通过实验分析并验证TCP/IP协议族中各个协议的报文格式以及协议之间的交互过程,同时通过实验掌握TCP/IP协议报文捕获和分析工具。
3、实验内容
通过运行ping命令或浏览器或进行ftp文件下载产生网络行为,从而在某种网络行为下的报文(即分析wireshark捕获的icmp、arp、http、udp、tcp、smtp、报文并验证HTTP以及相关协议的报文格式和工作过程)。
4、实验结果分析
(备注:实验步骤我没有具体写,不然的话总页面数太多了)
1. TCP协议分析
TCP报文格式如下图所示:
三次握手:
发送请求报文——接受报文、回复——再发报文(完成3次握手开始正式通信)。
第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
第二次握手:服务器收到syn包,必须确认客户的ACK(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。
在完成三次握手,客户端与服务器开始传送数据。
四次挥手:由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这个原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
2、ARP报文分析
地址解析协议(ARP)的工作是实现网络层地址和链路层地址之间的转换,通常每个结点的RAM中都会保存有一个ARP表,当某个节点的表项在ARP表中不存在或者过期的话,那么就会产生ARP的特殊分组,有ARP查询分组和响应分组,二者具有相同的格式。ARP查询分组的目的就是寻问子网上所有的其他节点,以确定对应于要解析的IP地址对应的MAC地址,而ARP响应报文则是响应的节点返回MAC地址。
2.1 ARP请求报文:
主机A以广播的方式向网络发出ARP请求:“who has 192.168.42.129? tell 192.168.42.166”。找出192.168.42.129的物理地址后告诉192.168.42.166所在的主机。
2.2 ARP应答报文
主机B接收到ARP请求后,向主机A以单播的方式,发送ARP应答:“ 192.168.42.129 is at 96:00:95:d3:d1:e6“。
3、ICMP报文分析
ICMP格式
ICMP报文包含在IP数据中,属于IP的一个用户,IP头部就在ICMP报文的前面,所以一个ICMP报文包括IP头部、ICMP头部和ICMP报文,当IP头部的协议项的值为1就说明这是一个ICMP报文,ICMP头部中的类型域(Type)用于说明ICMP报文的作用及格式,此外还有一个代码域(Code)用于详细说明某种ICMP报文的类型,所有的数据都在ICMP头部后面。
执行ping的过程截图如下所示:
抓包结果截图:
由抓包的截图可得:
类型:8 (回显请求)代码:0
校验和:0x4d56(正确的校验和)
标示符:0x0001(BE)、0x0100(LE);
序列号:0x0005(BE)、0x0500(LE);
并且ICMP报文有请求和响应两种类型的报文,二者的格式是一致的。
4、HTTP报文分析
HTTP协议(超文本协议)是一个基于请求与响应模式的、无状态的、应用层的协议,常基于TCP的连接方式,HTTP 1.1版本中给出一种持续连接的机制,绝大多数的Web开发都是构建在HTTP协议之上的Web应用。其中HTTP协议是支持客户/服务器模式的,客户向服务器请求服务时,只需传送请求方法和路径,请求方法通常有GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。
4.1 HTTP请求报文分析(有不同的请求方法)
4.1.1 GET方法请求报文(第345个包)
请求行:方法字段:GET,版本是http/1.1.
首部行:主机host:sext.ie.sogou.com\r\n
Connection:Keep-Alive,即保持持久连接;
Accept-language:zh-cn,即接收语言是中文(图片上没有截到这小部分内容)。
4.1.2 POST方法请求报文(第394个包)
正如刚开始的分析阶段所示,HTTP协议提供了其他的请求方法,如下面所示的POST方法:
请求行:方法字段:POST,版本是http/1.1.
首部行:主机host:safe.ie.sogou.com\r\n
Connection:keep-alive,即保持持久连接;
Accept-language:zh-cn,即接收语言是中文。
4.2 HTTP响应报文(第967个包)
状态行:http/1.1 200 ok;请求成功。
首部行:响应Date:Tue,11,Dec 2012 11:11:06 GMT\r\n;
Content-Type:image/png\r\n 指示传输的对象是image/png图片;
Content-Length:223\r\n表明了被发送对象的字节数是223个字节。
4.3 HTTP协议数据传输出错分析
当数据传输正常时,会显示一直是处于Continuation or non-HTTP traffic状态,也就是Connection-alive状态。但是当TCP传输的报文丢失或者客户端所接受的报文无序时,便问请求重新发送。当重新发送成功时便又会回到Continuation or non-HTTP traffic状态。如下截图所示:
如截图中黑色线出着重凸显的4行内容,体现了数据传输出错时的原因和相关的处理方法(实际上就是重新传送),这是当HTTP基于TCP连接方式下的情况。
5、UDP报文分析
因为在发送方和接受方之间开始传输数据时,二者之间并没有进行过握手,所以UDP传输协议又称为无连接运输,提供面向事物的简单的不可靠信息传送服务,也就报文发送之后,是无法得知其是否安全完整到达的,IETF RFC 768是UDP的正式规范,与TCP一样,UDP协议直接位于IP协议的顶层。
UDP的报文段结构:
UDP报文段结构
UDP传输协议截图如下:
如截图可以看出是没有握手过程的,直接通过源端口和目的端口开始数据的传输。
源端口号:itap-ddtp(10100)
目的端口号:10166(10166)
总长度:1416bytes
检验和:0x4a4b(validation disabled)
数据长度:1408bytes
因为报头部分由4个字段,每个字段有2个字节,所以首部段为8个字节,再加上数据报文长度是1408字节,所以总的字节长度为1416字节,结果是对的。
6、SMTP报文分析
SMTP协议即简单邮件传输协议,是一种可靠且有效电子邮件传输文本协议。SMTP是建立在FTP文传输服务上的一种邮件服务,可以很简单地通过Telnet程序来测试一个SMTP服务器,SMTP使用TCP端口为25(Telnet的默认端口是23)。在实验之前需要下载Telnet小软件和64位转换器(用于在Telnet中输入用户名和密码,输入之前要用进行转码),然后在163邮箱主界面中的设置项中获得smtp.163.com这一服务器地址,然后打开转包软件wireshark软件就可以进行转包实验了。
在Telnet中,需要先和服务器建立连接,在telnet命令解释器中输入open smtp.163.com 25,就可以建立与smtp服务器的连接了。所截得的报文如下:
源端口:smtp (25);
目的端口:12198(12198);
报头长度:20 bytes;
响应代码(code):service ready(220),,220是邮件服务器返回给客户的相应状态,表示邮件服务器准备就绪。
响应参量:163.com Anti-spam GT for Coremail System(163com[20121016]),163.com是服务器的名称。
至此已经登上网易的smtp服务器了,通过敲击smtp指令就可以与服务器进行通信了。通过输入ehlo指令和auth login指令,并输入经过转码的用户名和密码就可以完成登录,再通过发送指令来发送邮件信息(包括mail from, rcpt to)。Telnet命令行截图如下:
因为我只有一个网易账号,所以我给自己发送了一封邮件,邮件的内容为”hello, whaat”,登录邮箱可以查看接受到的邮件。
抓包情况如下图所示:
在整个过程中,我进行了三次和服务器建立连接,之前两次分别由于指令输入错误次数过多和过长的等待时间而自动和服务器失去连接,最后一次成功登录并发送了邮件。观察截图可以发现,在返回的响应报文中有不同的数值参数,如502,503,334,235,250,354。其中502和503分别是两种不同类型的输入错误,502表示输入的命令在命令解释器中不存在,而503表示该主机还没有在服务器上注册;334则表示认证的内容无差错;235表示账户在服务器上认证成功;250则表示状态就绪,为OK;354表示邮件服务器在等...
下面对部分报文进行分析:
第一条:以telnet方式连接到服务器,这条在前面已经分析过了;
第二条:在服务器上注册主机,建立的是TCP连接;
此处输入的命令为ehlo,用于和服务器建立连接,即在服务器上注册该主机,eric是主机注册时的用户名,这个名称在输入的时候可以是任意的。当点开网络层时可以看到,改过程建立的是TCP连接,且协议为IPV4。
源端口:12217(12217);
目的端口:smtp(25);
命令(Command):ehlo;
请求的主机名:eric。
第三条:在服务器上验证邮箱的账号和密码;
图中报文所显示的是从开始认证到认证成功的过程,其中输入的还包括经转码后的用户名和密码(第3行和第5行),最后服务器返回的235,表示用户名和密码已经认证成功,该账户已经成功登录服务器,可以进行邮件的收发工作了。
第四条:通过telnet发送邮件过程;
账户登录之后,当进行发邮件工作时,先输入发送方的地址(mail from:<13508479146@163.com>),待服务器确认之后再输入接收方的邮件地址(rcpt to:<13508479146@163.com>),然后输入data,服务器分析该指令之后会返回结束方式的提示,然后输入要进行发送的内容,最后在一行中以单独的“.”结束输入并发送报文,服务器返回250 Mail OK表示邮件成功发送。
5、实验总结
作为一名计算机专业的学生,计算机网络是我们学业的重中之重。通过从上至下的顺序对网络中的不同层次进行学习,让我们大致了解了网络中数据传输和处理的原理和方法,对网络中的一些专业概念和名词进行讲解。之前上课听的总是云里雾里的,在抽象的层面上总是很难接受一些概念的东西,正如蔡老师说的,我们需要通过实践来验证这些过程,因为他们是真实存在的,但又是不可见的这次试验给我们提供了这样的机会。
在最开始的时候,根本不知道如何下手开始试验,教辅只是简单地讲解了软件的使用,然后让我们自己动手做。于是我们对着书和上网查找一些协议的功能,逐渐展开了我们的实验,有不懂得就相互讨论,最后对教员所要求的6种协议都有了更深层次的理解和体会。所以只要用心做,对于大学生而言,总可以做好的。
通过这次试验,我培养了自己动手的能力,另外,通过对wireshark抓包软件的使用,用其来抓取数据包,对http的请求、响应报文有了进一步的了解,对建立TCP连接时的三次握手有了切实的体会,通过对TCP报文首部格式的分析,并且把课本上多学的理论知识与实践结合起来,对以前的知识得到深化和巩固,为以后学习新的知识打下基础,也提高了学习的兴趣,收获很大。值得一提的是在抓smtp报文的过程中,我通过在网上查找方法,最终找到了Telnet程序用于建立和smtp服务器的连接,并下载了64为转码器进行用户名和密...
TCP实验
1 实验名称
基于TCP的Socket编程
2实验目的:
通过本实验了解和掌握编写基于TCP协议的网络应用程序, 能够使用套接字建立TCP连接传输数据,并实现客户端与服务器彼此之间的多线程通讯,加深对传输层协议的理解。
3 实验过程的函数分析
3.1 TCPclient
3.1.1socket()函数
1)函数功能
创建一个socket接口
2)函数原型
int socket(int family, int type, int Protecol);
family指定协议族,linux下:AF_INET(标明使用TCP/IP协议族),
type指定套接口类型:linux下有四种,分别是:SOCKET_STREAM,SOCK_DGRAM……(流套接字,数据套接字,……);
Protocol协议族类型:IPPROTO_TCP,IPPROTO_UDP,IPPRO_SCTP,分别是TCP传输协议,UDP传输协议,SCTP传输协议;
3)函数返回值
若成功创建socket,返回一个套接口描述字,简称套接字。若失败,则返回-1。
4)所需函数库
Sys/socket.h: 提供socket函数及数据结构。
5)调用样例
int sockfd;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
3.1.2 connect()函数
1)函数功能
建立连接。
2)函数原型
int connect(int sockfd,struct sockaddr *serv_addr, int addrlen);
sockfd:Socket描述符;
serv_addr:通信目的方的地址;
addrlen:目的地址长度。
值得一提的是,连接函数如bind、listen都是被动地等待对方建立连接时需要使用的,而connect()函数,则是主动地向对方建立连接时使用的。Connect()使用一个事先打开的socket,和目的方(即通信对方,或称服务器一方)地址信息,向对方发出建立连接的请求。
3)函数返回值
连接正常则返回0;否则,返回-1,系统错误码在errno中。
4)所需函数库
sys/types.h
sys/socket.h
5)调用样例
if( connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0);
在此函数调用中,我没有专门设置一个值来存储返回的值,而是对返回的值直接进行了判定。
3.1.3 recv ()函数
1)函数功能
本函数用于已连接的流式套接口进行数据的接收。
2)函数原型
int recv(int sockfd, char * buff,int len, int flags);
sockfd:socket描述符;
buff:存放发送数据的存储空间;
len:接收数据的字节数;
flags:通常设为0,详细说明可以参考Linux Manual。
3)函数返回值
返回实际接收到的数据字节数,或者-1,表示出错。
4)所需函数库
sys/types.h
sys/socket.h
5)调用样例
int k;
k=recv(sockfd, buff, MAXLINE, 0);
3.1.4 send()函数
1)函数功能
适用于已连接的流式套接口sockfd发送数据。
2)函数原型
int send( int sockfd, const char *sendline,int len,int flags);
sockfd:socket描述符;
sendline:用于存储发送数据的存储空间;
len:发送的数据的字节数;
flags:通常设为0,详细说明可以参考Linux Manual。
3)函数返回值
返回实际发送的数据的字节数,或者-1,表示出错。
4)所需函数库
sys/types.h
sys/socket.h
5)调用样例
if(send(sockfd,sendline, strlen(sendline), 0) ==-1)
对函数调用的返回值直接进行判断,没有设置专门的变量。
3.2 TCPserver
3.2.1 socket()函数
1)函数功能
创建一个socket接口
2)函数原型
int socket(int family, int type, int Protecol);
family指定协议族,linux下:AF_INET(标明使用TCP/IP协议族),
type指定套接口类型:linux下有四种,分别是:SOCKET_STREAM,SOCK_DGRAM……(流套接字,数据套接字,……);
Protocol协议族类型:IPPROTO_TCP,IPPROTO_UDP,IPPRO_SCTP,分别是TCP传输协议,UDP传输协议,SCTP传输协议;
3)函数返回值
若成功创建socket,返回一个套接口描述字,简称套接字。若失败,则返回-1。
4)所需函数库
Sys/socket.h: 提供socket函数及数据结构。
5)调用样例
int sockfd;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
3.2.2 connect()函数
1)函数功能
建立连接。
2)函数原型
int connect(int sockfd,struct sockaddr *serv_addr, int addrlen);
sockfd:Socket描述符;
serv_addr:通信目的方的地址;
addrlen:目的地址长度。
值得一提的是,连接函数如bind、listen都是被动地等待对方建立连接时需要使用的,而connect()函数,则是主动地向对方建立连接时使用的。Connect()使用一个事先打开的socket,和目的方(即通信对方,或称服务器一方)地址信息,向对方发出建立连接的请求。
3)函数返回值
连接正常则返回0;否则,返回-1,系统错误码在errno中。
4)所需函数库
sys/types.h
sys/socket.h
5)调用样例
if( connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0);
在此函数调用中,我没有专门设置一个值来存储返回的值,而是对返回的值直接进行了判定。
3.2.3 recv ()函数
1)函数功能
本函数用于已连接的流式套接口进行数据的接收。
2)函数原型
int recv(int sockfd, char * buff,int len, int flags);
sockfd:socket描述符;
buff:存放发送数据的存储空间;
len:接收数据的字节数;
flags:通常设为0,详细说明可以参考Linux Manual。
3)函数返回值
返回实际接收到的数据字节数,或者-1,表示出错。
4)所需函数库
sys/types.h
sys/socket.h
5)调用样例
int k;
k=recv(sockfd, buff, MAXLINE, 0);
3.2.4 send()函数
1)函数功能
适用于已连接的流式套接口sockfd发送数据。
2)函数原型
int send( int sockfd, const char *sendline,int len,int flags);
sockfd:socket描述符;
sendline:用于存储发送数据的存储空间;
len:发送的数据的字节数;
flags:通常设为0,详细说明可以参考Linux Manual。
3)函数返回值
返回实际发送的数据的字节数,或者-1,表示出错。
4)所需函数库
sys/types.h
sys/socket.h
5)调用样例
if(send(sockfd,sendline, strlen(sendline), 0) ==-1)
对函数调用的返回值直接进行判断,没有设置专门的变量。
3.2.5 bind()函数
1)函数功能
绑定socket,将ip、port与socket绑定。
2)函数原型
int bind(int sockfd, struct sockaddr *my_addr, int addrlen);
sockfd:socket描述符
my_addr:一个指向包含有本机IP地址及端口号等信息的sockaddr类型的指针;
addrlen:常被设置为sizeof(struct sockaddr)。
3)函数返回值
成功被调用时返回0;遇到错误时返回“-1”,并将errno置为相应的错误号。
4)所需函数库
sys/types.h
sys/socket.h
5)调用样例
if( bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1);
对函数调用的返回值直接进行判断,没有设置专门的变量,若返回值为-1,则表示绑定过程发生错误。
3.2.6 listen()函数
1)函数功能
服务器监听连接的接口以判断是否有服务请求。
2)函数原型
int listen(int sockfd, int backlog);
sockfd:是Socket系统调用返回的socket描述符;
backlog:在请求队列中允许的最大请求数。
3)函数返回值
遇到错误时返回-1,errno被置为相应的错误码。
4)所需函数库
sys/types.h
sys/socket.h
5)调用样例
if( listen(listenfd, 10) == -1);
对函数调用的返回值直接进行判断,没有设置专门的变量,若返回之为-1,则表示监 听过程发生错误。
3.2.6 accept()函数
1)函数功能
接受指定Socket接口上的连接请求。
2)函数原型
int accept(int scokfd,struct sockaddr*addr,int *addrlen);
sockfd:socket描述符;
addr:accept()接受连接之后,在addr指向的结构中存放对方的地址信息。如果是AF_INET Socket,该地址信息就是对方的IP地址和端口号。
addrlen:在调用accept()之前,*addrlen必须被设置为addr数据结构的合法长度。在accept()返回之后,*addrlen中是对方地址信息的长度。
3)函数返回值
如果正常创建了一个新的连接,那么返回非负的整数:即新连接的Socket描述符,否则返回-1,errno是系统的错误码。
4)所需函数库
sys/types.h
sys/socket.h
5)调用样例
int connfd;
connfd = accept(listenfd,(struct sockaddr*)NULL, NULL)。
4 程序流程图
服务器与客户机3次握手过程
TCPclient与TCPserver的工作流程图:
5 程序运行结果分析
6、实验总结
在最初学习网络这门课程的时候,从来没有想过自己还可以编写TCP通信的程序,因为我一直觉得QQ或者其他的通讯软件特别厉害,普通人是不可能实现那样的功能的。但是在网络实验的过程中,渐渐地学习一些相关的函数和参考别人的代码,结合通信的工作原理图,开始慢慢地入门。在实现多线程的过程中,开始我只是通过设定一些中间变量来控制通话的过程,比如当某个端点输入某个特定的字符之后,对方就可以恢复了,但是教辅说这个只能是半成品,后面在看操作系统的书时,想到了子进程的创建,于是我想服务器或者在运行接受或者发送进程时,同...
这个实验提高了我的动手能力和自学的能力,也让我对TCP连接方式有了更进一步的理解和体会,在课程学习里设定的实验,只要用心和努力,总可以顺利完成、总会有收获。