linux下socket内核缓冲区的大小

本次尝试主要研究 linux socket接受发送缓冲区的大小,以及当缓冲区阻塞时,能发送多少数据。

(1)实验与尝试

测试环境: vmware虚拟机 centos7系统。

服务端建立连接后睡眠,应用层不接受任何数据,只有内核接受缓冲区才接受数据。

服务端代码如下:

#include
#include
#include
#include
#include
#include
#include
#include

#define MAXLINE 8096

int main(int argc, char** argv){
    int  listenfd, connfd;
    struct sockaddr_in  servaddr;
    char  buff[MAXLINE];
    FILE *fp;
    int  n;

    if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ){
        printf("create socket error: %s(errno: %d)\n",strerror(errno),errno);
        return 0;
    }
    printf("----init socket----\n");

    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(6666);
    //设置端口可重用
    int contain;
    setsockopt(listenfd,SOL_SOCKET, SO_REUSEADDR, &contain, sizeof(int));

    if( bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){
        printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno);
        return 0;
    }
    printf("----bind sucess----\n");

    if( listen(listenfd, 10) == -1){
        printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno);
        return 0;
    }
    if((fp = fopen("new.txt","ab") ) == NULL )
    {
        printf("File.\n");
        close(listenfd);
        exit(1);
    }

    printf("======waiting for client's request======\n");
    while(1){
        struct sockaddr_in client_addr;
        socklen_t size=sizeof(client_addr);
        if( (connfd = accept(listenfd, (struct sockaddr*)&client_addr, &size)) == -1){
            printf("accept socket error: %s(errno: %d)",strerror(errno),errno);
            continue;
        }
		
	int s_length;
	socklen_t optl = sizeof s_length;
	getsockopt(connfd,SOL_SOCKET,SO_SNDBUF,&s_length,&optl);     
	printf("server connfd send buffer = %d\n",s_length);                         
	getsockopt(connfd,SOL_SOCKET,SO_RCVBUF,&s_length,&optl);      
	printf("server connfd recv buffer = %d\n",s_length);  
	
	sleep(300000);	
	
	while(1){
		n = read(connfd, buff, MAXLINE);
		if(n == 0)
			break;
		fwrite(buff, 1, n, fp);
	}
	buff[n] = '\0';
	printf("recv msg from client: %s\n", buff);
	close(connfd);
	fclose(fp);
    }
    close(listenfd);
    return 0;
}

客户端代码如下:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define MAXLINE 8096

int main(int argc, char** argv){
    int   sockfd, len;
    char  buffer[MAXLINE];
    struct sockaddr_in  servaddr;
    FILE *fq;

	/*
    if( argc != 2){
        printf("usage: ./client \n");
        return 0;
    }
	*/
    if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
        printf("create socket error: %s(errno: %d)\n", strerror(errno),errno);
        return 0;
    }
	
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(6666);
	servaddr.sin_addr.s_addr=inet_addr("127.0.0.1");
	/*
    if( inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0){
        printf("inet_pton error for %s\n",argv[1]);
        return 0;
    }
	*/
    if( connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0){
        printf("connect error: %s(errno: %d)\n",strerror(errno),errno);
        return 0;
    }
	
	int s_length;
    socklen_t optl = sizeof s_length;
	getsockopt(sockfd,SOL_SOCKET,SO_SNDBUF,&s_length,&optl);     //
    printf("client send buffer = %d\n",s_length);                         // 
 
    getsockopt(sockfd,SOL_SOCKET,SO_RCVBUF,&s_length,&optl);      //
    printf("client recv buffer = %d\n",s_length);  

	
    if( ( fq = fopen("/root/socket/all.txt","rb") ) == NULL ){
        printf("File open.\n");
        close(sockfd);
        exit(1);
    }

    bzero(buffer,sizeof(buffer));
    int sum = 0;
    int writelen = 0;
    while(!feof(fq)){
        len = fread(buffer, 1, sizeof(buffer), fq);
        writelen = write(sockfd, buffer, len);
	if(writelen < 0) {
            printf("write.\n");
            break;
        }
	sum += writelen;	
	printf("writelen %d sum %d\n",writelen, sum);
    }
    printf("sum %d", sum);
    close(sockfd);
    fclose(fq);

    return 0;
}

运行服务端 效果截图如下:

linux下socket内核缓冲区的大小_第1张图片

客户端截图效果如下

linux下socket内核缓冲区的大小_第2张图片

最后写多少数据进去不同的时期运行结果不是固定的

linux下socket内核缓冲区的大小_第3张图片

 

linux下socket内核缓冲区的大小_第4张图片

(3)分析与疑惑:

客户端与服务端的连接socket 内核发送缓冲区约为2.6M,接收缓冲区为1M,按照以前的想法,文本数据all.txt 的大小约为8.8M,客户端每次向发送缓冲区写如8096字节。按照原来的设想,客户端能写入的字节 = 客户端发送缓冲区大小 + 服务端接收缓冲区大小,约3.6M。事实上客户端写入的字节数均大于4.7M,与设想不符合。

(3)尝试解决

尝试使用抓包工具wiresha'rk,查看tcp连接状态以及窗口大小,单服务器与客户端都再虚拟机上,发包没有经过网卡,故捕获不了。利用linux自带的 tcpdump -i -lo  抓取回环网口的包,截图如下;

linux下socket内核缓冲区的大小_第5张图片

结论尚未明确,等待下一部操作。有知情大佬请留言。

你可能感兴趣的:(linux下socket内核缓冲区的大小)