12.4.5套接字缓冲区的上层支持例程

我们上面讲了套接字缓冲区基本的操作方法,利用它们就可以完成数据包的发送和接收工作。为了保证网络传输的高效和稳定,我们需要对整个过程进行流程控制,因此,我们又引进了两个支持例程。它们是利用信号的交互来完成任务的。

 

sock_queue_rcv_skb()函数用来对数据的接收进行控制,通常调用它的形式为:

        sk=my_find_socket(whatever);

        if(sock_queue_rcv_skb(sk,skb)==-1)

        {

       myproto_stats.dropped++;

       kfree_skb(skb,FREE_READ);

       return;

         }

它利用套接字的读队列的计数器,从而避免了大量的数据包堆积在套接字层。一旦到达这个极限,其余的数据包就会被丢弃。这样做是为了保障高层的应用协议有足够快的读取速度,比如TCP协议,包含对该流程的控制,当接收端不能再接收数据时,TCP 协议就告诉发送端的机器停止传输。

 

在数据传输方面, sock_alloc_send_skb() 可以对发送队列进行控制,  我们不能把所有的缓冲区都填充数据,使得发送队列总有空余, 避免了数据堵塞。这个函数在具体应用时有很多微妙之处,所以推荐编写网络协议的作者尽可能使用它。

许多发送例程利用这个函数几乎可以做所有的工作:

 

   skb=sock_alloc_send_skb(sk,....)

   if(skb==NULL)

       return -err;

   skb->sk=sk;

   skb_reserve(skb, headroom);

   skb_put(skb,len);

   memcpy(skb->data, data, len);

   protocol_do_something(skb);

上面大部分代码我们前面已经见过。其中最重要的一句是 skb->sk=sksock_alloc_send_skb() 负责把缓冲区送到套接字层。通过设置 skb->sk, 我们告诉内核无论哪个例程对缓冲区进行 kfree_skb()处理,都必须保证缓冲区已经成功地送到套接字层。 因此一旦网络设备驱动程序发送一个缓冲区, 并将之释放,我们就认为数据已经发送成功,这样我们就可以继续发送数据了。在源代码中我们看到 kfree_skb 操作执行就会触发sock_alloc_send_skb()