linux2.6协议栈源码分析,Linux2.6内核协议栈系列--TCP协议2.接收(示例代码)

本文详细介绍了TCP报文的处理流程与排队机制。包括TCP报文如何通过不同的队列进行管理,如待处理队列、预排队队列和接收队列;深入探讨了tcp_v4_rcv()函数如何处理报文以及tcp_rcv_established()函数如何处理已建立连接的报文。同时,还讲解了如何将数据直接复制到用户缓冲区或排队等待处理。
摘要由CSDN通过智能技术生成

1.排队机制

接收输入TCP报文时,有三个队列:

● 待处理队列

● 预排队队列

● 接收队列

接收队列包含了处理过的TCP数据段,也就是说,去除了全部的协议头,正准备将数据复制到用户应用程序。接收队列包含了所有按顺序接收的数据段,在其他两个队列中的TCP数据段则需要进一步处理。

TCP报文首先由tcp_v4_rcv()进行处理。该函数要决定是否需要处理报文或者在待处理队列和预排队队列中排队。

/* 传输层报文处理入口 */

int tcp_v4_rcv(struct sk_buff *skb)

{

...

/*首先获取一个套接字旋转锁,当进入该例程时,要禁用下半部功能,因为该

例程是从NET SoftIRQ中断调用的。*/

bh_lock_sock(sk);/* 在软中断中对套接口加锁 */

ret = 0;

/* 如果进程没有访问传输控制块,则进行正常接收 */

/*接着检查套接字是否处于使用状态。当有人在使用该套接字时,(sk)->sk_lock.owner

为1.当对套接字执行读、写、修改操作时,套接字就会处于使用状态。*/

if (!sock_owned_by_user(sk)) {

/*调用tcp_prequeue将该TCP报文发往预排队队列。*/

if (!tcp_prequeue(sk, skb))

/*如果无法将TCP排队,就直接处理该数据段。*/

ret = tcp_v4_do_rcv(sk, skb);

} else

/* 将报文添加到后备队列中,待用户进程解锁控制块时处理 */

sk_add_backlog(sk, skb);

bh_unlock_sock(sk);

...

}

2.tcp_rcv_established()的处理

这里不介绍全部处理细节,仅介绍处理和排队机制。首先讨论直接将数据复制到用户缓冲区的可能性。如果不可能,就去除TCP头,将数据段发往接收队列排队。

/* 当连接已经正常建立时,处理接收到的TCP报文 */

int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,

struct tcphdr *th, unsigned len)

{

struct tcp_sock *tp = tcp_sk(sk);

...

}

else {/* 有数据负荷 */

int eaten = 0;

/* 判断正在接收的段是否可以直接复制到用户空间 */

/* 正在接收的段的序号是否与尚未从内核空间复制到用户空间的段最

前面的序号相等,即接收队列应当是空的 */

/* TCP段中的用户数据长度小于用户空间缓存的剩余可用量 */

if (tp->ucopy.task == current &&

tp->copied_seq == tp->rcv_nxt &&

len - tcp_header_len <= tp->ucopy.len &&

sock_owned_by_user(sk)) {/* 锁被当前进程持有 */

__set_current_state(TASK_RUNNING);

/* 将SKB的数据复制到用户缓冲区 */

if (!tcp_copy_to_iovec(sk, skb, tcp_header_len)) {

if (tcp_header_len ==

(sizeof(struct tcphdr) +

TCPOLEN_TSTAMP_ALIGNED) &&

tp->rcv_nxt == tp->rcv_wup)/* 更新时间戳 */

tcp_store_ts_recent(tp);

tcp_rcv_rtt_measure_ts(tp, skb);/* 更新往返时间 */

__skb_pull(skb, tcp_header_len);

/* 下一个预期接收的段序号 */

/*将tp->rcv_nxt更新为已处理报文的结束序列号。*/

tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;

NET_INC_STATS_BH(LINUX_MIB_TCPHPHITSTOUSER);

eaten = 1;

}

}

if (!eaten) {

...

/* 移动指针,跳过TCP头部,也就是去除TCP头 */

__skb_pull(skb,tcp_header_len);

/* 将数据包添加到接收队列中缓存起来,等待进程主动读取 */

__skb_queue_tail(&sk->sk_receive_queue, skb);

/* 设置skb的属主为当前套口,更新使用的接收缓存总量及预分配缓存长度 */

sk_stream_set_owner_r(skb, sk);

/* 更新rcv_nxt为该分段的结束序列号 */

tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;

}

...

return 0;

}

3.

内容太多了,未完待续

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值