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

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

  • 相关阅读:
    RBO基于规则的优化器access paths优先级
    脚本:监控临时表空间使用率
    脚本:格式化的V$SQL_SHARED_CURSOR报告
    脚本:监控并行进程状态
    Oracle内部错误:ORA00600[25012]一例
    Trace obtained enqueue information by set event 10704
    Script:Translate RDBA relative data block address
    [Repost]List of X$ Tables
    Oracle学习笔记:oem手工管理
    Oracle学习笔记:redo重做日志
  • 原文地址:https://www.cnblogs.com/pangblog/p/3315469.html
Copyright © 2020-2023  润新知