TCP/IP网络协议栈分为四层, 从下至上依次是:
在链路层本身, 主要负责将数据跟物理层交互, 常见工作包括网卡设备的驱动, 帧同步(检测什么信号算是一个新帧), 冲突检测(如果有冲突就自动重发), 数据差错校验等工作。
链路层常见的有以太网, 令牌环网的标准。
网络层
网络层的IP协议是构成Internet的基础。该层次负责将数据发送到对应的目标地址, 网络中有大量的路由器来负责做这个事情, 路由器往往会拆掉链路层和网络层对应的数据头部并重新封装。IP层不负责数据传输的可靠性, 传输的过程中数据可能会丢失, 需要由上层协议来保证这个事情
传输层
网络层负责的是点到点的协议, 即只到某台主机, 传输层要负责端到端的协议, 即要到达某个进程。
典型的协议有TCP/UDP两种协议, 其中TCP协议是一种面向连接的, 稳定可靠的协议, 会负责做数据的检测, 分拆和重新按照顺序组装, 自动重发等。而UDP就只负责将数据送到对应进程, 几乎没有任何逻辑, 也就是说需要应用层自己来保证数据传输的可靠性。
在网络通信过程中, 源主机的应用程序只知道目的应用程序的IP地址, 并不知道对方主机的硬件地址, 所以在数据发送之前, 需要先找到目标及其的硬件地址, 这就是ARP协议所起的作用了。
每次在建立连接之前, 会在本地网络广播发送目的IP地址, 所有机器都会受到该请求, 目的机器发现该请求中的IP地址跟自己一样, 就把自己的硬件地址返回回去, 否则忽略该请求。
一般来说, 每台机器都维护的有一个ARP缓存表, 存储了近期的IP地址和硬件地址的映射关系, 可以用arp -a命令来查看缓存表中内容。
如果目的机器和本机器不在同一个网段之内的话, 会将数据发送给网关来处理, 一般网关就是路由器, 此时网关会进行IP路由, 将ARP请求发送到目的网络地址, 然后再依次将应答返回给该发起请求的机器。
IP地址的一共分为如下几类:
在互联网刚出来的时候, 大部分组织都申请的B类网络地址, 导致B类地址很快就用完了, 但是A类又有很多空闲的地址, 而每个路由器又必须掌握所有网络的信息, 随着C类网络的增多, 路由器中的路由表项数也就越来越多了。
针对这种情况, 后来人们发现, 绝大部分内部网络的机器都不需要一个独立的公网IP的, 这些机器通过一个公网IP跟外部连接, 在自己的网络内部为每台机器申请一个私有IP, 内部再建设一个路由器, 做内网IP地址的定位即可。
私有IP的出现大大解决了IP浪费的问题, 所以我们日常中可以看到很多如192.168.xx这样的IP, 这些IP都只是局域网内部IP, 不会浪费IP地址。
RFC1918就规定了组建局域网的私有IP地址规范:
除了私有IP之外, 还有几种特殊的IP地址:
交互过程:
上图中每次连接线上的数字标记了此次数据包中的关键信息, 比如
如上讲的都是一来一回的交互, 一般情况下可能会存在一方数据发得特别快, 另一方数据发得特别慢, 这种时候如果不做控制, 势必会让慢的这方数据处理不过来从而导致丢包。
TCP协议中采用了滑动窗口协议来解决该问题, 类似上面的mss, 再增加一个新的选项win, 告诉对方自己的滑动窗口大小, 对方在发送数据的时候每次发送数据就知道对方到底窗口空间还够不够, 如果不够了就不发了, 从而解决了一快一慢这种问题。
其他状态都还好, 在工作中常会碰到TIME_WAIT连接过多的问题, 这里把TIME_WAIT状态单独拿出来说一下。
TIME_WAIT是主动关闭方在收到被动关闭方发的FIN包之后处于的状态, 这个包是主动关闭方收到的最后一个包了, 在收到这个包之后还不能直接就把连接给关闭了, 还得等待一段时间才能关闭, 等待时间为2MSL。
为什么要等待一段时间呢? 主要是两个原因:
所以一定要有一个TIME_WAIT的状态等待一段时间, 等待的MSL时间RFC上面建议是2分钟, 但是笔者实际工作中测试往往是30秒。
但是如果你的服务是一个高并发短连接服务, TIME_WAIT可能会导致连接句柄被大量占用, 而你又相信服务内部是一个非常稳定的网络服务, 或者即使有两个连接交互出现故障也可以接受或者有应用层处理, 不希望有那么多的TIME_WAIT状态的连接, 一般有两种方式:
然后执行/sbin/sysctl -p生效参数。
UDP协议就简单很多了, 基本上就只包含源地址, 目的地址, 长度, 校验, 数据。
交互过程也不再像TCP这样经过很复杂的建立连接和关闭连接的过程了, 就直接每次都发送数据了, 这样会有如下的一些问题: