聊点实在的:计算机网络到底是个啥?
先别急着背那七层模型。学网络这么多年,我最怕听到的问题就是“计算机网络是啥”。教科书上会告诉你:网络是若干节点和链路的集合,实现资源共享和数据通信。这话没毛病,但你听完依然啥也不会。今天咱们换个聊法,不讲教科书,讲实在的。
计算机网络本质上是一套“在不可靠的现实世界里,用一堆约定俗成的协议,把数据从一台机器安全、有序、高效地搬到另一台机器”的工程方案。你每天刷网页、发消息、看视频,背后全是这套方案在兜底。这篇文章适合三类人:准备考408但被谢希仁和王道折磨得昏天黑地的学生,刚入门DevOps需要补网络短板的工程师,以及单纯好奇“为什么我家的Wi-Fi一会儿好一会儿坏”的普通人。我会尽量少用术语,用到术语也一定给你解释明白,因为整件事说到底没那么玄乎。
1. 先把“网络是什么”这件事掰扯清楚
1.1 网络不是一堆硬件,而是一套“约定”
很多人理解网络,第一个想到的是路由器、交换机、网线、光纤。这些确实是硬件,但硬件本身没有意义。就像你有一堆快递员和货车,但没有一套收件地址规则、没有分拣流程、没有签收标准,这堆东西也送不了快递。
网络的价值全在协议上。所谓协议,就是通信双方共同遵守的规则——你发过来的数据什么格式、我该怎么回应、传输过程中出错怎么办、速率快慢怎么协商,全部由协议规定。最常见的比喻是把协议比作语言:中国人用中文交流,法国人用法语,两边都能听懂的前提是双方约定用同一种语言或者有翻译。互联网的聪明之处在于,它用一个“分层”的方案,让世界上所有品牌的路由器、手机、服务器,只要遵守同一套协议,就能互相通信,互相之间甚至不需要知道对方用什么芯片、跑什么系统。
这里有个特别重要的视角:网络不是把两台电脑用线连起来就完事,而是要解决一连串问题。数据从你的手机出发,要经过Wi-Fi、光猫、小区交换机、城域网、骨干网,最后到达远在几千公里外的服务器。沿途每一段链路的带宽不一样,丢包率不一样,延迟不一样。数据到了服务器,还要保证顺序对了、内容没损坏、没被黑客掉包。这一整套问题,才是网络这门学科真正要处理的东西。
1.2 你其实天天在用网络,只是没意识到
我举个最常见的场景。你在浏览器里输入一个网址,回车,页面出来了。就这么一个动作,背后的网络在几毫秒内至少做完了下面几件事:先查这个域名对应的IP地址(DNS解析),然后建立到服务器的连接(TCP握手或者QUIC握手),服务器处理请求返回内容,浏览器再把它渲染出来。每一件事都涉及不同的协议,这些协议互相配合,就像一条流水线。
再比如你打开手机连Wi-Fi,手机会先发请求找无线接入点,接入点回应后,手机再去问“我该用什么IP地址”,然后路由器分配一个地址,接下来还会确认这个地址没有别人在用。这一串操作全部发生在你点“连接”之后的几秒钟内,你感知不到,但每一步都可能出问题,出问题的方式也五花八门——密码错误、DHCP分配失败、IP地址冲突、DNS未响应。这些故障如果你不懂网络,就只能重启路由器;如果懂网络,命令行里敲几个命令就能定位到具体是哪一步卡住了。
还有个细节,现在很多人会看到“我们的系统检测到您的计算机网络中存在异常流量,请稍后重新发送请求”这种提示。这个提示本身就是一个网络层面的安全策略——系统检测到某个IP在短时间内发起了大量请求,触发了频率限制或者人机校验,它背后的逻辑就是:一层防护机制在帮助你识别“请求方到底是人还是程序”。理解了网络,你就知道这不是玄学,而是流量控制与安全防护的常见手段。
2. 站在应用层往底层看:先搞懂你天天打交道的几个名词
2.1 IP地址、子网掩码、网关:一台电脑接入网络的真实过程
你打开电脑上的网络设置,经常能看到一堆数字:IP地址、子网掩码、默认网关。这仨是啥?我用最直白的话给你捋一遍。
IP地址就是你在网络世界里的门牌号,IPv4长这样:192.168.1.100,它由32位二进制组成,为了好记才写成四个十进制数。这个地址在网络里必须是“当前可见范围内”唯一的,不然数据就不知道该送给谁。子网掩码的作用是切分“哪些IP和我住同一栋楼”,比如255.255.255.0表示前三位相同的IP都在本楼,也就是同一个子网。在同一栋楼里通信,直接喊就行,不需要出门;不同楼的通信,才需要把数据交给网关,也就是楼下的保安兼快递中转站。
默认网关是你访问外部世界的“出门通道”。数据包的目的地址如果和你的子网掩码匹配不上,就默认扔给网关,让网关拿去路由器做下一步转发。所以你会看到,大多数家庭网络的默认网关是192.168.1.1之类,因为那正是你家路由器的地址。
那这些配置是从哪来的?手动敲的当然可以,但绝大多数时候是用DHCP自动获取的。你的设备开机后发一个广播:“有没有人可以给我分配一个IP?”路由器回应“你用它吧”,设备再用这个IP确认一下“有人用吗?没人用我就定了”。这一整套流程基本上在1秒内跑完。如果哪天你看到“IP地址冲突”的报错,多半是网络里有两台设备被分到了同一个IP,老设备说“这是我”,新设备说“凭什么”,通信就乱了。
2.2 DNS和HTTP:从输入网址到看到页面,到底发生了什么
你输入网址,这个操作对计算机来说其实是“我要访问某个IP地址的某个端口上的某个资源”。但你不可能也没必要记住一串数字,于是DNS(域名系统)出现了。DNS就像手机里的通讯录:你喊一声“老王”,它翻译成王先生的电话号码。在网络世界里,“老王”就是域名,“电话号码”就是IP地址。
整个翻译过程是分层的。浏览器先查本地DNS缓存,没有再查系统的hosts文件,还没有就去问配置的DNS服务器(通常是你家路由器或者运营商给的),一问就是一连串的迭代查询,最后拿到目标网站的IP。这里有个值得注意的坑:如果你的DNS服务器响应慢或者被污染,哪怕网速再快,打开页面也会卡半天。我遇到过一次很经典的问题,某网站图片加载极慢,排查半天发现是DNS解析超时,换了一个公共DNS秒开。
拿到IP之后,浏览器开始发HTTP请求。HTTP协议干的事很单纯:浏览器对服务器说“我想要这个资源”,服务器回一句“给你,这是内容”,或者“找不到”。它明文传输的特点在早期没问题,但后来大家都意识到隐私问题,于是有了HTTPS——在HTTP外面套了一层加密传输(TLS/SSL)。这层加密做的事,就是把“大家好”这种所有人都听得到的对话,变成只有你俩听得懂的悄悄话。它同时还附赠一个证书体系,让你可以确认对面真是你想访问的那个网站,而不是冒充的。
2.3 这一层才是DevOps和普通开发者真正需要“背”下来的东西
我说句实在话:对大部分开发者和DevOps工程师来说,你不需要把TCP的拥塞控制算法背得烂熟,但上面这几个名词你最好能懂——因为它们是你排查线上故障的基础。HTTP状态码你得认识:200是正常返回,301/302是重定向,403是没权限,404是不存在,500是服务器内部错误,502是网关出问题,503是服务暂不可用,504是网关超时。这些状态码就像医生的诊断信号,一眼看过去你就能大致判断问题出在前端还是后端、出在代理还是出在源站。
网络不通的时候,你也要能快速判断是哪一层的问题。打开命令行,先ping一下目标IP,通不通?通的话说明网络层没问题;再试试telnet域名端口,端口通不通?通的话说明传输层没问题;最后用curl把请求打过去,看看返回值是什么。从下往上逐层排查,这是网络排查的基本功,也是我强烈建议你用一分钟就能学会并立刻上手的技能。
3. TCP和UDP:为什么程序员总把“可靠传输”挂在嘴边
3.1 三次握手到底在做什么
TCP的三次握手,可能是计算机网络里被问得最多、也最容易被背成“仪式”的东西。很多人会背:客户端发SYN,服务器回SYN+ACK,客户端再回ACK,连接建立。但为什么要这么折腾?我用一个生活例子给你讲透。
假设你想约朋友去爬山。你发信息问:“周末去爬山吗?”(第一次握手,SYN)。朋友回:“行,周末去。”(第二次握手,SYN+ACK)。你收到后回:“好嘞,那周末见。”(第三次握手,ACK)。为什么不能两次就完事?因为朋友回“周末去”之后,他并不知道你收到没有——万一你没收着,以为人家没答应,就会再问一遍,对面就崩溃了。三次握手的关键作用,是让双方都确认“我能收到你发的,你也能收到我发的”,这样两边才敢开始传正式数据。
我见过不少人混淆了一个概念:以为TCP是“传得快”的。其实恰恰相反,TCP为了可靠,付出了很大的效率代价。它要排序、要去重、要确认、要重传,还要控制发送速率,这一切都建立在连接之上。所以TCP适合的场景是:文件传输、网页浏览、邮件收发,这些应用永远把“内容完整准确”放在第一位,速度慢一点可以接受。
3.2 滑动窗口与拥塞控制:公路上堵车怎么办
TCP还有一个有意思的机制,叫滑动窗口。滑动窗口解决的是“发送方能不能一次发一大坨数据”的问题。如果主机只能发一个包、等一个确认,那延迟得多大?所以TCP允许你连续发一批包,发送的数量由一个“窗口”限制,这个窗口大小会变化。我发送窗口是4,那我发4个包可以不用等确认;收到确认后窗口继续往前滑,接着发后面的。这个机制大大提高了链路利用率,但它也带来一个隐患——如果网络本身就堵,你还拼命发,大家全堵死。
于是TCP又搞了拥塞控制。中文核心思想就一句话:先小步试探,发现路好走就大胆提速,发现堵车就立刻降速。刚开始发1个包,确认收到后加倍到2个、4个……这叫慢启动。等到了一定阈值,不再翻倍,而是加1缓慢增长,这叫拥塞避免。一旦发生丢包,就认为是网络拥堵的信号,赶紧把发送速率降下来。这一整套机制特别像早晚高峰开车:路况好的时候一脚油门,看到前车刹车灯亮了就赶紧减速,但也不能刹死,不然后面的车全撞上。
还有个概念叫超时重传。发送方发了个包,迟迟等不到确认,就认为丢了,重新发一遍。这里有个细节:等多久算超时?等短了容易误判,网络只是慢,结果瞎重发导致更堵;等长了又浪费时间。实际实现里这个超时时间不是固定的,会根据网络状况动态调整,这就是RTO(重传超时时间)的计算逻辑。考试要记住,工程上也经常因为RTO配置不合理导致各种诡异的“网络抖动”。
3.3 UDP和它的新朋友QUIC
TCP可靠但笨重,UDP简单但不管不顾。UDP发出去就完了,不保证到达、不保证顺序、不保证不重复,连“连接”这个概念都没有。那它有什么用?直播、语音、视频通话,这些场景讲究“新数据比旧数据重要”——你视频通话卡顿了一下,旧画面补发过来也没意义,大家看的是实时画面,下一帧马上就到了。用TCP反而会因为重传旧数据导致新的画面堵在后面,时延越拉越大。所以UDP丢一个包就丢一个,最多画面花一帧。
但这几年有个叫QUIC的协议火起来,Google搞的,底层还是UDP,却在上面重新实现了可靠传输、加密、多路复用这些TCP和TLS才有的能力。它的逻辑是:TCP的很多特性被“僵化”在操作系统内核里,很难升级,那我不如到用户态自己造一个。现在HTTP/3就是基于QUIC的,很多大厂已经用上了。这个趋势给我们的启示是:网络协议不是一潭死水,它在持续演进,你要理解的是演进背后的原因——为什么需要多路复用?为什么需要连接迁移?每一个新特性背后都有一个真实场景的痛点。
4. 别被“七层模型”唬住:实际网络是怎么把数据送过去的
4.1 子网划分与路由:从你的电脑到目标服务器之间的漫游
协议栈的分层是个好理论工具,但真正理解网络怎么工作,你得看数据包是怎么一步步漫游的。IP层负责寻址,它不管走哪条路,只管把包送到“目的IP所在的网络”。而路由器负责转发,它有一个路由表,表里记录着“去哪个网段,走哪个接口,下一跳是谁”。数据包每经过一台路由器,就查一次表,决定下一站交给谁,这个过程叫跳路由。
这个过程完美解释了什么叫“逐跳转发”。路由器不需要知道去北京的完整路线,它只需要知道下一跳交给谁;每一台路由器都只做“局部决策”。这就像你在山里问路,每个路口的大爷只告诉你“往前走三公里右转”,到那个路口再问下一个大爷。全局地图不存在也没关系,只要每个路口都知道下一段怎么走,你总能到目的地。
子网划分在这条链路里扮演的角色是“快递分拣”。一个数据包到了某台路由器,路由器先看目的IP,再和路由表里的掩码做与运算,判断“这个目标在不在我直接连接的某个子网里”。在,就直接顺着对应端口送过去;不在,就扔给下一跳。这也是为什么网络工程师特别看重路由表设计——路由表一乱,数据就会绕路,甚至陷入路由环路。
4.2 NAT:为什么你家的多台设备共用一个公网IP
IPv4的地址总数是43亿个左右,听起来不少,但全球设备数量远超这个数。当年设计的时候没料到互联网这么火,所以后来搞出了NAT技术。简单说,NAT就是让你家里所有设备共用一个公网IP上网,内部用192.168.x.x这种私有地址互相区分,出家门的时候,路由器把每个内部设备的地址和端口翻译成一个公网IP加不同端口,数据回来的时候,再按端口映射回对应的内部设备。
这个机制在IPv6之前是续命的关键。但它带来一个衍生问题:外部主动发起的连接很难打进内网——因为路由器不知道这个“陌生数据包”该转发给家里哪台设备。所以你会发现,在家里搭建一个服务,外网访问非常费劲,要配置端口映射、做内网穿透,本质都是在绕开NAT的这个限制。
IPv6的设计初衷就是彻底解决地址短缺问题,它的地址空间大得离谱,说句玩笑话,给地球上的每一粒沙子分一个地址都用不完。IPv6普及了之后,NAT理论上可以退役,每台设备都有全球唯一地址,端到端通信回归了网络设计的原始理想。但现实里IPv6部署依然充满波折,因为很多应用、防火墙、老旧设备对它支持不好,这个过渡期可能还会持续很久。
5. 给两类人分别划重点:考试怎么复习,工作怎么应用
5.1 备战考试:谢希仁、王道、湖科大教书匠、自顶向下怎么选
热词里出现了好几个熟悉的名字。谢希仁的《计算机网络》是国内高校最常用的教材,结构传统、覆盖面广,侧重于让学生建立整体认识。王道的辅导书,它的特点是直击考点,把历年考研的套路拆得很细,适合备考冲刺阶段刷题用。湖科大教书匠这个B站UP主的视频,我认真看过几集,最大的优点是动画演示做得好——IP分片、TCP握手、CSMA/CD这些抽象过程,看动画比看文字理解起来快得多。至于《计算机网络:自顶向下》这本书,这是国外经典教材,它的叙事逻辑是反过来的,先从应用层讲起,再一层一层往下拆,特别适合有编程背景、容易对抽象模型反感的人。
如果你的目标是考408,我建议的组合是:第一遍用谢希仁或自顶向下建立知识框架,第二遍配合王道的重难点解析和真题练习巩固考点,遇到实在理解不了的过程性内容,去B站看湖科大教书匠对应的动画讲解。王道更偏向“考什么”,湖科大更偏向“为什么”,自顶向下更偏向“网络是给应用服务的”。四者并不冲突,找到各自舒服的位置搭着用就行。
考试复习还有一个我的个人经验:不要只看,一定要手写。把TCP的报文段结构画出来,把IP数据报的首部字段一个个默写出来,把路由算法的每一步算给自己听。你学的时候觉得都懂了,合上书一默写就露馅,网络协议这种东西,考的就是精确记忆和快速判断,没有捷径。
5.2 DevOps工程师方向:不背协议,但要会看现象
DevOps工程师需要的网络能力和考证侧重完全不一样。你不需要手写一个IP报文,但你要能在线上出故障时,快速判断问题出在哪一层。核心技能列表我总结为四件事:
一是会看连通性。ping、telnet、nc这些命令的返回结果,要能一眼看出是网络不通、防火墙拦截、还是端口未监听。二是会看HTTP。curl的返回码、响应时间、DNS解析耗时、TLS握手耗时,这些数据能帮你判断瓶颈在哪里。三是会看TCP连接状态。ss或netstat输出里出现的ESTABLISHED、TIME_WAIT、CLOSE_WAIT、SYN_SENT,这些状态我都见过一堆人踩坑。四是会抓包。tcpdump/Wireshark不要求精通,但至少知道怎么抓一个“奇怪的失败”流量,然后带着抓包结果去求助网络工程师。
说句掏心窝的话:DevOps面试里问到TCP三次握手,很多时候不是真考你背没背,而是想看你有没有能力把“握手”和“线上故障”联系起来。你能说出来“SYN超时可能是防火墙丢包导致的”、“TIME_WAIT过多是因为短连接太多”,这个价值比背一百遍报文结构高得多。
5.3 我的学习路径建议:从看现象到看本质
我自己学网络的过程大概分了三步走,供你参考。第一步是“看现象”:把家里的网络、公司的网络当成一个黑盒,遇到问题先猜,再试,反复折腾,建立一个感性认识。第二步是“看协议”:开始看书、看视频,把现象和理论对上号——哦,原来我之前遇到的那个卡顿是因为TCP慢启动;哦,这个白屏是因为DNS缓存了旧的解析记录。第三步是“看实现”:读内核、读源码、用抓包工具亲眼看一下TCP的序列号和确认号是怎么变化的。到这一步,你会觉得网络真的不玄了,它就是一行行代码和一条条规则在真实世界里跑出来的结果。
6. 实战总结:一次线上应用“假死”的排障全记录
6.1 从现象到定位:重启能解决,但绝不治本
前阵子我遇到一个典型的线上问题。某个服务运行一段时间后变得极其缓慢,重启进程立刻恢复,但过几个小时后又会复发。这不是我们的应用代码有明显bug,因为吞吐量和CPU都正常。我第一反应是网络层出了问题——不解决它,靠重启永远只是在给服务“续命”。
先用ss -s看了一下系统的TCP连接统计,发现TIME_WAIT的数量异常高,达到几万个。TIME_WAIT是什么?它是TCP连接主动关闭后,为了等待网络中可能迟到的旧数据包消失而保留的一个状态,通常会持续60秒。问题是,我们这台服务用了大量短连接——每次请求都新建连接,请求完就关掉,于是在高并发下,TIME_WAIT积累得飞快。TIME_WAIT本身不占太多内存,但它占用的端口号和连接表项,会拖慢新连接建立的效率,严重时直接导致连接失败。
6.2 用工具箱一步步排查:从tcpdump到内核参数
我做了两个动作。第一个是用tcpdump抓包,确认了“新建连接请求很多,然后快速关闭”的模式。第二个是看了应用侧的连接复用配置,发现连接池配置不合理,每次请求都是新建连接,没有复用长连接。这才是根因。
临时缓解措施是调整内核参数,把TIME_WAIT状态下socket的回收时间调短一点:即修改tcp_fin_timeout值,并开启tcp_tw_reuse(指在NAT环境下允许复用处于TIME_WAIT状态的连接)。注意这里有不少坑,tcp_tw_reuse不是无脑开的,它在某些情况下会和NAT冲突,导致连接数据错乱。所以我更推荐的根本解决方案是:让应用层使用连接池,用长连接减少新建和关闭频率,从源头上把TIME_WAIT的次数降下来。随后我们改造了服务,用连接池复用底层连接,TIME_WAIT数量肉眼可见地掉下来了,服务也恢复了稳定。
6.3 这次排障教会我的三件事
第一,线上问题永远不要急着重启逃避,先讲证据再动手,抓包数据是最不容反驳的证据。第二,很多看似“网络问题”的事故,根因不在网络,而在应用层怎么使用网络。短连接建得太多、keep-alive配得太短、连接池调得太小,都会把压力转嫁给TCP层。第三,理解TCP连接状态非常有用,它就像一个窗口,让你能看到操作系统眼里你的服务到底在经历什么。
这类排查想练好,平时就要积累基本功。我建议你把netstat、ss、lsof、tcpdump这几个命令的常用参数打印下来贴在工位上,多练几次就熟了。它们就是网络排障的四件套,基本覆盖了从“连接有没有建立”到“数据包长什么样”的全部问题。
最后分享一个我自己的习惯。学习网络不要贪多,今天搞懂一个概念就行。比如今天搞懂“DNS解析分几步”,明天搞懂“为什么TCP要三次握手”,后天搞懂“HTTPS证书有什么用”。积累下来,遇到实际问题时,这些点会自动连成线。计算机网络真正的难点不在概念多深,而在于概念之间的关联——一旦你把这些关联弄明白,再去看那些教科书,会发现它们其实写得还挺清楚的。