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数据结构是如何控制的呢?

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

 

 

 

 

 

posted @ 2013-09-11 20:16  pangbangb  阅读(871)  评论(0编辑  收藏  举报