Network Socket 怎么负责更多的链接

一台服务器理论最大链接数:

{本机IP, 本机端口, 对端IP, 对端端口}

服务器通常固定在某个本地端口上监听,等待客户端的连接请求。因此,服务端端 TCP 连接四元组中只有对端 IP, 也就是客户端的 IP 和对端的端口,也即客户端的端口是可变的,因此,最大 TCP 连接数 = 客户端 IP 数×客户端端口数。对 IPv4,客户端的 IP 数最多为 2 的 32 次方,客户端的端口数最多为 2 的 16 次方,也就是服务端单机最大 TCP 连接数,约为 2 的 48 次方

当然,服务端最大并发 TCP 连接数远不能达到理论上限。首先主要是文件描述符限制,按照上面的原理,Socket 都是文件,所以首先要通过 ulimit 配置文件描述符的数目;另一个限制是内存,按上面的数据结构,每个 TCP 连接都要占用一定内存,操作系统是有限的。

  1. 创建子进程(建立一个子公司)
  2. 创建更多的线程(在公司成立多个项目组)
  3. 每个项目组负责多个项目(采用轮询管理项目的进度)
    • 由于 Socket 是文件描述符,因而某个线程盯的所有的 Socket,都放在一个文件描述符集合 fd_set 中,这就是项目进度墙,然后调用 select 函数来监听文件描述符集合是否有变化。一旦有变化,就会依次查看每个文件描述符。那些发生变化的文件描述符在 fd_set 对应的位都设为 1,表示 Socket 可读或者可写,从而可以进行读写操作,然后再调用 select,接着盯着下一轮的变化。
  4. 每个项目组负责多个项目(采用主动报告方式报告项目的进度)
    • 如果改成事件通知的方式,情况就会好很多,项目组不需要通过轮询挨个盯着这些项目,而是当项目进度发生变化的时候,主动通知项目组,然后项目组再根据项目进展情况做相应的操作。
    • 能完成这件事情的函数叫 epoll,它在内核中的实现不是通过轮询的方式,而是通过注册 callback 函数的方式,当某个文件描述符发送变化的时候,就会主动通知。因而,epoll 被称为解决 C10K 问题的利器。

Network Socket 与文件描述符

说 TCP 的 Socket 就是一个文件流,是非常准确的。因为,Socket 在 Linux 中就是以文件的形式存在的。

除此之外,还存在文件描述符。写入和读出,也是通过文件描述符。

在内核中,Socket 是一个文件,那对应就有文件描述符。

每一个进程都有一个数据结构 task_struct,里面指向一个文件描述符数组,来列出这个进程打开的所有文件的文件描述符。

文件描述符是一个整数,是这个数组的下标。这个数组中的内容是一个指针,指向内核中所有打开的文件的列表。

既然是一个文件,就会有一个 inode,只不过 Socket 对应的 inode 不像真正的文件系统一样,保存在硬盘上的,而是在内存中的。

在这个 inode 中,指向了 Socket 在内核中的 Socket 结构。在这个结构里面,主要的是两个队列,一个是发送队列,一个是接收队列。在这两个队列里面保存的是一个缓存 sk_buff。这个缓存里面能够看到完整的包的结构。

Network Socket 套接字

在建立 Socket 的时候,应该设置什么参数呢?Socket 编程进行的是端到端的通信,往往意识不到中间经过多少局域网,多少路由器,因而能够设置的参数,也只能是端到端协议之上网络层和传输层的。

在网络层,Socket 函数需要指定到底是 IPv4 还是 IPv6,分别对应设置为 AF_INET 和 AF_INET6。

另外,还要指定到底是 TCP 还是 UDP。还记得咱们前面讲过的,TCP 协议是基于数据流的,所以设置为 SOCK_STREAM,而 UDP 是基于数据报的,因而设置为 SOCK_DGRAM。

基于tcp socket 函数调用过程

  1. 服务器调用bind 函数开启一个端口进行监听,当一个网络包来的时候,内核要通过 TCP 头里面的这个端口,来找到你这个应用程序,把包给你。为什么要 IP 地址呢?有时候,一台机器会有多个网卡,也就会有多个 IP 地址,你可以选择监听所有的网卡,也可以选择监听一个网卡,这样,只有发给这个网卡的包,才会给你。
  2. 当服务端有了 IP 和端口号,就可以调用 listen 函数进行监听。在 TCP 的状态图里面,有一个 listen 状态,当调用这个函数之后,服务端就进入了这个状态,这个时候客户端就可以发起连接了。在内核中,为每个 Socket 维护两个队列。一个是已经建立了连接的队列,这时候连接三次握
  3. 在内核中,为每个 Socket 维护两个队列。一个是已经建立了连接的队列,这时候连接三次握手已经完毕,处于 established 状态;一个是还没有完全建立连接的队列,这个时候三次握手还没完成,处于 syn_rcvd 的状态。
  4. 接下来,服务端调用 accept 函数,拿出一个已经完成的连接进行处理。如果还没有完成,就要等着。
  5. 在服务端等待的时候,客户端可以通过 connect 函数发起连接。先在参数中指明要连接的 IP 地址和端口号,然后开始发起三次握手。内核会给客户端分配一个临时的端口。一旦握手成功,服务端的 accept 就会返回另一个 Socket
    • 这是一个经常考的知识点,就是监听的 Socket 和真正用来传数据的 Socket 是两个,一个叫作监听 Socket,一个叫作已连接 Socket。
  6. 连接建立成功之后,双方开始通过 read 和 write 函数来读写数据,就像往一个文件流里面写东西一样。

基于 udp socket 函数调用过程

对于 UDP 来讲,过程有些不一样。UDP 是没有连接的,所以不需要三次握手,也就不需要调用 listen 和 connect,但是,UDP 的交互仍然需要 IP 和端口号,因而也需要 bind。UDP 是没有维护连接状态的,因而不需要每对连接建立一组 Socket,而是只要有一个 Socket,就能够和多个客户端通信。也正是因为没有连接状态,每次通信的时候,都调用 sendto 和 recvfrom,都可以传入 IP 地址和端口。

Network 路由网关与协议

  • 根据路由规则转发数据包的三层设备
    • 转发网关(不修改源IP 和目的MAC 地址)
    • NAT 网关 (修改源IP 和目的MAC 地址)
  • 路由策略与策略路由
    • 除了可以根据目的 ip 地址配置路由外,还可以根据多个参数来配置路由,这就称为策略路由。
    • 一条路由规则中可以包括多条路径例如:
      • ip route add default scope global nexthop via 100.100.100.1 weight 1 nexthop via 200.200.200.1 weight 2
  • 一条路由规则至少包括以下3个信息
    • 目的网络:这个包想去哪儿?
    • 出口设备:将包从哪个口扔出去?
    • 下一跳网关:下一个路由器的地址。
    • 核心思想是根据目的IP 来配置路由
  • 路由协议要在路由器之间交换信息,这些信息的交换还需要走路由吗?不是死锁了吗?
  • 路由器之间信息的交换使用什么协议呢?报文格式是什么样呢?

Network ICMP 协议与Ping 、 Traceroute

  1. icmp 分为 查询报文与有差错控制报文
  2. ping 使用查询报文,traceroute 使用差错报文
  3. 查询报文有 ICMP ECHO REQUEST 与 ICMP ECHO REPLY,查询的类型为8,应答的报文为0
  4. 差错报文:
    • 终点不可达
      • 网络不可达 (没找到地方)
      • 主机不可达 (找到地方没找到人)
      • 协议不可达 (找到地方,找到人,语言不通)
      • 端口不可达 (找到地方,找到人,要说的事情对不上)
      • 分片错误 (因为过程中策略限制,无法送达)
    • 源站抑制 (告诉发送方减小发送的数量)
    • 时间超时 (超过网络包的生存时间)
    • 路由重定向(告诉发送方下次走另外一条路线)

Traceroute 的第一个作用就是故意设置特殊的 TTL,来追踪去往目的地时沿途经过的路由器。Traceroute 的参数指向某个目的 IP 地址,它会发送一个 UDP 的数据包。将 TTL 设置成 1,也就是说一旦遇到一个路由器或者一个关卡,就表示它“牺牲”了。如果中间的路由器不止一个,当然碰到第一个就“牺牲”。于是,返回一个 ICMP 包,也就是网络差错包,类型是时间超时

Traceroute 还有一个作用是故意设置不分片,从而确定路径的 MTU。要做的工作首先是发送分组,并设置“不分片”标志。发送的第一个分组的长度正好与出口 MTU 相等。

报文类型类型代码描述
目的不可达3当数据包无法到达目的地时发送,例如网络不可达、主机不可达、协议不可达、端口不可达等
超时11当数据包的 TTL(生存时间)字段降为 0 时发送,或分片重组超时
参数问题12当 IP 数据包中的参数有问题时发送,例如 IP 头部中的某些字段值无效
重定向5当路由器发现一个更有效的路由时发送,建议发送方使用更短的路径
回显请求8用于测试目的主机的可达性和响应时间,发送方发送回显请求
回显应答0对回显请求的响应,确认目的主机的可达性
时间戳请求13用于请求目的主机的时间戳信息,以便同步网络设备的时钟
时间戳应答14对时间戳请求的响应,包含目的主机的时间戳信息
信息请求15请求目的主机的特定信息
信息应答16对信息请求的响应
路由器通告(IPv6)9用于 IPv6,由路由器发送给邻近节点,提供网络配置信息
路由器请求(IPv6)10用于 IPv6,由节点发送给路由器,请求网络配置信息
邻居通告(IPv6)135用于 IPv6,通告节点的可达性
邻居请求(IPv6)133用于 IPv6,请求邻居节点的信息
重定向消息(IPv6)134用于 IPv6,类似于 IPv4 的重定向报文,但用于 IPv6 环境