Linux内核源代码解析之——sock's buffer参数

本文原创为freas_1990,转载请标明出处:http://blog.csdn.net/freas_1990/article/details/11539695

关于socket与sock的关系再简单说一下。

socket是面向文件与API的,拿来给application程序员fuck。

而sock是面向数据包的,用来发送用户的数据和接收网卡传到内核的数据。

我们再看一下sock的结构体定义。

struct sock {

...
volatile unsigned long wmem_alloc;
volatile unsigned long rmem_alloc; ...
unsigned short rcvbuf;
unsigned short sndbuf; ...
};

注意,这里的rcvbuf和sendbuf不是缓冲区,而只是一个可调整的参数。通过setsocketopt()可以这两个参数进行调整。

其中的wmem_alloc和rmem_alloc是动态变化的,实时记录了当前sock获取了多少rcvbuf。

那为什么需要设置wmem_alloc这样的一个值呢?

在计算机的内存管理里,有这样的一个技术——用一个值来记录当前(server)使用了多少内存,所有的内存分配,释放会记录到这个变量里,以做到对内存的实时反馈。

在Linux内核里,在redis里也有,相信在很多别的server代码里也会有。

如果不使用这样的变量会出现什么样的问题呢?

这个问题我暂时不给出答案,大家可以思考一下。

那什么时候这几个变量会起作用呢?

我们来看一下下面的代码。

struct sk_buff *
sock_wmalloc(struct sock *sk, unsigned long size, int force,
int priority)
{
if (sk) {
if (sk->wmem_alloc + size < sk->sndbuf || force) {
struct sk_buff * c = alloc_skb(size, priority);
if (c) {
cli();
sk->wmem_alloc+= size;
sti();
}
return c;
}
DPRINTF((DBG_INET, "sock_wmalloc(%X,%d,%d,%d) returning NULL\n",
sk, size, force, priority));
return(NULL);
}
return(alloc_skb(size, priority));
}

当我们发送一个数据包的时候,会调用sock_wmalloc函数,这个函数会把当前sock已经分配的内存(wmem_alloc)和马上会分配的数据包内存相加后与sndbuf比较,如果大于sndbuf的话,就不能发送这个包。
从这里,可以看出来,sndbuf其实只是一个参数,它是可以动态调整,也是可以忽视的(如果force参数被设置了)。

那这两个参数是何时被初始化的呢?

来看一下如下代码

static int
inet_create(struct socket *sock, int protocol)
{
struct sock *sk;
struct proto *prot;
int err; sk = (struct sock *) kmalloc(sizeof(*sk), GFP_KERNEL);
...
  sk->sndbuf = SK_WMEM_MAX;
sk->rcvbuf = SK_RMEM_MAX;
...
  if (sk->prot->init) {
err = sk->prot->init(sk);
if (err != 0) {
destroy_sock(sk);
return(err);
}
}
return(0);
}

我们再来看一下,setsocketopt是如何修改这个参数的。

/*  * This is meant for all protocols to use and covers goings on  * at the socket level. Everything here is generic.  */

int sock_setsockopt(struct sock *sk, int level, int optname,   char *optval, int optlen) {  int val;  int err; ...   case SO_SNDBUF:    if(val>32767)     val=32767;    if(val<256)     val=256;    sk->sndbuf=val;    return 0; ...   case SO_RCVBUF:    if(val>32767)     val=32767;    if(val<256)     val=256;    sk->rcvbuf=val;    return(0); ...   default:      return(-ENOPROTOOPT);    } }

那sock里的skb数据结构是如何控制的呢?

那一张漂亮的图是如何画出来的呢?

上一篇:【Linux】分割命令split


下一篇:Linux内核源代码解析之TCP面向字节流