网络原理TCP/IP(4)

文章目录

  • 面向字节流
  • 粘包问题
  • 异常情况
  • TCP小结

面向字节流

创建⼀个TCP的socket,同时在内核中创建⼀个发送缓冲区和⼀个接收缓冲区;

• 调⽤write时,数据会先写⼊发送缓冲区中;

• 如果发送的字节数太⻓,会被拆分成多个TCP的数据包发出;

• 如果发送的字节数太短,就会先在缓冲区⾥等待,等到缓冲区⻓度差不多了,或者其他合适的时机发送出去;

• 接收数据的时候,数据也是从⽹卡驱动程序到达内核的接收缓冲区;

• 然后应⽤程序可以调⽤read从接收缓冲区拿数据;

• 另⼀⽅⾯,TCP的⼀个连接,既有发送缓冲区,也有接收缓冲区,那么对于这⼀个连接,既可以读数据,也可以写数据.这个概念叫做全双⼯

由于缓冲区的存在,TCP程序的读和写不需要⼀⼀匹配,例如:
• 写100个字节数据时,可以调⽤⼀次write写100个字节,也可以调⽤100次write,每次写⼀个字节;
• 读100个字节数据时,也完全不需要考虑写的时候是怎么写的,既可以⼀次read100个字节,也可以⼀次read⼀个字节,重复100次;

粘包问题

• ⾸先要明确,粘包问题中的"包",是指的应⽤层的数据包.
• 在TCP的协议头中,没有如同UDP⼀样的"报⽂⻓度"这样的字段,但是有⼀个序号这样的字段.
• 站在传输层的⻆度,TCP是⼀个⼀个报⽂过来的.按照序号排好序放在缓冲区中.
• 站在应⽤层的⻆度,看到的只是⼀串连续的字节数据.
• 那么应⽤程序看到了这么⼀连串的字节数据,就不知道从哪个部分开始到哪个部分,是⼀个完整的应⽤层数据包.

那么如何避免粘包问题呢?归根结底就是⼀句话,明确两个包之间的边界.

  1. 通过特殊符号,作为分隔符,见到分隔符就视为是一个包结束
  2. 指定出包的长度,比如在包开始的位置加上一个特殊的空间来表示整个数据的长度

上述的这样的问题,都是应该在设计应用层协议的时候把这些问题都考虑进去了

思考:对于UDP协议来说,是否也存在"粘包问题"呢?
• 对于UDP,如果还没有上层交付数据,UDP的报⽂⻓度仍然在.同时,UDP是⼀个⼀个把数据交付给应⽤层.就有很明确的数据边界.
• 站在应⽤层的站在应⽤层的⻆度,使⽤UDP的时候,要么收到完整的UDP报⽂,要么不收.不会出现"半个"的情况。

异常情况

  1. 其中一方出现了进程崩溃
    进程无论是正常结束还是异常崩溃,都会触发到回收文件资源,关闭文件这样的效果(系统自动完成),就会触发四次挥手
    TCP连接的生命周期,可以比进程更长一些,虽然进程已经退出了,但是TCP连接还在,仍然可以继续进行四次挥手
  2. 其中一方出现了关机(按照正常流程关机)
    当有个主机触发关机操作就会先强制终止所有的进程(类似于上述的强杀进程),终止进程自然就会触发四次挥手,但是四次挥手不一定能挥完,如果挥手快,能够顺利挥完,此时本段和对端都能正确的删除掉保存的连接信息,如果挥手慢,至少也能把第一个fin发给对端,告诉对端,本端要结束了,对端收到fin之后,对端也就要进入释放连接的流程,返回ack,并且发送fin,但是不会有ack应答,势必要进行重传(超时重传的流程中),当重传几次之后发现还是不行,还是没有ack,这个时候单方面的释放连接信息
  3. 其中一方·出现了断电(直接拔电源,突发性的关机)
    如果直接断电,机器瞬间关机,来不及发送fin
    a)断电的是接收方,发送方就会突然发现没有ack了,就要重传,重传几次之后还是不行,TCP就会尝试“复位”连接(相当于清除原来的TCP中的各种临时数据,重新开始)需要用到TCP的“复位报文段”RST
    b)断电的是发送方,这种情况下,接收方需要区分出,发送方是挂了还是暂时没发,就会触发“心跳包”来询问对方的情况,如果对方没有回应,本端就会尝试复位并且单方面释放连接了
  4. 网线断开
    情况结合3中的a)和 b)

TCP小结

为什么TCP这么复杂?因为要保证可靠性,同时⼜尽可能的提⾼性能.
可靠性:
• 校验和
• 序列号(按序到达)
• 确认应答
• 超时重发
• 连接管理
• 流量控制
• 拥塞控制

提高性能:
• 滑动窗⼝
• 快速重传
• 延迟应答
• 捎带应答

你可能感兴趣的:(网络,tcp/ip,网络协议)