Chinaunix首页 | 论坛 | 博客
  • 博客访问: 33016
  • 博文数量: 21
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 205
  • 用 户 组: 普通用户
  • 注册时间: 2017-01-22 19:18
文章分类
文章存档

2017年(21)

我的朋友

分类: 嵌入式

2017-02-06 15:00:37

 

TCP运行过程

tcp的运行过程是怎样的?用户如何使用它?

tcp协议栈移植完成后,就像一个不停运转的摩天轮。用户要使用它,只需在它的每个舱体内装上游客即可。

每个舱体相当于一个pcb。新建一个pcb就相当于新建一个舱体。让男女游客进仓,相当于为tcp->recv,tcp->poll等注册对应的回调函数。

下面讨论一个pcb从创建到销毁,在它身上发生了什么?
 

应用层接口

tcp状态迁移相关链表

tcp_input(),负责查询pcb所属的状态链表,并分流

tcp_input(struct pbuf *p, struct netif *inp)详解。                                                       

1) 参数p:指向ip报文头;参数inp:接收的网口                                                  

2) 处理流程

a. 数据包有效性检测,丢弃过短的数据包(ip报文、tcp段都有最小的长度);丢弃广播、多播包;丢弃校验出错的数据包。                                                       

b. 遍历tcp_active_pcbs链表,检查是否包含接收段所对应的pcb。若包含,继续后续处理。

c. 遍历tcp_tw_pcbs链表,检查是否包含接收段所对应的pcb。若包含,则调用tcp_timewait_input()重发ACK。后退出。                                                       

d. 遍历tcp_listen_pcbs链表,检查是否包含接收段所对应的pcb。若包含,则调用tcp_listen_input()。先检查下flag,看是否是连接请求(SYN置位)。若是,创建一个新的pcb,设置相关参数,然后将其放入tcp_active_pcbs链表。                                                       

    另外原有的tcp_listen_pcbs链表仍有lpcb。服务器时刻处于侦听状态,以接收来自多个ip的连接请求。后退出。                                                    

e. 若是处于tcp_bound_pcbstcp_active_pcbs链表的pcb收到了数据,则会调用tcp_process()进一步处理接收的数据。                                                

f. 检查该pcb接收段的recv_flags(在tcp_process()中设置,根据pcb的当前状态和接收tcp段头的相关标志进行)。                                                       

    TF_RESET 收到的tcp段头TCP_RST被置位。该连接被远端强行断开(远端调用tcp_abort())。所以此时也只能将该pcbtcp_active_pcbs链表中删除,并释放该pcb相关资源。                                                   

    TF_CLOSED pcb处于LAST_ACK状态,并收到ack确认时。说明连接正常断开,将该pcbtcp_active_pcbs链表中删除,并释放该pcb相关资源。                                                   

    TF_GOT_FIN 收到的tcp段头TCP_FIN被置位。即收到远端断开的请求。在e步骤的tcp_process()中,已经立即返了一个ACK。此处调用TCP_EVENT_RECV()以通知应用层收到了FIN请求,要进行断开连接处理。                                                 

      (通知应用层时,数据为NULL,即表示收到FIN请求。

TCP状态迁移

tcp_process()处理clientserverpcbtcp状态机的迁移。

拥塞处理

 tcp_receive()处理接收报文中相关字段,主要做两件事:     

1a. 根据ackno确定是否重传,更新拥塞窗口。

          b. 分析ackno与发送窗口的关系,更新unackedunsent链表。

2a. 根据seqno+len与接收窗口的关系,看接收报文中哪些数据该保留,哪些该丢弃。

          b. 该保留的先放入乱序链表ooseq,看能否凑成更大的连续段;然后将连续段放入recv_data中,等待应用程序处理。

TCP数据发送

tcp_out主要有两个函数:

1. tcp_enqueue():将应用层的整个数据包拆分成段。按序放入pcb->unsent队列。

2. tcp_out() :从pcb->unsent队列取出要发送的段,调用tcp_out_segment()将特定的段发送出去。

阅读(5618) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~