socket 接口
在很多底层网络应用开发者的眼里,一切编程都是 socket(套接字),几乎所有的网络编程都要依靠 socket。我们每天打开浏览器浏览网页时,浏览器进程和 Web 服务器之间都需要 socket 来进行通信。socket 是网络通信中应用程序对应的进程和网络协议之间的接口,如下图所示。
socket 在网络传输中有如下作用:
- socket 位于协议之上,屏蔽了不同网络协议之间的差异:。
- socket 是网络编程的入口,它提供了大量的系统调用,构成了网络程序的主体。
- socket 是 SylixOS 文件系统中的一个设备,可以通过标准 I/O 函数对 socket 进行操作,这使得我们对网络的控制和对文件的控制一样方便。
常用的 socket 类型有三种:流式(SOCK_STREAM)、数据报式(SOCK_DGRAM)以及原始式(SOCK_RAW)。流式 socket 是一种面向连接的 socket,针对于面向连接的 TCP 服务应用;数据报式 socket 是一种无连接的 socket,对应于无连接的 UDP 服务应用,对于 TCP 或 UDP 的程序开发,焦点在 Data 字段,我们没法直接对 TCP 或 UDP 头部字段进行修改,当然还有 IP 头。换句话说,我们对它们头部操作的空间非常受限,只能使用它们已经开放给我们的诸如源/目的 IP,源/目的端口等;原始式 socket 可以得到原始的 IP 包,可以自定义 IP 所承载的具体协议类型,如 TCP,UDP 或 ICMP,并手动对每种承载在 IP 协议之上的报文进行填充。
IP 地址和端口号唯一标识网络通信中的一个应用程序,其中 IP 地址加端口号就称之为 socket,也被称之为套接字。为 TCP/IP 协议设计的应用层编程接口称为 socket API。socket API 在网络分层结构中的位置,如下图所示。
网路字节序
我们已经知道,内存中的多字节数据相对于内存地址有大端和小端之分,磁盘文件中的多字节数据相对于文件中的偏移地址也有大端和小端之分。网络数据流同样有大端和小端之分,如何定义网络数据流的地址是一个需要关注的话题,发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出,接收主机把从网络上接收到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存,因此,网络数据流的地址应这样规定:先发出的数据是低地址,后发出的数据是高地址。
16 位数据大小端表示与内存布局,如下图所示。
TCP/IP 协议规定,网络数据流应采用大端字节序,即低地址存放高字节。为使网络程序具有可移植性,使同样的 C 代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和主机字节序的转换。
#include <arpa/inet.h>
uint32_t htonl(uint32_t x);
uint16_t htons(uint16_t x);
uint32_t ntohl(uint32_t x);
uint16_t ntohs(uint16_t x);
上述函数名字中,h 表示 host,n 表示 network,l 表示 long,s 表示 short。例如 htonl 函数表示将长整数从主机字节序转换为网络字节序并返回。例如,将 IP 地址转换后进行发送,如果主机是小端字节序,这些函数将对参数做相应的大小端转换,然后返回。如果主机是大端字节序,这些函数不做转换,将参数原封不动地返回。虽然在使用这些函数时包含的是 <arpa/inet.h> 头文件,但系统实现经常是在其他头文件中声明这些函数,只是这些头文件都包含在 <arpa/inet.h> 中,对于系统来说,这些函数也可被实现为宏。
socket 地址
socket API 适用于各种底层网络协议,如 IPv4、IPv6 以及后面要讲的 UNIX Domain socket。然而,各种网络协议的地址格式并不相同,为使不同格式地址能够传入到套接字函数,地址会被强制转换成一个通用的地址结构 sockaddr。
下面是在 SylixOS 下的实现:
struct sockaddr {
u8_t sa_len;
sa_family_t sa_family;
#if LWIP_IPV6
char sa_data[26];/* sylixos add 4 bytes to a same size with in6 */
#else /* LWIP_IPV6 */
char sa_data[14];
#endif /* LWIP_IPV6 */
};
IPv4(AF_INET)地址 in_addr 结构:
struct in_addr {
in_addr_t s_addr;
};
IPv4(AF_INET)地址 sockaddr_in 结构:
struct sockaddr_in {
u8_t sin_len;
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
#define SIN_ZERO_LEN 8
char sin_zero[SIN_ZERO_LEN];
};
下面是 sockaddr_in 结构成员含义:
- sin_len:数据结构长度,是为增加 OSI 协议支持而增加的,有了长度成员后简化了变长套接口地址结构的处理。
- sin_family:地址族(AF_INET)。
- sin_port:网络协议端口号。
- sin_addr:网路字节序的 IPv4 地址。
- sin_zero:8 字节的数据填充。
IPv6(AF_INET6)地址 in6_addr 结构:
struct in6_addr {
union {
u8_t u8_addr[16];
u32_t u32_addr[4];
} un;
#define s6_addr un.u8_addr
};
IPv6(AF_INET6)地址 sockaddr_in6 结构:
struct sockaddr_in6 {
u8_t sin6_len; /* length of this structure */
sa_family_t sin6_family; /* AF_INET6 */
in_port_t sin6_port; /* Transport layer port */
u32_t sin6_flowinfo; /* IPv6 flow information */
struct in6_addr sin6_addr; /* IPv6 address */
/*
* sylixos add this
*/
u32_t sin6_scope_id; /* set of interfaces for a scope */
};
下面是 sockaddr_in6 结构成员含义:
- sin6_len:数据结构长度。
- sin6_family:地址族(AF_INET6)。
- sin6_port:传输层端口号。
- sin6_flowinfo:流信息,低序 20 位是流标签,高序 12 位保留。
- sin6_addr:IPv6 地址。
- sin6_scope_id:范围 ID。
UNIX 协议域地址 sockaddr_un 结构:
struct sockaddr_un {
uint8_t sun_len; /* sockaddr len including null */
uint8_t sun_family; /* AF_UNIX */
char sun_path[104]; /* path name (gag) */
};
下面是 sockaddr_un 结构成员含义:
- sun_len:数据结构长度。
- sun_family:地址族(AF_UNIX)。
- sun_path:路径名。
不同套接口地址结构对比,如下图所示。
sockaddr_in 中的成员 sin_addr 表示 32 位的 IPv4 地址。但是我们通常用点分十进制的字符串表示 IPv4 地址,以下函数可以在字符串表示和 in_addr 表示之间进行地址转换。
点分十进制字符串(如“192.168.1.15”)转换为 32 位网络字节序二进制值函数:
#include <arpa/inet.h>
uint32_t inet_addr(const char *name);
函数 inet_addr 原型分析:
- 此函数成功时返回 32 位二进制的网络字节序地址,失败返回 INADDR_NONE。
- 参数 name 是点分十进制地址,如“192.168.1.15”。
此函数存在一个问题,不能表示全部的有效 IP 地址(从 0.0.0.0 到 255.255.255.255),当函数出错时返回值为 INADDR_NONE(一般为一个 32 位均为 1 的值),这就意味着点分十进制数串 255.255.255.255(这是 IPv4 的有限广播地址)不能由此函数进行转换,因为它的二进制值被用来指示函数失败,此函数还有一个潜在的问题,有些非正式的文档把出错时的返回值定义为-1 而不是 INADDR_NONE,这样比较函数的返回值(无符号的值)与负常值时可能会出问题,这取决于 C 编译器。
点分十进制字符串(如“192.168.1.15”)转换为 32 位网络字节序二进制值函数:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int inet_aton(const char *name, struct in_addr *addr);
函数 inet_aton 原型分析:
- 此函数字符串有效时返回 1,无效时返回 0。
- 参数 name 是点分十进制地址,如“192.168.1.15”。
- 参数 addr 是用于保存网络字节序二进制值的缓冲地址。
此函数有一个没有写到正式文档中的特征,如果指针为空,则函数仍然执行输入串的有效性检测,但不存储任何结果。
32 位网络字节序二进制值转换为点分十进制字符串(如“192.168.1.15”)函数:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
char *inet_ntoa(struct in_addr addr);
函数 inet_ntoa 原型分析:
- 此函数正确时返回字符串指针,错误时返回 NULL。
- 参数 addr 是 32 位网络字节序地址。
由于此函数返回值所指的字符串驻留在静态内存中,这意味着此函数是不可重入的,并且此函数以结构体为参数,而不是指向结构的指针,通常情况,这个函数被设计成宏。
可重入的 32 位网络字节序二进制值转换为点分十进制字符串(如“192.168.1.15”)函数:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
char *inet_ntoa_r(struct in_addr addr, char *buf, int buflen);
函数 inet_ntoa_r 原型分析:
- 此函数正确时返回字符串指针,错误时返回 NULL。
- 参数 addr 是 32 位网络字节序地址。
- 参数 buf 为点分十进制字符串缓冲区。
- 参数 buflen 为缓冲区长度。
inet_pton 和 inet_ntop 是两个较新的地址转换函数,对 IPv4 和 IPv6 地址都能处理。其中字母 p 和 n 分别代表 presentation 和 numeric。地址表达式(presentation)格式通常是 ASCII 串,数值(numeric)格式是存在于套接口地址结构中的二进制值。
函数 inet_pton 将字符串地址表达式转换为二进制数值:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int inet_pton(int af, const char *cp, void *buf);
函数 inet_pton 原型分析:
- 此函数正确时返回 1,错误时返回-1,输入不是有效的表达格式时返回 0。
- 参数 af 必须是 AF_INET 或者 AF_INET6。其他地址族不被支持,且返回错误。
- 参数 cp 是地址串,如 IPv4 的“192.168.1.15”。
- 参数 buf 用于保存二进制结果。
inet_pton 函数没有指定 buf 的大小,因此需要应用程序保证在 AF_INET 时有足够的空间存放一个 32 位地址,在 AF_INET6 时有足够的空间存放一个 128 位地址。
inet_ntop 函数将二进制数值转换为字符串表达式:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
const char *inet_ntop(int af, const void *cp, char *buf, size_t len);
函数 inet_ntop 原型分析:
- 此函数正确时返回地址串的指针,错误时返回 NULL。
- 参数 af 必须是 AF_INET 或者 AF_INET6。其他地址族不被支持,且返回错误。
- 参数 cp 保存了二进制数值。
- 参数 buf 用于保存转换后的地址字符串。
- 参数 len 指定了 buf 的大小,用于避免缓冲区的溢出。
地址转换函数总结,如下图所示。
socket 函数
为了执行网络 I/O,必须做的第一件事情就是调用 socket 函数,指定期望的通信协议类型(例如:可以指定 IPv4 的 TCP 通信、指定 IPv6 的 UDP 通信、指定 UNIX 域通信等)。
调用 socket 函数可以创建一个套接字:
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
函数 socket 原型分析:
- 此函数成功时返回文件描述符也称之为套接口描述字(socket descriptor),简称为套接字(socketfd),失败时返回-1 并设置错误号。
- 参数 domain 是协议域,又称协议族。协议族决定了 socket 的地址类型,在通信中必须采用对应的地址,如 AF_INET 决定了要用 IPv4 地址(32 位的)与端口号(16 位的)的组合、AF_UNIX 决定了要用一个绝对路径名作为地址。协议族参数描述,如下表所示。
协议域 | 说明 |
---|---|
AF_UNSPEC | 未指定 |
AF_INET | IPv4 因特网域 |
AF_INET6 | IPv6 因特网域 |
AF_UNIX/AF_LOCAL | UNIX 域 |
AF_PACKET | PACKET 域 |
AF_ROUTE | 路由域 |
- 参数 type 是 socket(套接字)类型。如下表所示是 SylixOS 支持的所有类型,当然这些需要搭配具体协议域进行使用。
套接字类型 | 说明 |
---|---|
SOCK_DGRAM | 数据报套接口,固定长度,无连接的,不可靠的报文传递 |
SOCK_RAW | 原始套接口,IP 协议的数据报接口 |
SOCK_SEQPACKET | 有序分组套接口,固定长度的、有序的、可靠的、面向连接的报文传递 |
SOCK_STREAM | 字节流套接口,有序的、可靠的、双向的、面向连接的字节流 |
- 参数 protocol 是协议类型:
协议类型 | 说明 |
---|---|
IPPROTO_IP | IPv4 网络协议 |
IPPROTO_ICMP | 因特网控制报文协议 |
IPPROTO_TCP | 传输控制协议 |
IPPROTO_UDP | 用户数据报协议 |
IPPROTO_IPV6 | IPv6 网络协议 |
IPPROTO_ICMPV6 | 因特网控制报文协议 |
IPPROTO_SCTP | 流控制传输协议 |
IPPROTO_RAW | 原始 IP 数据包协议 |
IPPROTO_UDPLITE | UDP传输协议扩展 |
参数 domain 确定了通信的特性,包括地址格式等。AF_UNIX 是一种高级的 IPC 机制,具体使用将在”AF_UNIX域协议“中详细叙述,AF_PACKET 是一个较新的套接口类型,支持对数据链路层的操作,具体使用将在”AF_PACKET链路层通信“中详细叙述。AF_UNSPEC 域在 SylixOS 中不被支持。
参数 protocol 通常为 0,表示为给定的域和套接字类型选择默认协议。当对同一域和套接字类型支持多个协议时,可以使用 protocol 选择一个特定协议。在 AF_INET 通信域中,套接字类型 SOCK_STREAM 的默认协议是传输控制协议(TCP),套接字类型 SOCK_DGRAM 的默认协议是 UDP。
对于数据报接口,两个对等应用程序之间通信时不需要逻辑连接。只需要向对等应用程序所使用的套接字送出一个报文。因此数据报(SOCK_DGRAM)提供了一个无连接的服务。而字节流(SOCK_STREAM)要求在交换数据之前,在本地套接字和通信的对等应用程序的套接字之间建立一个逻辑连接。
对于字节流(SOCK_STREAM),应用程序分辨不出报文的界限。这意味着从字节流套接字读数据时,它也许不会返回所有由发送应用程序所写的字节数。最终可以获得发送过来的所有数据,但也许要通过若干次函数调用才能得到。
并非所有的套接字协议域与类型的组合都是有效的,如下表所示给出了一些有效的组合和对应的真正协议,其中标识为“Y”的项表示是有效的,只是没有找到便捷的缩略词,而标识为“N”的项表示不支持。
类型 | AF_INET | AF_INET6 | AF_UNIX | AF_PACKET | AF_ROUTE |
---|---|---|---|---|---|
SOCK_SEQPACKET | SCTP | SCTP | Y | N | N |
SOCK_STREAM | TCP | TCP | Y | N | N |
SOCK_DGRAM | UDP | UDP | Y | Y | N |
SOCK_RAW | IPv4 | IPv6 | N | Y | Y |
socket 选项
套接字选项通过调用 setsockopt 函数和 getsockopt 函数进行操作,SylixOS 网络支持多种套接字选项如下表所示。
#include <sys/socket.h>
int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen);
函数 setsockopt 原型分析:
- 此函数成功时返回 0,失败时返回-1 并设置错误号。
- 参数 s 是套接字(socket 函数返回)。
- 参数 level 是选项等级如下表所示。
- 参数 optname 是选项名如下表所示。
- 参数 optval 是选项值。
- 参数 optlen 是选项长度。
通过调用 setsockopt 函数来设置不同选项等级的不同选项,参数 optval 是一个指向变量的指针类型,根据不同的选项,类型也不同如下表所示。
#include <sys/socket.h>
int getsockopt(int s, int level, int optname,
void *optval, socklen_t *optlen);
函数 getsockopt 原型分析:
- 此函数成功返回 0,失败返回-1 并设置错误号。
- 参数 s 是套接字(socket 函数返回)。
- 参数 level 是选项等级如下表所示。
- 参数 optname 是选项名如下表所示。
- 输出参数 optval 返回选项值。
- 参数 optlen 是选项长度。
调用 getsockopt 函数可以获得套接字的选项值,参数 optlen 将返回选项值的实际长度。
选项等级 | 选项名 | 说明 | 适用函数 | 数据类型 | 协议域 |
---|---|---|---|---|---|
SOL_SOCKET | SO_BROADCAST | 运行发送广播数据报 | getsockopt setsockopt | int | AF_NET AF_INET6 |
SO_ERROR | 获取待处理错误并消除 | getsockopt | int | AF_INET AF_INET6 AF_ROUTE AF_UNIX AF_PACKET AF_SCTP | |
SO_KEEPALIVE | 周期性测试连接是否存活 | getsockopt setsockopt | int | AF_NET AF_INET6 | |
SO_LINGER | 设置socket链接关闭时间,该关闭socket不再进行正常的四次挥手动作 | getsockopt setsockopt | struct linger | AF_NET AF_INET6 AF_UNIX | |
SO_DONTLINGER | 关闭SO_LINGER选项 | setsockopt | int | AF_UNIX | |
SO_RCVBUF | 接受缓冲区大小 | getsockopt setsockopt | int | AF_NET AF_INET6 AF_UNIX AF_PACKET | |
SO_RCVTIMEO | 数据接受超时时间 | getsockopt setsockopt | struct timeval / int | AF_NET AF_INET6 AF_UNIX AF_PACKET | |
SO_SNDTIMEO | 数据发送超时时间 | getsockopt setsockopt | struct timeval / int | AF_NET AF_INET6 AF_UNIX | |
SO_REUSEADDR | 允许重用本地地址 | getsockopt setsockopt | int | AF_NET AF_INET6 AF_UNIX | |
SO_NO_CHECK | 不创建UDP校验和(该选项不支持 UDPLITE) | getsockopt setsockopt | int | AF_NET AF_INET6 | |
SO_UDPCONALA | UDP连接赋值本地地址 | getsockopt setsockopt | int | AF_NET AF_INET6 | |
SO_BINDTODEVICE | 绑定socket到指定网络接口 | setsockopt | struct ifreq | AF_NET AF_INET6 | |
SO_SECREGION | 设置 socket 安全域(仅支持在root权限设置) | getsockopt setsockopt | unsigned int | AF_NET AF_INET6 AF_PACKET | |
SO_PRIORITY | 设置IP数据包优先级 | getsockopt setsockopt | int | AF_NET AF_INET6 | |
SO_TYPE | 获取socket类型(包括:SOCK_RAW/SOCK_STREAM/SOCK_DGRAM) | getsockopt | int | AF_NET AF_INET6 AF_UNIX AF_PACKET | |
SO_CONTIMEO | 连接超时时间 | getsockopt setsockopt | struct timeval | AF_UNIX | |
SO_PASSCRED | 是否传输认证信息 | getsockopt setsockopt | int | AF_UNIX | |
SO_ACCEPTCONN | 查看socket是否已经处于listen状态(仅针对getsockopt接口) | getsockopt | int | AF_NET AF_INET6 AF_UNIX | |
SOL_PACKET | PACKET_ADD_MEMBERSHIP | 加入多播组 | setsockopt | struct packet_mreq | AF_PACKET |
PACKET_DROP_MEMBERSHIP | 离开多播组 | setsockopt | struct packet_mreq | AF_PACKET | |
PACKET_RECV_OUTPUT | 是否接收输出数据包 | getsockopt setsockopt | int | AF_PACKET | |
PACKET_RX_RING | 为mmap分配内存空间 | setsockopt | struct tpacket_req | AF_PACKET | |
PACKET_VERSION | 设置AF_PACKET版本 | getsockopt setsockopt | enum tpacket_versions | AF_PACKET | |
PACKET_STATISTICS | 收集数据包统计信息 | getsockopt | struct tpacket_stats | AF_PACKET | |
PACKET_HDRLEN | 数据包头部长度 | getsockopt | int | AF_PACKET | |
PACKET_RESERVE | 为mmap分配空间保留额外的头部空间 | getsockopt setsockopt | unsigned int | AF_PACKET | |
IPPROTO_IP | IP_TTL | IP包在网络中的存活时间 | getsockopt setsockopt | int | AF_INET |
IP_TOS | 服务类型和优先级 | getsockopt setsockopt | int | AF_INET | |
IP_MINTTL | 最小 TTL 值 | getsockopt setsockopt | int | AF_INET | |
IP_HDRINCL | 操作系统不自动添加IP头部,由应用程序添加 | getsockopt setsockopt | int | AF_INET | |
IP_OPTIONS | 应用程序添加IP头部自定义选项(仅支持RAW socket 类型) | getsockopt setsockopt | int | AF_INET | |
IP_MULTICAST_TTL | 多播TTL | getsockopt setsockopt | int | AF_INET | |
IP_MULTICAST_IF | 多播数据发送接口配置 | getsockopt setsockopt | struct in_addr | AF_INET | |
IP_MULTICAST_LOOP | 多播数据是否回环本地发送接口 | getsockopt setsockopt | int | AF_INET | |
IP_MSFILTER | 组播源过滤配置 | getsockopt setsockopt | struct ip_msfilter | AF_INET | |
MCAST_MSFILTER | 组播组过滤配置 | getsockopt setsockopt | struct group_filter | AF_INET | |
MRT_VERSION | 组播路由版本信息 | setsockopt | int | AF_INET | |
MRT_ASSERT | 组播路由断言 | setsockopt | int | AF_INET | |
MRT_API_SUPPORT | 组播路由API支持情况 | setsockopt | uint32_t | AF_INET | |
MRT_API_CONFIG | 组播路由配置情况 | setsockopt | uint32_t | AF_INET | |
IP_PKTINFO | 启用接收包扩展信息 | setsockopt | int | AF_INET | |
IP_ADD_MEMBERSHIP | 加入多播组 | setsockopt | struct ip_mreq | AF_INET | |
IP_DROP_MEMBERSHIP | 离开多播组 | setsockopt | struct ip_mreq | AF_INET | |
IP_ADD_SOURCE_MEMBERSHIP | 加入源特定多播组 | setsockopt | struct ip_mreq_source | AF_INET | |
IP_DROP_SOURCE_MEMBERSHIP | 离开源特定多播组 | setsockopt | struct ip_mreq_source | AF_INET | |
IP_BLOCK_SOURCE | 增加一个被屏蔽的源地址到多播组(可以是全部网络接口) | setsockopt | struct ip_mreq_source | AF_INET | |
IP_UNBLOCK_SOURCE | 从多播组解除一个被屏蔽的源地址(可以是全部网络接口) | setsockopt | struct ip_mreq_source | AF_INET AF_INET | |
MCAST_JOIN_GROUP | 加入多播组 | setsockopt | struct group_req | AF_INET | |
MCAST_LEAVE_GROUP | 离开多播组 | setsockopt | struct group_req | AF_INET | |
MCAST_JOIN_SOURCE_GROUP | 加入源多播组 | setsockopt | struct group_source_req | AF_INET | |
MCAST_LEAVE_SOURCE_GROUP | 离开源多播组 | setsockopt | struct group_source_req | AF_INET | |
MCAST_BLOCK_SOURCE | 增加一个被阻止的源地址到多播组(单个网络接口) | setsockopt | struct group_source_req | AF_INET | |
MCAST_UNBLOCK_SOURCE | 从多播组解除一个被屏蔽的源地址(单个网络接口) | setsockopt | struct group_source_req | AF_INET | |
MRT_INIT | 初始化组播路由表 | setsockopt | int | AF_INET | |
MRT_DONE | 完成组播路由配置 | setsockopt | N/A | AF_INET | |
MRT_ADD_VIF | 添加一个虚拟接口到组播路由接口 | setsockopt | struct vifctl | AF_INET | |
MRT_DEL_VIF | 删除一个虚拟接口从组播路由接口 | setsockopt | vifi_t | AF_INET | |
MRT_ADD_MFC | 添加或更新组播转发缓存(Multicast Forwarding Cache,MFC)表项 | setsockopt | struct mfcctl2 | AF_INET | |
MRT_DEL_MFC | 删除指定的MFC表项 | setsockopt | struct mfcctl2 | AF_INET | |
MRT_ASSERT | 触发组播路由表中的断言 | setsockopt | int | AF_INET | |
MRT_API_CONFIG | 组播路由配置情况 | setsockopt | uint32_t | AF_INET | |
IPPROTO_TCP | TCP_NODELAY | 是否开启小包立即发送功能 | getsockopt setsockopt | int | AF_INET AF_INET6 |
TCP_KEEPALIVE | 探测对方是否存活前连接闲置秒数 | getsockopt setsockopt | int | AF_INET AF_INET6 | |
TCP_KEEPIDLE | 对一个连接探测前的允许时间 | getsockopt setsockopt | int | AF_INET AF_INET6 | |
TCP_KEEPINTVL | 两个探测的时间间隔 | getsockopt | int | AF_INET AF_INET6 | |
TCP_KEEPCNT | 探测的最大次数 | getsockopt | int | AF_INET AF_INET6 | |
TCP_REALTIME | TCP实时模式,快速重传,该选项可以提供网络的实时响应速度 | getsockopt setsockopt | int | AF_INET AF_INET6 | |
TCP_QUICKACK | 立即发送ACK | getsockopt setsockopt | int | AF_INET AF_INET6 | |
TCP_DESC | 获取TCP状态信息 | getsockopt | struct tcp_desc | AF_INET AF_INET6 | |
IPPROTO_IPV6 | IPV6_MINHOPCNT | IPV6最小TTL值 | getsockopt setsockopt | int | AF_INET6 |
IPV6_UNICAST_HOPS | 单播数据包跳数 | getsockopt setsockopt | int | AF_INET6 | |
IPV6_MULTICAST_IF | 设置组播数据包网络接口索引 | getsockopt setsockopt | int | AF_INET6 | |
IPV6_MULTICAST_HOPS | 设置组播数据包跳数 | getsockopt setsockopt | int | AF_INET6 | |
IPV6_MULTICAST_LOOP | 组播数据包是否回环到发送者 | getsockopt setsockopt | int | AF_INET6 | |
IPV6_CHECKSUM | 检验和 | getsockopt setsockopt | int | AF_INET6 | |
IPV6_V6ONLY | 套接字仅支持IPV6 | getsockopt setsockopt | int | AF_INET6 | |
IPV6_RECVPKTINFO | 接收附加消息 | setsockopt | int | AF_INET6 | |
IPV6_RECVHOPLIMIT | 接收跳数限制 | setsockopt | int | AF_INET6 | |
IPV6_JOIN_GROUP | 加入IPV6组播组 | setsockopt | struct ipv6_mreq | AF_INET6 | |
IPV6_LEAVE_GROUP | 离开IPV6组播组 | setsockopt | struct ipv6_mreq | AF_INET6 | |
IPPROTO_UDPLITE | UDPLITE_SEND_CSCOV | 执行发送校验和 | setsockopt | int | AF_NET AF_INET6 |
UDPLITE_RECV_CSCOV | 执行接收校验和 | setsockopt | int | AF_NET AF_INET6 | |
IPPROTO_RAW | IPV6_CHECKSUM | IPV6校验和 | setsockopt getsockopt | int | AF_NET6 |
上表中 SOL_PACKET 选项等级用于 AF_PACKET 类型套接字的选项,这些选项将在”AF_PACKET链路层通信“中详细介绍。
下面程序展示了通过设置套接字选项来控制相应套接字的行为,此程序首先通过调用 setsockopt 函数设置 IPv4 的接收缓冲区的大小,然后调用 getsockopt 函数来获得接收缓冲区的大小以确认接收缓冲区的大小被正确改变。
#include <stdio.h>
#include <sys/socket.h>
int main (int argc, char *argv[])
{
int sockfd;
int sopt = 2048;
int gopt;
int ret;
socklen_t len = sizeof(int);
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
fprintf(stderr, "create socket error.\n");
return (-1);
}
ret = setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &sopt, len);
if (ret < 0) {
fprintf(stderr, "setsockopt error.\n");
return (-1);
}
ret = getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &gopt, &len);
if (ret < 0) {
fprintf(stderr, "getsocket error.\n");
return (-1);
}
fprintf(stdout, "IPv4 recv buffer size: %d\n", gopt);
return (0);
}
在 SylixOS Shell 下运行程序,结果显示如下:
# ./Set_Socket_Options
IPv4 recv buffer size: 2048