类型

  • 基于网络协议的套接字类型
    1. 流式套接字(TCP Socket,SOCK_STREAM)
      • 特点: 面向连接:在进行数据传输之前,需要先建立连接,传输完成后再断开连接。连接的建立和断开遵循特定的握手协议,例如 TCP 的三次握手和四次挥手。
      • 可靠传输:通过确认机制、重传机制和滑动窗口协议等,保证数据在传输过程中不会丢失、重复或乱序,确保数据的完整性和顺序性。
      • 字节流传输:数据以字节流的形式进行传输,就像水流一样连续不断,发送方可以连续发送数据,接收方可以按顺序接收数据。
      • 使用场景:适用于对数据传输可靠性要求较高的场景,如文件传输(FTP)、网页浏览(HTTP)、电子邮件(SMTP、POP3、IMAP)等。
    2. 数据报套接字(UDP Socket,SOCK_DGRAM)
      • 特点: 无连接:在发送数据之前不需要建立连接,直接将数据报发送到目标地址。因此,它的通信效率较高,开销较小。
      • 不可靠传输:不保证数据的可靠到达,也不保证数据的顺序性。数据可能会丢失、重复或乱序,但传输速度相对较快。
      • 数据报传输:数据以独立的数据报形式进行传输,每个数据报都包含完整的目标地址和源地址信息,接收方根据数据报的头部信息进行接收和处理。
      • 使用场景:适用于对实时性要求较高,对数据准确性要求相对较低的场景,如实时音视频传输(如 VoIP、在线直播)、游戏网络通信等。
    3. 原始套接字(SOCK_RAW)
      • 特点: 直接访问网络层:可以绕过传输层协议(如 TCP 和 UDP),直接对网络层数据包进行操作。这使得开发者可以自定义数据包的头部信息,实现一些特殊的网络功能。
      • 高级网络编程:需要对网络协议有深入的了解,使用起来相对复杂。
      • 使用场景:常用于网络协议分析、网络安全工具开发(如网络嗅探器、防火墙等)以及实现一些特殊的网络应用,如 ICMP 协议的应用程序。
  • 基于通信范围的套接字类型
    1. 网络套接字
      • 特点:用于不同主机之间的网络通信,通过网络协议(如 IP 协议)进行数据传输。可以跨越局域网、广域网等不同的网络范围。
      • 使用场景:上述的 TCP 套接字和 UDP 套接字都属于网络套接字,广泛应用于互联网上的各种通信场景。
    2. Unix 域套接字(Unix Domain Socket)
      • 特点
        • 本地进程间通信:仅用于同一主机上不同进程之间的通信,不涉及网络协议栈,因此通信效率更高,延迟更低。
        • 文件系统接口:通过文件系统中的文件作为通信端点,使用起来类似于网络套接字,但更加简单和高效。
        • 支持流式和数据报两种模式:可以选择使用面向连接的流式模式(SOCK_STREAM)或无连接的数据报模式(SOCK_DGRAM)。
      • 使用场景:适用于同一主机上不同进程之间的高效通信,如数据库服务器与客户端之间的通信、系统服务之间的交互等。
  • 其他特殊套接字类型
    1. 可靠数据报套接字(SOCK_RDM)
      • 特点:结合了 UDP 的无连接特性和 TCP 的可靠传输特性,提供可靠的数据报传输服务。但在实际应用中使用相对较少。
      • 使用场景:在一些对实时性和可靠性都有一定要求的场景中可能会使用,但由于实现复杂,应用范围有限。
    2. 顺序包套接字(SOCK_SEQPACKET)
      • 特点:类似于流式套接字,但它保留了消息的边界,即发送的每个消息都会作为一个独立的单元被接收,不会像流式套接字那样将数据合并成连续的字节流。
      • 使用场景:适用于需要按消息边界处理数据的场景,如某些特定的网络协议实现。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#define AF_UNSPEC	PF_UNSPEC
#define AF_LOCAL PF_LOCAL
#define AF_UNIX PF_UNIX
#define AF_FILE PF_FILE
#define AF_INET PF_INET
#define AF_AX25 PF_AX25
#define AF_IPX PF_IPX
#define AF_APPLETALK PF_APPLETALK
#define AF_NETROM PF_NETROM
#define AF_BRIDGE PF_BRIDGE
#define AF_ATMPVC PF_ATMPVC
#define AF_X25 PF_X25
#define AF_INET6 PF_INET6
#define AF_ROSE PF_ROSE
#define AF_DECnet PF_DECnet
#define AF_NETBEUI PF_NETBEUI
#define AF_SECURITY PF_SECURITY
#define AF_KEY PF_KEY
#define AF_NETLINK PF_NETLINK
#define AF_ROUTE PF_ROUTE
#define AF_PACKET PF_PACKET
#define AF_ASH PF_ASH
#define AF_ECONET PF_ECONET
#define AF_ATMSVC PF_ATMSVC
#define AF_RDS PF_RDS
#define AF_SNA PF_SNA
#define AF_IRDA PF_IRDA
#define AF_PPPOX PF_PPPOX
#define AF_WANPIPE PF_WANPIPE
#define AF_LLC PF_LLC
#define AF_IB PF_IB
#define AF_MPLS PF_MPLS
#define AF_CAN PF_CAN
#define AF_TIPC PF_TIPC
#define AF_BLUETOOTH PF_BLUETOOTH
#define AF_IUCV PF_IUCV
#define AF_RXRPC PF_RXRPC
#define AF_ISDN PF_ISDN
#define AF_PHONET PF_PHONET
#define AF_IEEE802154 PF_IEEE802154
#define AF_CAIF PF_CAIF
#define AF_ALG PF_ALG
#define AF_NFC PF_NFC
#define AF_VSOCK PF_VSOCK
#define AF_KCM PF_KCM
#define AF_QIPCRTR PF_QIPCRTR
#define AF_SMC PF_SMC
#define AF_XDP PF_XDP
#define AF_MAX PF_MAX

在网络编程里,上述代码是一系列宏定义,它们主要用于指定套接字地址族(Address Family)。地址族明确了套接字通信所采用的网络协议或通信机制。下面详细解释其含义与作用。
宏定义的含义
在这些宏定义里,AF_ 开头代表地址族(Address Family),PF_ 开头代表协议族(Protocol Family)。在早期的 BSD 套接字实现中,这两者是有区别的,但在现代的大多数系统里,它们的值是相同的,所以可以互换使用。这些宏定义把一个有意义的符号常量和一个整数数值关联起来,便于在代码里使用。

  • 常见地址族及其用途
  1. 本地通信相关
    • AF_LOCAL(或 AF_UNIX、AF_FILE):用于 Unix 域套接字,主要实现同一台主机上不同进程之间的通信。它借助文件系统中的文件作为通信端点,性能较高,且有流式(SOCK_STREAM)和数据报(SOCK_DGRAM)两种通信模式。
    1
    2
    3
    4
    #include <sys/socket.h>
    #include <sys/un.h>
    // 创建 Unix 域流式套接字
    int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
  2. 互联网通信相关
    • AF_INET:代表 IPv4 协议族,是互联网上广泛使用的地址族,用于基于 IPv4 地址的网络通信,可搭配 TCP(SOCK_STREAM)或 UDP(SOCK_DGRAM)协议。
    1
    2
    3
    4
    #include <sys/socket.h>
    #include <arpa/inet.h>
    // 创建 IPv4 TCP 套接字
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    • AF_INET6:代表 IPv6 协议族,用于基于 IPv6 地址的网络通信,同样支持 TCP 和 UDP 协议,是为了应对 IPv4 地址枯竭问题而推出的新一代互联网协议。
    1
    2
    3
    4
    #include <sys/socket.h>
    #include <arpa/inet.h>
    // 创建 IPv6 UDP 套接字
    int sockfd = socket(AF_INET6, SOCK_DGRAM, 0);
  3. 其他网络协议相关
    • AF_BLUETOOTH:用于蓝牙通信,可让设备之间通过蓝牙协议进行数据传输,常用于无线耳机、蓝牙音箱等设备与手机或电脑的连接。
    1
    2
    3
    4
    5
    #include <sys/socket.h>
    #include <bluetooth/bluetooth.h>
    #include <bluetooth/rfcomm.h>
    // 创建蓝牙套接字
    int sockfd = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
    • AF_IRDA:用于红外通信,红外技术曾广泛应用于手机、遥控器等设备之间的短距离通信,但随着蓝牙和 Wi - Fi 等技术的发展,其使用逐渐减少。
  4. 系统内部通信相关
    • AF_NETLINK:用于内核空间和用户空间之间的通信,许多系统服务和工具会借助它与内核进行交互,例如 iproute2 工具就利用 AF_NETLINK 来配置网络接口。
    1
    2
    3
    4
    #include <sys/socket.h>
    #include <linux/netlink.h>
    // 创建 netlink 套接字
    int sockfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
    • 在 socket() 函数中的使用
    • 在创建套接字时,socket() 函数的第一个参数就是地址族,它决定了套接字使用的网络协议或通信机制。例如:
    1
    2
    3
    4
    5
    6
    7
    #include <sys/socket.h>
    // 创建一个 IPv4 TCP 套接字
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
    perror("socket creation failed");
    return -1;
    }
    • 在这个例子中,AF_INET 表明使用 IPv4 协议族,SOCK_STREAM 表示使用 TCP 协议进行流式传输,第三个参数 0 让系统自动选择合适的协议。
  5. 总结
    • 这些地址族宏定义为网络编程提供了丰富的选择,使开发者能够根据不同的应用场景选择合适的网络协议或通信机制来创建套接字。

函数解析

setsockopt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// setsockopt 是一个用于配置套接字选项的系统调用,通常用于调整套接字的行为和特性。在网络编程中,setsockopt 被广泛用于设置各种参数,以便优化网络通信或改变套接字的默认行为。
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);

// sockfd:要配置的套接字的文件描述符,通常是通过 socket 函数创建的。

// level:指定选项的协议级别。常用的值包括:
// SOL_SOCKET:用于套接字级别的选项。
// IPPROTO_TCP:用于 TCP 级别的选项。
// IPPROTO_IP:用于 IP 级别的选项。

// 以下是一些常见的 optname 参数及其说明:
// 套接字级别选项 (SOL_SOCKET)
// SO_REUSEADDR:允许重用本地地址。
// SO_KEEPALIVE:启用 TCP 保活功能。
// SO_BROADCAST:允许发送广播消息。
// SO_SNDBUF:设置发送缓冲区大小。
// SO_RCVBUF:设置接收缓冲区大小。
// SO_LINGER:设置关闭套接字时的延迟时间。
// SO_OOBINLINE:将紧急数据视为正常数据。
// TCP 级别选项 (IPPROTO_TCP)
// TCP_NODELAY:禁用 Nagle 算法。
// TCP_MAXSEG:设置最大报文段大小(MSS)。
// TCP_KEEPIDLE:设置 TCP 保活的空闲时间。
// TCP_KEEPINTVL:设置 TCP 保活探测之间的时间间隔。
// TCP_KEEPCNT:设置 TCP 保活探测的最大次数。
// IP 级别选项 (IPPROTO_IP)
// IP_TTL:设置 IP 数据包的生存时间(TTL)。
// IP_MULTICAST_IF:设置多播接口。
// IP_MULTICAST_TTL:设置多播数据包的 TTL。
// IP_MULTICAST_LOOP:控制多播循环。

// optval:指向选项值的指针,通常是一个整数或其他类型的数据。

// optlen:选项值的大小,以字节为单位。

// example
{
int optval = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(optval));
}
// 在 C 语言中,调用 setsockopt 函数设置不同的套接字选项时,每个调用都是独立的。也就是说,调用 setsockopt 设置 SO_KEEPALIVE 和 TCP_NODELAY 是相互独立的,互不影响。设置一个选项不会覆盖另一个选项。

listen

1
2
3
4
5
6
7
8
9
10
// listen 是一个用于在服务器端套接字上进行监听的系统调用。它使套接字准备接受传入的连接请求。通常在 TCP 服务器中使用。

int listen(int sockfd, int backlog);

// 参数说明
// sockfd:要监听的套接字文件描述符。这通常是通过 socket() 函数创建的,并通过 bind() 进行绑定的套接字。
// backlog:表示在套接字队列中等待连接的最大数量。如果有多个连接请求到达,但尚未被接受,那么这些请求将被放入等待队列中,直到被处理。该值通常设置为一个合理的数值(如 5 或 10),具体取决于应用程序的需求。
// 返回值
// 如果成功,返回 0。
// 如果失败,返回 -1,并设置 errno 以指示错误类型。

accept

1
2
3
4
5
6
7
8
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
// 参数
// sockfd: 监听套接字的文件描述符,通常是通过 socket 和 bind 函数创建的。
// addr: 指向一个 struct sockaddr 类型的结构体,用于存储客户端的地址信息。如果不需要地址信息,可以传递 NULL。
// addrlen: 指向 socklen_t 类型的变量,表示 addr 结构体的大小。accept 调用后,该变量将被更新为实际的地址长度。
// 返回值
// 成功时,返回一个新的套接字文件描述符,用于与连接的客户端进行通信。
// 失败时,返回 -1,并设置 errno 以指示错误。