posxi api与网络协议栈实现原理

对于网络编程的api只是固定的函数如下:
客户端: socket/bind/connect/send/recv/close
服务器: socket/bind/listen/accept/recv/send/close
epoll接口: epoll_create/epoll_ctl/epoll_wait
不常用:setsockopt/getsockopt/fnctl/shotdown

Tcp主要分为三个阶段:
1 建立连接(三次握手)
2 数据传输
3 断开连接(四次挥手)

1 建立连接

发送端发生在connect函数之后,对于服务器是发生在网络协议栈。
三次握手流程:
在这里插入图片描述
第一次:建立端向服务器主动发送一个建立连接请求包(设置syn=1,seq=x);tcp帧协议规定syn=1表述发送的包无数据;seq主动请求端会自己生成一个随机的初始序列号x(用来做顺序传输)。
第二次:服务器接收到主动请求端的建立请求包后,会在网络协议栈的半连接队列中创建一个结点(tcb控制块),并且回一个包ack=x+1给客户端(也会设置自己的初始序列号y)。
第三次:建立端收到被动建立端的应答包后,将自己的状态设置为establed状态,并再次发送一个包告诉服务器,我已可以传输了,服务器收到后,从半连接队列中移动一个结点到全连接队列。三次连接完成。服务器就会分配一个fd进行传输。
三次握手:建立端发生在connect函数,被动建立端是被动实现的。
问题:
1 第三次客户端发送确认包后,服务器怎么能从半连接队列中找到对应的结点,放到全连接队列?
tcp头包含五元组(sip,dip,sport,dport,proto)
2 此结点生命周期多长,何时释放?
close()后释放。
3 端口只有65535个?为何能做百万服务器?
五元组(sip,dip,sport,dport,proto)

Tcp协议头:
在这里插入图片描述

connect函数:客户端发送connect函数时,会将ip和端口copy到网络协议栈,网络协议栈组一个包将syn=1,seq=x设置,然后发送给服务器。
listen函数:服务器调用后,内核会在网络协议栈中创建两个队列(半连接队列和全连接队列)
accept函数:从全连接队列中获取一个结点,然后分配一个fd与结点一一对应,并返回fd。若全连接队列中午结点,则是条件等待。若设置fcntl为非阻塞后,全连接队列无结点则直接返回。

结点(tcb控制块):tcp的11种状态,sendbuff/recvbuff,fd–五元组都是存在这里面。

2 数据传输

tcp如何保证顺序(先发先到)?
正常的发送数据,是客户端发送一个服务器收到后发送一个确认包,客户端收到确认包在发送。这样数据传输太慢。tcp做法是在一段时间能不需要确认。具体流程:
在这里插入图片描述
公网上传输,无法保证先发的先到。比如客户端发送了1,2,3,4服务器接收到的可能是124或者2134等乱序的。tcp如何保证顺序的呢?
超时重传:服务器每接收一个包,网络协议栈就会启动一个200ms的定时器,接收到后就重置定时器,一旦超时则检测收到包的顺序看看那个包没有收到。若3没有收到,则从3之后的包全部进行重传(例如4提前接收到了也重传)
慢启动:主要用来确认发送端什么情况下发几个包用的?如何计算?
刚刚开始发送的时候,初始值较少。第一次发送1个包,第二次发送2个,第三次发送4个,第四次发送8个。。。具体的发送的过程如下图:
在这里插入图片描述
tcp刚刚建立时候,包的数据指数级的增长,当达到门限值16时候,就降一半成线性增长;对于指数级增加这个过程叫慢启动,对于超过门限值后降一半成指数级增长叫拥塞控制
针对数据传输过程:
在这里插入图片描述

3 断开连接

断开的主要有两个
close()
shutdown() 关闭单方向。
四次挥手过程:
在这里插入图片描述
第一次:主动断开方发送断开请求发送FIN=1设置的包给被动方,主动方进入终止等待1阶段;
第二次:当接收方收到主动断开的请求,回一个应答包,并且进入close_wait关闭等待状态。
第三次:过一段时间后被动方再发送一个确认包,被动方进入最后确认状态
第四次:主动发会回一个最后确认包。主动方进入TIME_WAIT状态。等待2msl时间关闭。被动方收到包后就直接关闭。

问题:
1 大量Time_wait,产生原因?解决方案?
主动方调用close端菜会有time_wait状态,若服务器出现大量的time_wait是,则可能是服务器代码主动调用了close导致的。
解决方案:1 这是一种不正常的逻辑,查逻辑bug 2: 若代码逻辑正常,则可用setsockopt()函数设置为reuse重用状态,只是一定程度的减少

2 大量Close_wait,产生原因?解决方案?
主要是对端调用close时间不合适,本端在recv==0内调用close没有调用成功,或者是有延迟阻塞的情况导致的。
解决方案:可将业务交给另外一个线程异步处理。

3 大量Fin_wait1,Fin_wait2,产生原因,解决方案?
原因:close没有调用或者延迟调用close()
fin_wait2无法通过程序释放,只能通过kill,os系统回收

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

丰恒谷

你的鼓励是我最大创作动力!!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值