TCP/IP、UDP、HTTP、SOCKET详解
文章大纲
- 网络osi七层及各层作用
- tcp与udp基本介绍
- tcp连接过程详解
- socket原理与连接详解
一、网络osi七层及各层作用
- 应用层:文件传输,电子邮件,文件服务,虚拟终端 tftp,http,snmp,ftp,smtp,dns,telnet
- 表示层:数据格式化,代码转换,数据加密 没有协议
- 会话层:解除或建立与别的接点的联系 没有协议
- 传输层:提供端对端的接口 tcp,udp
- 网络层:为数据包选择路由 ip,icmp,rip,ospf,bgp,igmp
- 数据链路层:传输有地址的帧以及错误检测功能 slip,cslip,ppp,arp,rarp,mtu
- 物理层:以二进制数据形式在物理媒体上传输数据 iso2110,ieee802,ieee802.2
二、tcp与udp基本介绍
tcp
tcp:transmission control protocol 传输控制协议tcp是一种面向连接(连接导向)的、可靠的、基于字节流的运输层(transport layer)通信协议。 特点: 面向连接的协议,数据传输必须要经过三次握手建立连接,所以在tcp中需要连接时间。 传输数据大小限制,一旦连接建立,双方可以按统一的格式传输大的数据。 一个可靠的协议,确保接收方完全正确地获取发送方所发送的全部数据。
udp
udp: user datagram protocol的简称, 中文名是用户数据包协议,是 osi 参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务。 特点: 每个数据报中都给出了完整的地址信息,因此无需要建立发送方和接收方的连接。 udp传输数据时是有大小限制的,每个被传输的数据报必须限定在64kb之内。 udp是一个不可靠的协议,发送方所发送的数据报并不一定以相同的次序到达接收方。
三、tcp连接过程详解
基本参数介绍
listen:侦听来自远方的tcp端口的连接请求
syn-sent:再发送连接请求后等待匹配的连接请求(客户端)
syn-received:再收到和发送一个连接请求后等待对方对连接请求的确认(服务器)
established:代表一个打开的连接
fin-wait-1:等待远程tcp连接中断请求,或先前的连接中断请求的确认
fin-wait-2:从远程tcp等待连接中断请求
close-wait:等待从本地用户发来的连接中断请求
closing:等待远程tcp对连接中断的确认
last-ack:等待原来的发向远程tcp的连接中断请求的确认
time-wait:等待足够的时间以确保远程tcp接收到连接中断请求的确认
closed:没有任何连接状态
主动端可能出现的状态:fin_wait1、fin_wait2、closing、time_wait
被动端可能出现的状态:close_wait last_ack
客户端的状态可以用如下的流程来表示:
closed->syn_sent->established->fin_wait_1->fin_wait_2->time_wait->closed
服务器的状态可以用如下的流程来表示:
closed->listen->syn收到->established->close_wait->last_ack->closed
温馨提示:
(1)主动端出现大量的fin_wait1时需要注意网络是否畅通、出现大量的fin_wait2需要仔细检查程序为何迟迟收不到对端的fin(可能是主动方或者被动方的bug)、出现大量的time_wait需要注意系统的并发量/socket句柄资源/内存使用/端口号资源等。
(2)被动端出现大量的 close_wait 需要仔细检查为何自己迟迟不愿调用close关闭连接(可能是bug,socket打开用完没有关闭)
状态迁移
建立连接时的状态变迁
一开始,建立连接之前服务器和客户端的状态都为closed。服务器创建socket后开始监听,变为listen状态。客户端请求建立连接,向服务器发送syn报文,客户端的状态变为syn_sent。服务器收到客户端的报文后向客户端发送ack和syn报文,此时服务器的状态变为syn_rcvd。然后,客户端收到ack、syn,就向服务器发送ack,客户端状态变为established,服务器收到客户端的ack后也变为established。此时,3次握手完成,连接建立!
断开连接时的状态变迁
由于tcp连接是全双工的,断开连接会比建立连接麻烦一点点。客户端先向服务器发送fin报文,请求断开连接,其状态变为fin_wait1。服务器收到fin后向客户端发生ack,服务器状态变为close_wait。客户端收到ack后就进入fin_wait2状态。此时连接已经断开了一半了。如果服务器还有数据要发送给客户端,就会继续发送。直到发完了,就发送fin报文,此时服务器进入last_ack状态。客户端收到服务器的fin后,马上发送ack给服务器,此时客户端进入time_wait状态,再过了2msl长的时间后进入closed状态。服务器收到客户端的ack就进入closed状态。
至此,还有一个状态没有提及:closing状态。closing状态表示客户端发生了fin,但没有收到服务器的ack,却收到了服务器的fin。这种情况发生在服务器发送的ack丢包的时候,因为网络传输有时会有意外。
tcp连接建立(tcp三握手)
tcp连接的建立采用客户-服务器模式:主动发起连接建立的应用进程叫做客户,被动等待连接建立的应用进程叫做服务器。
连接建立阶段:
第一次握手:客户端的应用进程主动打开,并向服务端发出请求报文段。其首部中:syn=1,seq=x。
第二次握手:服务器应用进程被动打开。若同意客户端的请求,则发回确认报文,其首部中:syn=1,ack=1,ack=x+1,seq=y。
第三次握手:客户端收到确认报文之后,通知上层应用进程连接已建立,并向服务器发出确认报文,其首部:ack=1,ack=y+1。当服务器收到客户端的确认报文之后,也通知其上层应用进程连接已建立。
在这个过程中,通信双方的状态如下图,其中closed:关闭状态、listen:收听状态、syn-sent:同步已发送、syn-rcvd:同步收到、estab-lished:连接已建立
至此,tcp连接就建立了,客户端和服务器可以愉快地玩耍了。只要通信双方没有一方发出连接释放的请求,连接就将一直保持。
tcp连接终止协议*(tcp四挥手)
由于tcp连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个fin来终止这个方向的连接。收到一个 fin只意味着这一方向上没有数据流动,一个tcp连接在收到一个fin后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
(1) tcp客户端发送一个fin,用来关闭客户到服务器的数据传送。
(2) 服务器收到这个fin,它发回一个ack,确认序号为收到的序号加1。和syn一样,一个fin将占用一个序号。
(3) 服务器关闭客户端的连接,发送一个fin给客户端。
(4) 客户端发回ack报文确认,并将确认序号设置为收到序号加1。
为什么客户端最后还要等待2msl?
msl(maximum segment lifetime),tcp允许不同的实现可以设置不同的msl值。
第一,保证客户端发送的最后一个ack报文能够到达服务器,因为这个ack报文可能丢失,站在服务器的角度看来,我已经发送了fin+ack报文请求断开了,客户端还没有给我回应,应该是我发送的请求断开报文它没有收到,于是服务器又会重新发送一次,而客户端就能在这个2msl时间段内收到这个重传的报文,接着给出回应报文,并且会重启2msl计时器。
第二,防止类似与“三次握手”中提到了的“已经失效的连接请求报文段”出现在本连接中。客户端发送完最后一个确认报文后,在这个2msl时间中,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样新的连接中不会出现旧连接的请求报文。
为什么建立连接是三次握手,关闭连接确是四次挥手呢?
建立连接的时候,服务器在listen状态下,收到建立连接请求的syn报文后,把ack和syn放在一个报文里发送给客户端。而关闭连接时,服务器收到对方的fin报文时,仅仅表示对方不再发送数据了但是还能接收数据,而自己也未必全部数据都发送给对方了,所以己方可以立即关闭,也可以发送一些数据给对方后,再发送fin报文给对方来表示同意现在关闭连接,因此,己方ack和fin一般都会分开发送,从而导致多了一次。
参数详解
closed
这个没什么好说的了,表示初始状态。
listen
这个也是非常容易理解的一个状态,表示服务器端的某个socket处于监听状态,可以接受连接了。
syn_rcvd
这个状态表示接受到了syn报文,在正常情况下,这个状态是服务器端的socket在建立tcp连接时的三次握手会话过程中的一个中间状态,很短暂,基本上用netstat你是很难看到这种状态的,除非你特意写了一个客户端测试程序,故意将三次tcp握手过程中最后一个ack报文不予发送。因此这种状态时,当收到客户端的ack报文后,它会进入到established状态。
syn_sent
这个状态与syn_rcvd遥想呼应,当客户端socket执行connect连接时,它首先发送syn报文,因此也随即它会进入到了syn_sent状态,并等待服务端的发送三次握手中的第2个报文。syn_sent状态表示客户端已发送syn报文。
established
这个容易理解了,表示连接已经建立了。
fin_wait_1
这个状态要好好解释一下,其实fin_wait_1和fin_wait_2状态的真正含义都是表示等待对方的fin报文。而这两种状态的区别是:fin_wait_1状态实际上是当socket在established状态时,它想主动关闭连接,向对方发送了fin报文,此时该socket即进入到fin_wait_1状态。而当对方回应ack报文后,则进入到fin_wait_2状态,当然在实际的正常情况下,无论对方何种情况下,都应该马上回应ack报文,所以fin_wait_1状态一般是比较难见到的,而fin_wait_2状态还有时常常可以用netstat看到。
fin_wait_2
上面已经详细解释了这种状态,实际上fin_wait_2状态下的socket,表示半连接,也即有一方要求close连接,但另外还告诉对方,我暂时还有点数据需要传送给你,稍后再关闭连接这就是著名的半关闭的状态了,这是在关闭连接时,客户端和服务器两次握手之后的状态。在这个状态下,应用程序还有接受数据的能力,但是已经无法发送数据,但是也有一种可能是,客户端一直处于fin_wait_2状态,而服务器则一直处于wait_close状态,而直到应用层来决定关闭这个状态
time_wait
表示收到了对方的fin报文,并发送出了ack报文,就等2msl后即可回到closed可用状态了。如果fin_wait_1状态下,收到了对方同时带fin标志和ack标志的报文时,可以直接进入到time_wait状态,而无须经过fin_wait_2状态。
closing
这里先说一下另一种状态(同时打开)
rst是另一种关闭连接的方式,应用程序应该可以判断rst包的真实性,即是否为异常中止。而同时打开和同时关闭则是两种特殊的tcp状态,发生的概率很小。
下面说closing状态 ,这种状态比较特殊,实际情况中应该是很少见,属于一种比较罕见的例外状态。正常情况下,当你发送fin报文后,按理来说是应该先收到(或同时收到)对方的ack报文,再收到对方的fin报文。但是closing状态表示你发送fin报文后,并没有收到对方的ack报文,反而却也收到了对方的fin报文。什么情况下会出现此种情况呢?其实细想一下,也不难得出结论:那就是如果双方几乎在同时close一个socket的话,那么就出现了双方同时发送fin报文的情况,也就会出现closing状态,表示双方都正在关闭socket连接。
close_wait
这种状态的含义其实是表示在等待关闭。怎么理解呢?当对方close一个socket后发送fin报文给自己,你系统毫无疑问地会回应一个ack报文给对方,此时则进入到close_wait状态。接下来呢,实际上你真正需要考虑的事情是查看你是否还有数据发送给对方,如果没有的话,那么你也就可以close这个socket,发送fin报文给对方,也即关闭连接。所以你在close_wait状态下,需要完成的事情是等待你去关闭连接。
last_ack
这个状态还是比较容易好理解的,它是被动关闭一方在发送fin报文后,最后等待对方的ack报文。当收到ack报文后,也即可以进入到closed可用状态了。
四、socket原理与连接详解
socket原理
socket socket的英文原义是“孔”或“插座”。作为4bds unix的进程通信机制,取后一种意思。通常也称作“套接字”,用于描述ip地址和端口,是一个通信链的句柄(引用)。 每个插座就是一个应用程序。 细节 不同的通信规则需要定义不同的插座。 udp:datagramsocket 、 datagrampacket tcp:serversocket 、socket
建立socket连接
建立socket连接至少需要一对套接字,其中一个运行于客户端,称为clientsocket ,另一个运行于服务器端,称为serversocket 。套接字之间的连接过程分为三个步骤:服务器监听,客户端请求,连接确认。
服务器监听:服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态,等待客户端的连接请求。
客户端请求:指客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。
连接确认:当服务器端套接字监听到或者说接收到客户端套接字的连接请求时,就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发 给客户端,一旦客户端确认了此描述,双方就正式建立连接。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。
连接实例
参考文章