Socket緩沖區大小修改與系統設置


每個Socket在Linux中都映射為一個文件,並與內核中兩個緩沖區(讀緩沖區、寫緩沖區)相關聯。

或者說,每個Socket擁有兩個內核緩沖區。

有時,我們需要修改緩沖區的內核限制的最大值,使其符合我們的實際需求。

一、系統設置

復制代碼

[jiang@localhost ~]$ uname -a
Linux localhost.localdomain 2.6.32-642.el6.x86_64 #1 SMP Tue May 10 17:27:01 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
[jiang@localhost ~]$ cat /proc/sys/net/core/rmem_max
124928
[jiang@localhost ~]$ cat /proc/sys/net/core/wmem_max
124928
[jiang@localhost ~]$ cat /proc/sys/net/core/rmem_default
124928
[jiang@localhost ~]$ cat /proc/sys/net/core/wmem_default
124928

復制代碼

 

rmem_max:一個Socket的讀緩沖區可由程序設置的最大值,單位字節;
wmem_max:一個Socket的寫緩沖區可由程序設置的最大值,單位字節;
rmem_default:一個Socket的被創建出來時,默認的讀緩沖區大小,單位字節;
wmem_default:一個Socket的被創建出來時,默認的寫緩沖區大小,單位字節;

注:/proc是一個很特殊的文件系統,其並非真實存在於物理磁盤,而是當前系統運行狀態的一個映射,存在於RAM中。

二、應用程序級修改緩沖區大小

我們可以在程序中動態地修改(通過setsockopt系統調用)持有的有效Socket的讀寫緩沖區大小。

復制代碼

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>

int main(int argc, char **argv)
{
     if (argc != 2)
     {
         printf("Usage: %s $RCFBUFSIZE\n", argv[0]);
         goto error;
     }

    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
     if (sockfd < 0)
     {
         printf("create socket error=%d(%s)!!!\n", errno, strerror(errno));
         goto error;
     }

    // 查看系統默認的socket接收緩沖區大小
     int defRcvBufSize = -1;
     socklen_t optlen = sizeof(defRcvBufSize);
     if (getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &defRcvBufSize, &optlen) < 0)
     {
         printf("getsockopt error=%d(%s)!!!\n", errno, strerror(errno));
         goto error;
     }
     printf("OS default udp socket recv buff size is: %d\n", defRcvBufSize);

    // 按照執行參數設置UDP SOCKET接收緩沖區大小
     int rcvBufSize = atoi(argv[1]);
     if (rcvBufSize <= 0)
     {
         printf("rcvBufSize(%d) <= 0, error!!!\n", rcvBufSize);
         goto error;
     }
     printf("you want to set udp socket recv buff size to %d\n", rcvBufSize);
     optlen = sizeof(rcvBufSize);
     if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &rcvBufSize, optlen) < 0)
     {
         printf("setsockopt error=%d(%s)!!!\n", errno, strerror(errno));
         goto error;
     }
     printf("set udp socket(%d) recv buff size to %d OK!!!\n", sockfd, rcvBufSize);

    // 查看當前UDP SOCKET接收緩沖區大小
     int curRcvBufSize = -1;
     optlen = sizeof(curRcvBufSize);
     if (getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &curRcvBufSize, &optlen) < 0)
     {
         printf("getsockopt error=%d(%s)!!!\n", errno, strerror(errno));
         goto error;
     }
     printf("OS current udp socket(%d) recv buff size is: %d\n", curRcvBufSize);

    close(sockfd);

    exit(0);

error:
     if (sockfd >= 0)
         close(sockfd);
     exit(1);
}

復制代碼

編譯 && 運行:

[jiang@localhost ~]$ gcc -o main main.c
[jiang@localhost ~]$ ./main 1024
OS default udp socket recv buff size is: 124928
you want to set udp socket recv buff size to 1024
set udp socket(3) recv buff size to 1024 OK!!!
OS current udp socket(2280) recv buff size is: 2280

我們通過setsockopt系統調用成功地修改了sock的接收緩沖區大小。

但是,代碼級的修改緩沖區大小,不是萬能的,其受限於系統配置。

[jiang@localhost ~]$ ./main 1048576
OS default udp socket recv buff size is: 124928
you want to set udp socket recv buff size to 1048576
set udp socket(3) recv buff size to 1048576 OK!!!
OS current udp socket(249856) recv buff size is: 249856

可見,我們希望設置接收緩沖區大小為1024*1024B(1MB),但實際並未達到我們的效果,雖然setsockopt成功了!

我們可以通過修改系統運行時的配置(/proc),來動態地“釋放權限”,讓應用程序可以設置更大的內核讀寫緩沖區。

三、系統配置級修改緩沖區大小

復制代碼

[jiang@localhost ~]$ su - root
Password: 
[root@localhost ~]# echo 262144 > /proc/sys/net/core/rmem_default
[root@localhost ~]# echo 1048576 > /proc/sys/net/core/rmem_max
[root@localhost ~]# logout
[jiang@localhost ~]$ cat /proc/sys/net/core/rmem_default
262144
[jiang@localhost ~]$ cat /proc/sys/net/core/rmem_max
1048576
[jiang@localhost ~]$ ./main 1048576
OS default udp socket recv buff size is: 262144
you want to set udp socket recv buff size to 1048576
set udp socket(3) recv buff size to 1048576 OK!!!
OS current udp socket(2097152) recv buff size is: 2097152

 

我們在root下,修改了系統運行時的配置:

/proc/sys/net/core/rmem_default
/proc/sys/net/core/rmem_max

我們設置讀緩沖區默認值為256KB,最大值為1MB。

程序運行時,我們希望設置讀緩沖區為1MB。

通過輸出信息,我們可以驗證,修改/proc中的配置文件,我們使得一個socket默認的讀緩沖區為256KB,讀緩沖區最大值為1MB。

setsockopt系統調用級設置受限於系統運行時配置,可以通過修改系統配置,使得程序設置更大的讀寫緩沖區。
需要注意的兩點:

1.)當系統關機重啟時,對/proc的修改,是否依然存在?

不會。這就比較重要,若服務器由於異常宕機,重啟后失去了原有的設置,就有可能導致接收緩沖區過小,出現UDP丟包的可能。

2.)為什么我通過setsockopt設置讀緩沖區值為rcvBufSize,但實際getsockopt獲取的讀緩沖區大小是2*rcvBufSize?

這個是和源碼有關系。

(引用自:https://blog.csdn.net/liuguanghui1988/article/details/53375269)

 

case SO_SNDBUF:

if (val > sysctl_wmem_max)

val = sysctl_wmem_max;

if ((val * 2 ) < SOCK_MIN_SNDBUF)

sk->sk_sndbuf = SOCK_MIN_SNDBUF;

else

sk->sk_sndbuf = val * 2 ;

 

系統這么做,猜測可能是由於UDP解包封包需要的額外的空間。

所以,我稱r/wmem_max為:可由程序設置的緩沖區最大值。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM