TCP协议之TCP缓冲区

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Function_Dou/article/details/89915119

每个套接字都会有一个发送缓冲区和接收缓冲区, 这样的功能保证了TCP的容错性, 毕竟数据有保存可以重传.


TCP缓冲区

对TCP来说套接字接收缓冲区限制了TCP通告对端的窗口大小. 并且, 接收缓冲区不存在溢出问题, 因为不允许发送超过本端所通告窗口大小的数据, 这就是TCP流量控制. 如果对端发送了超过窗口大小的数据, 则接收端将直接丢弃.


UDP缓冲区

既然说了TCP缓冲区, 顺便提一下UDP吧. UDP没有发送缓冲区只有接收缓冲区, 如果对端的接收缓冲区满了则其他数据也将被直接丢弃.


TCP缓冲区设置

TCP缓冲区可以通过 getsockopt获取 和 setsockopt设置. 但是后者的调用位置必须要正确才行.

因为TCP窗口的大小是在三次握手建立连接时相互告知的(MSS和MTU那一节), 所以setsockopt函数必须在listen之前以及connect调用之前才行. 如果不清楚为什么是listen之前而不是accept之前的可以回过头看一下**[网络编程三次握手] ()**.

对于客户端,SO_RCVBUF选项须在connect之前设置.
对于服务器,SO_RCVBUF选项须在listen前设置.


先来看一下默认的TCP缓冲区大小 :

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>

int main(int argc, char *argv[]){
    int tcp_buf, udp_buf;
    int sock;
    socklen_t len;

    sock = socket(AF_INET, SOCK_STREAM, 0);
    len = sizeof(sock);
    getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void *)&tcp_buf, &len);
    printf("tcp buff : %d\n", tcp_buf);	// tcp buff : 16384

    close(sock);

    sock = socket(PF_INET, SOCK_DGRAM, 0);
    len = sizeof(sock);
    getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void *)&udp_buf, &len);
    printf("udp buff : %d\n", udp_buf);	// udp buff : 212992

    close(sock);


    return 0;
}

我们再来通过setsockopt来设置缓冲区大小.

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>

int main(int argc, char *argv[]){
    int tcp_buf, udp_buf;
    int sock;
    socklen_t len;

    sock = socket(AF_INET, SOCK_STREAM, 0);
    len = sizeof(sock);
    getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void *)&tcp_buf, &len);
    printf("tcp old buff : %d\n", tcp_buf);	// tcp old buff : 16384
    
    tcp_buf = 8;
    setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void *)&tcp_buf, len);
    getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void *)&tcp_buf, &len);
    printf("tcp new buff : %d\n", tcp_buf);	// tcp new buff : 4608

    close(sock);

    sock = socket(PF_INET, SOCK_DGRAM, 0);
    len = sizeof(sock);
    getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void *)&udp_buf, &len);
    printf("udp buff : %d\n", udp_buf);	// udp buff : 212992
    
    udp_buf = 8;
    setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void *)&udp_buf, len);
    getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void *)&udp_buf, &len);
    printf("udp buff : %d\n", udp_buf);	// udp buff : 4608

    close(sock);

    return 0;
}

运行结果 :

tcp old buff : 16384
tcp new buff : 4608
udp buff : 212992
udp buff : 4608

很明显我们设置了缓冲区, 真正的缓冲区虽然被改变了但不是我们实际设置的值. 只是通过调用setsockopt向系统传达我们的要求.

还有需要注意的一点, 缓冲区的大小至少为MSS的4倍, 因为TCP还有快速恢复算法需要接收3次确认.


小结

  • TCP流量控制
  • 了解设置TCP缓冲区大小

猜你喜欢

转载自blog.csdn.net/Function_Dou/article/details/89915119
今日推荐