类型
- 基于网络协议的套接字类型
- 流式套接字(TCP Socket,SOCK_STREAM)
- 特点: 面向连接:在进行数据传输之前,需要先建立连接,传输完成后再断开连接。连接的建立和断开遵循特定的握手协议,例如 TCP 的三次握手和四次挥手。
- 可靠传输:通过确认机制、重传机制和滑动窗口协议等,保证数据在传输过程中不会丢失、重复或乱序,确保数据的完整性和顺序性。
- 字节流传输:数据以字节流的形式进行传输,就像水流一样连续不断,发送方可以连续发送数据,接收方可以按顺序接收数据。
- 使用场景:适用于对数据传输可靠性要求较高的场景,如文件传输(FTP)、网页浏览(HTTP)、电子邮件(SMTP、POP3、IMAP)等。
- 数据报套接字(UDP Socket,SOCK_DGRAM)
- 特点: 无连接:在发送数据之前不需要建立连接,直接将数据报发送到目标地址。因此,它的通信效率较高,开销较小。
- 不可靠传输:不保证数据的可靠到达,也不保证数据的顺序性。数据可能会丢失、重复或乱序,但传输速度相对较快。
- 数据报传输:数据以独立的数据报形式进行传输,每个数据报都包含完整的目标地址和源地址信息,接收方根据数据报的头部信息进行接收和处理。
- 使用场景:适用于对实时性要求较高,对数据准确性要求相对较低的场景,如实时音视频传输(如 VoIP、在线直播)、游戏网络通信等。
- 原始套接字(SOCK_RAW)
- 特点: 直接访问网络层:可以绕过传输层协议(如 TCP 和 UDP),直接对网络层数据包进行操作。这使得开发者可以自定义数据包的头部信息,实现一些特殊的网络功能。
- 高级网络编程:需要对网络协议有深入的了解,使用起来相对复杂。
- 使用场景:常用于网络协议分析、网络安全工具开发(如网络嗅探器、防火墙等)以及实现一些特殊的网络应用,如 ICMP 协议的应用程序。
- 基于通信范围的套接字类型
- 网络套接字
- 特点:用于不同主机之间的网络通信,通过网络协议(如 IP 协议)进行数据传输。可以跨越局域网、广域网等不同的网络范围。
- 使用场景:上述的 TCP 套接字和 UDP 套接字都属于网络套接字,广泛应用于互联网上的各种通信场景。
- Unix 域套接字(Unix Domain Socket)
- 特点
- 本地进程间通信:仅用于同一主机上不同进程之间的通信,不涉及网络协议栈,因此通信效率更高,延迟更低。
- 文件系统接口:通过文件系统中的文件作为通信端点,使用起来类似于网络套接字,但更加简单和高效。
- 支持流式和数据报两种模式:可以选择使用面向连接的流式模式(SOCK_STREAM)或无连接的数据报模式(SOCK_DGRAM)。
- 使用场景:适用于同一主机上不同进程之间的高效通信,如数据库服务器与客户端之间的通信、系统服务之间的交互等。
- 其他特殊套接字类型
- 可靠数据报套接字(SOCK_RDM)
- 特点:结合了 UDP 的无连接特性和 TCP 的可靠传输特性,提供可靠的数据报传输服务。但在实际应用中使用相对较少。
- 使用场景:在一些对实时性和可靠性都有一定要求的场景中可能会使用,但由于实现复杂,应用范围有限。
- 顺序包套接字(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 套接字实现中,这两者是有区别的,但在现代的大多数系统里,它们的值是相同的,所以可以互换使用。这些宏定义把一个有意义的符号常量和一个整数数值关联起来,便于在代码里使用。
- 本地通信相关
- 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);
|
- 互联网通信相关
- 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);
|
- 其他网络协议相关
- 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 等技术的发展,其使用逐渐减少。
- 系统内部通信相关
- 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 让系统自动选择合适的协议。
- 总结
- 这些地址族宏定义为网络编程提供了丰富的选择,使开发者能够根据不同的应用场景选择合适的网络协议或通信机制来创建套接字。
函数解析
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
| int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
{ int optval = 1; setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(optval)); }
|
listen
1 2 3 4 5 6 7 8 9 10
|
int listen(int sockfd, int backlog);
|
accept
1 2 3 4 5 6 7 8
| int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
|