Linux 传输层实现
来源:互联网 发布:林丹 知乎 编辑:程序博客网 时间:2024/05/16 05:24
====================================进入传输层(TCP)==============================
tcp_v4_rcv(skb)
{
不是发给本机的报文则丢弃;
取TCP头,检查头部长度,取出完整TCP头,校验;因为每层头部包含选项,所以长度不固定,需要这么多步骤来取完整头。
根据TCP头来设置skb->cb[]控制块中的值;
根据五元组查找struct sock *sk,没找到则goto no_tcp_socket;ehash/bhash
process:
如果套接口处于TIME_WAIT,则goto do_time_wait;
防火墙过滤,失败则goto discard_and_relse;
skb->dev = NULL;传输层不关心接收报文的dev;
如果进程没有在访问struct sock *sk,则调用tcp_v4_do_rcv正常接收;否则,将报文添加到后备队列;?????????????
no_tcp_socket:
给对方发送RST报文;
discard_it:
kfree_skb(skb);
do_time_wait:?????????
调用tcp_timewait_state_process(),如果收到连接请求,重新处理报文;如果收到FIN,需要向对方发送ACK;如果收到无效段,需要向对方发送RST;
}
tcp_v4_do_rcv(sk,skb)
{
如果sk已建立sk->sk_state==TCP_ESTABLISHED,调用tcp_rcv_established()快速路径处理报文,处理失败的话给对端发送RST;
如果sk处于监听状态sk->sk_state==TCP_LISTEN,调用tcp_v4_hnd_req()处理半连接ACK报文;
如果半连接已经建立(nsk!=sk),调用tcp_child_process(sk,nsk,skb)初始化子传输控制块,如果失败则向客户端发送rst段,成功则返回;??????????
如果sk处于其他状态(SYN_RECV/SYN_SENT/FIN_WAIT1/FIN_WAIT2/LAST_ACK/CLOSING),调用tcp_rcv_state_process()处理状态(包括建立连接的函数tcp_v4_conn_request),失败的话向对方发送RST;?????????
对于所有发送RST的情况,都要随后kfree_skb(skb)。
}
tcp_rcv_established(sk,skb,struct tcphdr *th,len) //establish状态,处理接收到的报文
{
如果段满足条件(正好是预期的段序号)
{//快速路径
如果该段没有payload
{//没有payload的段??????
tcp_store_ts_recent()保存时间戳;?????????
tcp_rcv_rtt_measure_ts(tb,skb)采样RTT;??????????
tcp_ack(sk,skb,0) 处理ACK???????
tcp_data_snd_check(sk);/* 检测是否有数据需要发送给对方,同时检测是否有必要增加发送缓冲区大小 */
return 0;
}
否则
{//有payload??
如果该段满足一系列条件,可以直接复制到用户空间:
调用tcp_copy_to_iovec()将段复制给用户空间;更新时间戳;更新往返时间;更新下一个预期的段序号;
如果复制给用户失败,或者没有复制给用户:
检验校验和;更新时间戳;将数据包添加到接收队列(sk->sk_receive_queue)缓存,等用户进程来读取;设置预期段序号;
调用tcp_event_data_recv(),处理接收到段之后应该触发的事件,如设置发送确认状态,估算MSS,计算RTT,快速确认还是慢速确认?????
调用tcp_send_ack()快速确认或者调用tcp_send_delayed_ack()慢速确认;
如果数据已经传给用户空间,则释放skb,否则说明数据已经就绪,唤醒等待队列进程sk->sk_data_ready(sk, 0);通知他们读取数据;??????how?阻塞?非阻塞?
}
}
slow_path://慢速路径,慢速接收
解析TCP选项,失败的话,如果不是RST段,则需要向对方发送DACK tcp_send_dupack(),说明收到的段不在接收窗口内;
如果有RST字段,调用tcp_reset()关闭sk;
如果报文有效,且有SYN字段,说明对方发送了错误的段,同样调用tcp_reset()关闭sk;
step5:
处理ack,更新采样RTT;处理带外数据;
调用tcp_data_queue(sk,skb)慢速处理段中的数据;????????????????
检查是否有数据需要发送;
检查是否有ACK需要发送;
返回;
}
tcp_data_queue()
{//慢速处理段中的数据,此函数很长
如果可以复制到用户空间,则复制到用户空间,更新用户空间缓存,更新接收缓存、接收窗口。如果复制到用户空间成功,则释放报文;
如果没有复制到用户空间,则缓存到接收队列,如果接收队列缓存不足,则丢弃;
如果接收成功,更新下一个预期段序号;
如果没有复制到用户空间,则调用sk->sk_data_ready(sk,0);唤醒等待接收的用户进程;
如果不是预期段,释放skb并退出;
如果段序号太大,释放skb并退出;
如果接收窗口为0,丢弃;
对于乱序的段,加入tp->out_of_order_queue乱序队列,并处理乱序队列(SACK/DSACK)??????????
}
=========================进入传输层(UDP)===================================
udp_rcv(skb)
{
检查UDP报头、校验和;
根据四元组查找所属传输控制块struct sock sk;如果找到,调用udp_queue_rcv_skb(sk,skb)将UDP数据包添加到所属sk的接收队列;
如果找不到sk,检查IPSEC、校验和,如果有问题,就把skb给释放了,否则向对方发送ICMP表示报文不可达;
}
udp_queue_rcv_skb(sk,skb)
{
安全性检查;
通过检查之后调用sock_queue_rcv_skb(sk,skb);将接收到的数据报添加到传输控制块的接收队列;
}
sock_queue_rcv_skb(sk,skb)
{
检查接收缓存大小释放已经达到接收缓冲区上限;
过滤器过滤报文;
skb->dev=NULL;到达传输层,不关注设备
skb_queue_tail(sk->sk_receive_queue,skb)将报文添加到接收队列尾部;
如果套接口sk没关闭,则唤醒等待的进程sk->sk_data_ready(sk, skb_len);sk_data_ready = sock_def_readable
}
============================================================================
- Linux 传输层实现
- 传输层实现
- Linux内核--网络栈实现分析(五)--传输层之UDP协议(上)
- Linux内核--网络栈实现分析(九)--传输层之UDP协议(下)
- Linux内核--网络栈实现分析(五)--传输层之UDP协议(上)
- Linux内核--网络栈实现分析(九)--传输层之UDP协议(下)
- Linux内核--网络栈实现分析(五)--传输层之UDP协议(上)
- Linux内核--网络栈实现分析(九)--传输层之UDP协议(下)
- SUN RPC的传输层实现机制
- 传输层
- 传输层
- 传输层
- 传输层
- 传输层
- 传输层
- 传输层
- 传输层
- 传输层
- mac搭建java web,android studio环境
- 定时任务
- 内部类
- 关于mybatis返回单一对象或对象列表的问题
- 应该算是点笔记吧
- Linux 传输层实现
- MFC弹出对话框之前先进行条件判断以决定是否弹出对话框
- 关于类的总结之二
- React-Native移植-Android
- [bash shell] how to calculate float times float
- 决策树—ID3
- HDU 1004 Toxophily
- java.util包---LinkedHashSet
- iOS开发之 协议 protocol