Posix API与网络协议栈

文章目录

  • posix API
    • tcp网络编程主要学习的几个点,网络的api
    • socket
    • bind;
  • TCP三次握手过程
    • 数据发送
    • connect
    • udp
  • 断开连接的过程


posix API

tcp网络编程主要学习的几个点,网络的api

Posix API与网络协议栈_第1张图片

socket

意思是插座,两部分组成,fd(文件描述符),tcb(tcp control block)tcp控制块,是协议栈里边的
任何文件的文件描述符fd,是从3开始的,因为0,1,2是系统的标准输入输出报错,比3小的已经被系统占有了
在这里插入图片描述

bind;

五元组(remoteip, remoteport, localip, localport, proto),最后一个参数是协议类型,bind绑定时,用来填充本机的ip与端口
socket与bind在tcp这段是做准备的,属于本地的操作与外界没有关系

TCP三次握手过程

客户端 服务端
Posix API与网络协议栈_第2张图片
这个问题,为啥会是三次,就是为了确保双向通信
握手的过程中,服务端这边是被动的,第一次握手,服务端接收到一个包,从整个数据包里边解析出一个五元组,从而构建出一个节点叫tcb,这个时候会把它加入到一个队列里边,叫半连接队列,也叫syn队列
第三次握手,服务端收到的数据,先查找半连接队列,如何去查找呢,通过五元组查找
半连接与全连接建立的前提是,先进入listen的状态,半连接队列里边所有tcb的状态是SYN RCVD的状态
全连接队列的时候,连接已经建立完了,然后调用accept生成clientfd
listen(fd,backlog);backlog指的是没有分配clientfd的tcb的总数,也就是半连接与全连接队列的长度之和,还有一种理解,全连接队列有多长,backlog就有多长。
服务器的端口有65535,如何做到百万级别的连接的呢
端口复用,fd—>tcb,通过五元组区分,五元组决定一个tcb,一个连接一个tcb。

数据发送

send与recv
send把应用空间的数据拷贝到协议栈里边去,拷贝到sendbuff里边去,然后协议栈加上tcp的头,以及各种协议的头,然后发送出去
recv,将接收的数据从内核协议栈的recvbuff,发送给应用层app
recvbuf在接收数据的时候,发送数据,有个push的标志位,置为1会通知对方来读
关于send发送的数据,要考虑粘包与分包的问题
有两种方式,在协议头加上这个包有多长,以及在包之间发分隔符,这两个方法能成功,有一个条件就是包是顺序的
Posix API与网络协议栈_第3张图片
那么tcp如何保证顺序的,顺序就是先发先到
有一个概念叫延迟ack,数据包是确定的,我们发10个包,第一个发过来,每隔发一个包,启动一个延时定时器,比如200ms,200ms之内发送完后,发一个包重置定时器。
如果200ms到了还没发出去,产生超时,对方没收到怎么回ack,就回4,意思就是在4以前,不包含4,以前的1,2,3都收到了,4进行重发
这个延迟ack的方式是在什么地方呢,在tcp的协议栈中做的
Posix API与网络协议栈_第4张图片

connect

我们再来说说,connect的函数,到底要不要等呢,是要等三次握手完成之后呢,还是说不要等,它等不等取决于刚开始创建的socket,有没有设置为阻塞的。socket创建的时候,就已经把fd与tcb就已经创建好了
Posix API与网络协议栈_第5张图片
fcntl();做了什么呢,跟协议栈没半毛钱关系,只跟fd有关系,设置fd的属性比如阻塞与非阻塞,是文件系统这一层。

udp

tcp都做的这么好了,为啥还要udp呢
tcp在弱网的环境下,大量的数据传输,是不合适的,因为丢包的时候,也会有大量的包进行重传。也无法保证实时性
udp的实用场景,比如说游戏,还有迅雷,百度网盘的下载速度限制

断开连接的过程

应用层这边只有一个函数close();
调用close这个函数的时候,会给内核协议栈发一个fin位,使得fin位置1,然后把fin包发输出去,然后接收方也会让recv函数返回0,然后准备一个ack的包发回去
接收方也调用close函数,跟发送方一样,发一个fin包,最后接收到发送方的ack,最后老死不相往来,双方都进入time_wait,tcb被回收。

发送方 接收方
Posix API与网络协议栈_第6张图片那么有没有那种情况呢,两边同时调用close,都发送了fin出去,这样就进入了一个closing状态,这种有,但是情况比较少。如果这样出现大量的time_wait,设置重用,设置reused,下一次再一次建立连接的时候,这个tcb还会拿出来使用。time_wait出现的原因是避免ack传输的丢失,双方会陷入一个死锁的状态,time_wait的时间是120s
Posix API与网络协议栈_第7张图片

进入fin_wait1后就会进入fin_wait2状态,接收方那边的内核也会进入close_wait状态
如果服务器出现了大量的close_wait状态,也就是接收方没有调用close,也可能使用业务逻辑问题,在代码中也就是recv=0的返回到close的过程太远,解决办法有,要么先调用close,要么就把期间业务抛到一个消息队列里边,让线程池去处理。
Posix API与网络协议栈_第8张图片
还有一个问题就是,比如在http的请求中,请求一个第三方的业务,这里出现了一个现象,出现了一个fin_wait2,并且一直卡在这里,怎么办呢
通过何种方法去脱离fin_wait2的状态
只有再等两分钟,服务器那边没有响应的时候,fin_wait2这一段会终止掉
Posix API与网络协议栈_第9张图片

你可能感兴趣的:(进阶知识,c语言,c++,后端,网络协议)