送字节序号
snd_wnd, // 发送窗口 snd_wl1, snd_wl2, // 上次窗口更新时的数据序号和确认序号
snd_lbb; // 发送队列中最后一个字节的序号 u16_t acked; //
u16_t snd_buf; // 可用的发送缓冲字节数 u8_t snd_queuelen; // 可用的发送包数
struct tcp_seg *unsent; // ?发送的数据段队列
struct tcp_seg *unacked; // 发送了?收到确认的数据队列
struct tcp_seg *ooseq; // 接收到序列以外的数据包队列
#if LWIP_CALLBACK_API // 回调函数,部分函数在较低版?没定义
err_t (* sent)(void *arg, struct tcp_pcb *pcb, u16_t space);
err_t (* recv)(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err); // 数据包接收回调函数
err_t (* connected)(void *arg, struct tcp_pcb *pcb, err_t err);
err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err);
err_t (* poll)(void *arg, struct tcp_pcb *pcb); void (* errf)(void *arg, err_t err); #endif /* LWIP_CALLBACK_API */
// 剩下的所有字段在较低版?中均?定义,用到时再讲解 u32_t keep_idle; #if LWIP_TCP_KEEPALIVE
u32_t keep_intvl; // 保活定时器,用于检测空闲连接的另一端是否崩溃 u32_t keep_cnt;
#endif /* LWIP_TCP_KEEPALIVE */
u32_t persist_cnt; // 这两个字段可以使窗口大小信息保持不断流动 u8_t persist_backoff; u8_t keep_cnt_sent;
};
17 TCP建立流程
函数会初始化新的tcp_pcb 的内容,源 码如下: if (pcb != NULL) {
memset(pcb, 0, sizeof(struct tcp_pcb)); // 清0所有字段的值
pcb->prio = TCP_PRIO_NORMAL; // 设置PCB的优先级为64,优先级在1~127之间
pcb->snd_buf = TCP_SND_BUF; // TCP 发送数据缓冲区剩余大小
pcb->snd_queuelen = 0; // 发送缓冲中的数据包pbuf个数
pcb->rcv_wnd = TCP_WND; // 接收窗口大小 pcb->rcv_ann_wnd = TCP_WND; // 通告窗口大小 pcb->tos = 0; // IP 报头部TOS字段 pcb->ttl = TCP_TTL; // IP 报头部TTL字段
pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS; // 设置最大段大小,不能超过536字节
pcb->rto = 3000 / TCP_SLOW_INTERVAL;// 初始超时时间值,为6s
pcb->sa = 0; // 估计出的RTT平均值?? pcb->sv = 3000 / TCP_SLOW_INTERVAL; // 估计出的RTT方差??
pcb->rtime = -1; //重传定时器,当该值大于rto时则重传发生
pcb->cwnd = 1; // 阻塞窗口
iss = tcp_next_iss(); // iss 为一个临时变量,保存该连接的初始数据序列号
pcb->snd_wl2 = iss; // 上一个窗口更新时收到的ACK号
pcb->snd_nxt = iss; // 下一个将要发送的数据编号
pcb->snd_max = iss; // 发送了的最大数据编号 pcb->lastack = iss; // 上一个ACK编号 pcb->snd_lbb = iss; // 下一个将要缓冲的数据编号
pcb->tmr = tcp_ticks; // tcp_ticks是一个全局变量,记录了当前协议时钟滴答
pcb->polltmr = 0; // ?解??? #if LWIP_CALLBACK_API
pcb->recv = tcp_recv_null; // 注册默认的接收回调函数
#endif /* LWIP_CALLBACK_API */ pcb->keep_idle = TCP_KEEPIDLE_DEFAULT;
#if LWIP_TCP_KEEPALIVE //保活定时器相关设置。。?解??
E-mail:for_rest@foxmail.com 老衲五木出品
pcb->keep_intvl = TCP_KEEPINTVL_DEFAULT; pcb->keep_cnt = TCP_KEEPCNT_DEFAULT; #endif
pcb->keep_cnt_sent = 0;
}
服务器端需进入LISTEN状态等待客户端的连接等待客户端发送来的SYN数据包进行连接了ip_input函数会判断IP包头部的协议字段,并把TCP数数据包通过tcp_input 函数传递到TCP层
新建一个tcp_pcb结构,并将相应tcp_pcb_listen结构拷贝至其中,同时在tcp_active_pcbs 链表中添加这个新的tcp_pcb结构。这样新的TCP控制块就处在tcp_active_pcbs 中了
它应该从收到的SYN数据报中提取TCP头部中选项字段的值,