unix网络编程卷1_套接字联网API

UNIX网络编程卷1:套接字联网API

2. 传输层:TCP、UDP、SCTP

TCP状态转换图,全书最重要的图之一

UNIX网络编程第二章

3. 套接字编程简介

以下是UNIX网络编程卷一上的图,查看Linux 这几个地址的定义,有些许差别,Linux的定义如下:

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
// /usr/include/netinet/in.h
struct sockaddr_in
{
__SOCKADDR_COMMON (sin_);
in_port_t sin_port; /* Port number. */
struct in_addr sin_addr; /* Internet address. */

/* Pad to size of `struct sockaddr'. */
unsigned char sin_zero[sizeof (struct sockaddr)
- __SOCKADDR_COMMON_SIZE
- sizeof (in_port_t)
- sizeof (struct in_addr)];
};

/* Structure describing an Internet socket address. */
struct sockaddr_in
{
__SOCKADDR_COMMON (sin_);
in_port_t sin_port; /* Port number. */
struct in_addr sin_addr; /* Internet address. */

/* Pad to size of `struct sockaddr'. */
unsigned char sin_zero[sizeof (struct sockaddr)
- __SOCKADDR_COMMON_SIZE
- sizeof (in_port_t)
- sizeof (struct in_addr)];
};

/* Ditto, for IPv6. */
struct sockaddr_in6
{
__SOCKADDR_COMMON (sin6_);
in_port_t sin6_port; /* Transport layer port # */
uint32_t sin6_flowinfo; /* IPv6 flow information */
struct in6_addr sin6_addr; /* IPv6 address */
uint32_t sin6_scope_id; /* IPv6 scope-id */
};

4. 基本TCP套接字编程

内核为每一个监听套接字维护两个队列:

相关知识: 半连接攻击

6. IO复用:select和poll函数

5种IO模型(这部分小林的图解系列图更好)

一个输入操作包括2个不同的阶段:

  • 等待数据准备好
  • 从内核向进程复制数据

一个非阻塞描述符循环调用recvfrom时,我们称之为轮询。该操作大量消耗CPU时间。

IO多路复用同样是阻塞式的,不过它阻塞在IO复用系统调用上,如select、poll以及epoll,而不是阻塞在真正的IO系统调用上。注意,数据从内核复制到用户空间的那段时间,应用也是阻塞的。

信号驱动式IO模型暂未发现可用场景,就不放图了。

以上所有的IO模型,均为同步IO。

POSIX异步IO框架aio系列已经过时了,在Linux平台,可以使用从Linux内核5.1开始的io_uring异步框架。

注意,IO多路复用是在收到数据时触发读事件,通知上层应用,此时需要将数据复制到用户空间。而异步IO是收到数据,并且将数据从内核复制到了用户空间后,再通知应用处理数据。

五种IO模型的比较:

shutdown函数:

终止网络连接的一般方法是调用close函数,不过close有两个限制,如下:

  • close将描述符的引用计数减1,仅在该计数变为0时才关闭套接字。
  • close终止读和写两个方向的数据传输。

而shutdown函数,既可以不管引用计数就激发TCP的正常连接终止序列,也可以处理如下这种场景:

我们需要告知对端我们已经完成了数据发送,即使对端仍有数据要发送给我们。

理解为什么一定要四次挥手。

  • SHUT_RD:关闭读。套接字接收缓冲区的现有数据将被丢弃
  • SHUT_WR:关闭写,TCP称为半关闭。套接字发送缓冲区的现有数据将被发送
  • SHUT_RDWR:读写关闭

陈硕的muduo网络库中,即使用了TCP的半关闭功能。

1
2
3
4
5
6
7
8
// muduo/net/SocketsOps.cc
void sockets::shutdownWrite(int sockfd)
{
if (::shutdown(sockfd, SHUT_WR) < 0)
{
LOG_SYSERR << "sockets::shutdownWrite";
}
}

8. 基本UDP套接字编程

11. 名字与地址转换

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
# cmd:
# -----------------------------------------------------------
resolvectl status
# -----------------------------------------------------------
# output:
Global
LLMNR setting: no
MulticastDNS setting: no
DNSOverTLS setting: no
DNSSEC setting: no
DNSSEC supported: no
DNSSEC NTA: 10.in-addr.arpa
16.172.in-addr.arpa
168.192.in-addr.arpa
17.172.in-addr.arpa
18.172.in-addr.arpa
19.172.in-addr.arpa
20.172.in-addr.arpa
21.172.in-addr.arpa
22.172.in-addr.arpa
23.172.in-addr.arpa
24.172.in-addr.arpa
25.172.in-addr.arpa
26.172.in-addr.arpa
27.172.in-addr.arpa
lines 1-20...skipping...

同时支持IPv4与IPv6的转换函数:

头文件:<netdb.h>

创建一个TCP套接字并连接到一个服务器:

12. IPv4与IPv6的互操作性

拓展: 当数据流路径是 IPv6通道 –> IPv4通道 –>IPv6(通道)时,将采用隧道技术。

总结: IPv6 对 IPv6,IPv4 对 IPv4, IPv4 对 IPv6 采用映射。

关于黄色标注处:若客户选择AAAA记录从而发送IPv6数据,则不能工作。若选择A记录, 则A记录实际作为一个IPv4映射的IPv6地址返回给客户,使得客户可以发送IPv4数据。

14. 高级IO函数

这两个函数是最重要的函数之一,因为最通用。具体的使用,可以查看vector AP底层网络通信部分的代码。

15. unix域套接字

unix域提供两类套接字:字节流套接字(类似于TCP)和数据报套接字(类似于UDP)。

使用unix域套接字的三个理由:

  • 使用socket API,但不经过TCP/IP协议栈,快
  • 可以在两个进程之间传递描述符
  • 可以传递凭证,是服务器验证客户身份的可靠手段

unix域中用于标识客户与服务器的协议地址是普通文件系统中的路径名(绝对路径)。

socketpair函数可以用于网络服务器中的唤醒工作,除了该方式外,还可以使用管道或者eventfd方案。

指定SOCK_STREAM的socketpari称为流管道,是全双工通信方式。

注意:因为unix域套接字的地址是一个绝对路径,因此在bind地址之前,一定要确认路径文件是否存在,若存在,一定要先通过unlink清除路径文件。

16. 非阻塞式IO

Pass

20. 广播

21. 多播

单播地址标识单个IP接口,广播地址标识某子网的所有IP接口,多播地址标识一组IP接口。

广播一般局限于局域网内使用,多播既可以用于局域网,也可以跨广域网使用。

单播使用MAC地址,广播的MAC地址为 FF-FF-FF-FF-FF-FF,多播的MAC地址为:01-00-5e-0 + 低序23位,这三者是不同的。

一个进程接收某个多播数据包的先决条件是:该进程加入相应的多播组并绑定相应的端口

IPv4首部的TTL字段兼用作多播范围字段。

  • 0:接口局部,不能由接口输出
  • 1:链路局部,不可由路由器转发
  • 其他不再赘述,看图

关于不完备过滤与完备过滤:目前多播地址是224.0.0.1,若有一个多播地址225.0.1.1发送数据。由于多播地址组ID的高5位在到以太网地址的映射中被忽略,该主机的接口也将接收目的以太网地址为01:00:5e:00:01:01的帧。因此在数据链路层无法过滤掉,所以说数据链路层是不完备过滤。这种情况下,该帧承载的分组将在IP层完备过滤,IP层会比较该地址与本机接收应用进程已经加入的所有多播地址,根据结果是接收还是丢弃。因此该分组将被丢弃。

多播套接字选项:采用getsockoptsetsockopt,相关选项如下:

如果发送UDP多播之前,没有指定影响发送的多播套接字选项,那么UDP的外出接口将有内核选择,TTL或跳限将为1,并有一个副本自环回来。

附录A

IP层提供无连接不可靠的数据报递送服务。

IP层最重要的功能之一是路由

IPv4首部最大长度为60字节,固定部分20字节,选项部分,最长40字节。

协议字段中,1代表ICMPv4、2代表IGMPv4、6代表TCP、17代表UDP。

IPv6首部最大长度为40字节,没有选项。

下一个首部:6代表TCP、17代表UDP、58代表ICMPv6等

跳限类似于IPv4中的TTL


unix网络编程卷1_套接字联网API
http://ziyangfu.github.io/2023/07/21/unix网络编程卷1-套接字联网API/
作者
FZY
发布于
2023年7月21日
许可协议