欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

TCP/IP、UDP、HTTP、SOCKET详解

程序员文章站 2022-08-27 10:38:45
文章大纲 一、网络OSI七层及各层作用 二、TCP与UDP基本介绍 TCP TCP:Transmission Control Protocol 传输控制协议TCP是一种面向连接(连接导向)的、可靠的、基于字节流的运输层(Transport layer)通信协议。 特点: 面向连接的协议,数据传输必须 ......

文章大纲

  1. 网络osi七层及各层作用
  2. tcp与udp基本介绍
  3. tcp连接过程详解
  4. socket原理与连接详解
 
TCP/IP、UDP、HTTP、SOCKET详解
 

一、网络osi七层及各层作用

 
TCP/IP、UDP、HTTP、SOCKET详解
  1. 应用层:文件传输,电子邮件,文件服务,虚拟终端 tftp,http,snmp,ftp,smtp,dns,telnet
  2. 表示层:数据格式化,代码转换,数据加密 没有协议
  3. 会话层:解除或建立与别的接点的联系 没有协议
  4. 传输层:提供端对端的接口 tcp,udp
  5. 网络层:为数据包选择路由 ip,icmp,rip,ospf,bgp,igmp
  6. 数据链路层:传输有地址的帧以及错误检测功能 slip,cslip,ppp,arp,rarp,mtu
  7. 物理层:以二进制数据形式在物理媒体上传输数据 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/IP、UDP、HTTP、SOCKET详解
 

tcp连接终止协议*(tcp四挥手)

  由于tcp连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个fin来终止这个方向的连接。收到一个 fin只意味着这一方向上没有数据流动,一个tcp连接在收到一个fin后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
(1) tcp客户端发送一个fin,用来关闭客户到服务器的数据传送。
(2) 服务器收到这个fin,它发回一个ack,确认序号为收到的序号加1。和syn一样,一个fin将占用一个序号。
(3) 服务器关闭客户端的连接,发送一个fin给客户端。
(4) 客户端发回ack报文确认,并将确认序号设置为收到序号加1。

 

 
TCP/IP、UDP、HTTP、SOCKET详解
 

为什么客户端最后还要等待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 。套接字之间的连接过程分为三个步骤:服务器监听,客户端请求,连接确认。
  服务器监听:服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态,等待客户端的连接请求。
  客户端请求:指客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。
  连接确认:当服务器端套接字监听到或者说接收到客户端套接字的连接请求时,就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发 给客户端,一旦客户端确认了此描述,双方就正式建立连接。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。
连接实例

 
TCP/IP、UDP、HTTP、SOCKET详解
 

 

参考文章

    1. https://www.cnblogs.com/a0926/p/5174488.html