TCPIP 网络编程-08-套接字选项

套接字选项支持对套接字进行设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <sys/socket.h>

/**
* @brief 查看套接字选项
* sock 用于查看选项套接字文件描述符
* level 可查看的可选项的协议层
* optname 要查看的可选项名
* optval 保存查看结果的缓存地址值
* optlen 第四个参数 optval 的参缓存大小,返回四个参数的字节数
* @return 成功返回 0,失败返回-1
*/
int getsockopt(int sock, int level, int optname, void *optval, socklen_t *optlen);

/**
* @brief 查看套接字选项
* sock 用于更改选项套接字文件描述符
* level 可更改的可选项的协议层
* optname 要更改的可选项名
* optval 保存要更改的选项信息的缓存地址值
* optlen 第四个参数 optval 的字节数
* @return 成功返回 0,失败返回-1
*/
int setsockopt(int sock, int level, int optname, const void *optval, socklen_t oplen);

示例地址:https://github.com/XBoom/network-ip.git 中的 apps/socket/11/ 来看看

应用如下:

  1. 查看套接字类型,运行结果如下

    1
    2
    3
    [root]#./client 
    [11/client.c:23 main info] get tcp[1] sock opt :1 4
    [11/client.c:27 main info] get udp[2] sock opt :2 4

但是!!! 套接字类型只能在创建时设置,以后不能再改变

  1. 查看缓冲区大小

    1
    2
    3
    4
    [11/client.c:33 main info] tcp send buff size:16384 
    [11/client.c:36 main info] tcp recv buff size:131072
    [11/client.c:39 main info] udp send buff size:212992
    [11/client.c:42 main info] udp recv buff size:212992
  2. time-wait 重用

    1
    2
    3
    4
    int option = 1;
    optlen = sizeof(option);
    ret = setsockopt(tcp_sock, SOL_SOCKET, SO_REUSEADDR,
    (void *)&option, optlen);

    time_wait 在四次挥手过程中会等待 2msl 时间(大多数系统是 120s),是为了等待最后的 ack 未收到。如果服务端发起 Fin,那么最后会因为 time_wait 而等待端口释放,那么再异常重启状态下,就需要等待大概 4 分钟端口才能恢复(客户端因为端口是随机分配的,所以不太在意立即释放)。

    1
    net.ipv4.tcp_tw_reuse  # 1 表示启用了端口重用,即允许在 TIME_WAIT 状态下的连接所使用的端口被新的连接使用。 0 表示禁止
  3. Nagle算法

    Nagle算法是一种用于减少小包传输的网络优化算法。它的目标是减少网络上的小型数据包数量,提高网络效率。会等待当前缓冲区中的数据被确认之后才发送新的数据。这有助于避免发送大量的小数据包,从而提高网络的效率

    image-20240114181938761

    Nagle算法的原理如下:

    1. 如果长度达到 MSS,则允许发送
    2. 如果数据包中包含FIN(断开连接标致),则允许发送
    3. 当设置了TCP_NODELAY选项,则允许发送,禁止Nagle算法
    4. 未设置TCP_CORK选项时,若所有发送的小数据包(包含长度小于MSS)均被确认,则设置该选项后,内核会尽力把小的数据包拼成一个大的数据包(一个MTU)在发送出去,若到指定时间,一般为200ms,仍未组成一个MTU,也要立刻发送。
    1
    2
    3
    //禁用 Nagle
    int flag = 1;
    setsockopt(socket_fd, IPPROTO_TCP, TCP_NODELAY, (char*)&flag, sizeof(int));

    在某些情况下,Nagle算法可能会导致一定的延迟,特别是对于那些需要低延迟的应用程序。为了避免这种情况,可以通过设置TCP_NODELAY选项来禁用Nagle算法,强制立即发送数据(默认是开启的)

粘包 问题的缘由可能发生在发送端也可能发生在接收端:

  • 由 Nagle 算法造成的发送端的粘包:当提交一段数据给 TCP 发送时,TCP 并不立刻发送此段数据,而是等待一小段时间看看在等待期间是否还有要发送的数据,若有则会一次把这好几段数据发送出去。
  • 接收端接受不及时造成的接收端粘包:TCP 会把接收到的数据存在自己的缓冲区中,然后通应用层取数据。当应用层由于某些原因不能及时地把 TCP 的数据取出来,就会造成 TCP 缓冲区中存放了几段数据

解决粘包

  • 定长消息:协议提前约定好包的长度为多少,每当接收端接收到固定长度的字节就确定一个包;
  • 消息分隔符:利用特殊符号标志着消息的开始或者结束,例如 HTTP 协议中的换行符;
  • 长度前缀:先发送N个字节代表包的大小(注意大端和小端问题),后续解析也按长度读取解析。

参考文档

  1. 《TCPIP 网络编程》