计算机核心基础:从冯·诺依曼结构到TCP握手与批处理

发布时间:2026/10/21 6:15:39
计算机核心基础:从冯·诺依曼结构到TCP握手与批处理 1. 硬件系统和软件系统先看一台机器内部到底谁在干活1.1 “冯·诺依曼结构”不是考试名词是整台机器的骨架我经常看到有新人能把“三次握手”背得滚瓜烂熟但一抓包就蒙也能倒背OSI七层却不知道浏览器访问一个网页经过了哪些步骤。反过来有些老开发对框架如数家珍遇到网络超时却只会重启。这些问题的根源都一样缺的不是单个知识点而是一个能把这些基础串起来的认知框架。所以这篇文章干脆从一台电脑最底下的硬件开始一路讲到最常用的批处理脚本。先聊硬件。现在绝大多数计算机仍然是冯·诺依曼结构CPU、内存、外部存储、输入输出设备以及连接它们的总线。这个结构几十年前就定了直到今天也没跳出它的框架。用生活的话说CPU就是厨房里掌勺的师傅负责“算”内存是案板食材指令和数据要放到案板上师傅才能切、才能炒硬盘是冰箱食材平时放在里面要用的时候再拿到案板上。案板一断电上面摆的食材全没了所以内存断电就丢数据冰箱在断电后还是能保存食材所以硬盘可以持久化。CPU内部也不简单。它里面有寄存器这是最快的临时存储比内存还要快几个数量级CPU运算的时候数据基本先放寄存器。寄存器是CPU内部的小“口袋”容量很小速度极快。为了不让CPU等慢吞吞的内存现代CPU还加了好几层缓存一级、二级、三级缓存把最常用的数据提前搬到离计算单元更近的地方。理解这个概念很重要你写程序时如果某段代码经常用同一个数据让它正好待在缓存里性能能差出好多倍这就是所谓的“局部性原理”。内存之外外部存储也不只有一块硬盘。SSD、机械硬盘、U盘、光盘各有各的适合场景。机械硬盘是“转盘”结构顺序读快随机读慢SSD靠闪存芯片随机读写比机械盘强很多适合做系统和程序盘。无论哪种CPU都不能直接访问硬盘里的文件必须先把文件数据“搬”到内存里。这个搬运过程如果让CPU逐个字节干会浪费大量计算资源所以硬件里有DMA直接内存访问机制让硬盘控制器直接和内存传数据传完再通知CPU“我搞定了”。这也是很多高性能服务器能做高并发的硬件基础。1.2 软件不是“看不见的程序”是指令和数据的组合硬件是骨架软件是让骨架动起来的“咒语”。但咒语不能是人话CPU只认二进制机器码。我们写的高级语言最终都要被编译或解释成对应CPU指令集所支持的机器指令每条指令做一件极简单的事把某个数加一、把某块数据拷贝到某个地址、跳到某段代码继续执行。就是这么笨的指令堆叠起来构成了我们今天用的浏览器、聊天软件和各种业务系统。软件系统经常被分成系统软件和应用软件两类。系统软件包括操作系统、编译器、设备驱动、运行时环境等它们负责管理和调配硬件资源给应用软件提供稳定的运行空间。应用软件就是用户直接操作的那些比如文本编辑器、报表系统、游戏。这个界限有时候是模糊的比如数据库是应用软件但它又像基础设施一样被其他程序依赖。但从计算机基础的角度看你只要记住一条主线软件的本质是指令加数据运行时一定被加载到内存里最终被CPU执行。一个程序从双击图标到真正跑起来过程比你想象得复杂。双击不是直接让CPU执行文件而是让操作系统派一个加载器去解析可执行文件把代码段、数据段映射到内存分配合适的栈和堆空间做动态链接然后跳到程序入口地址开始执行。这个过程中文件在硬盘程序在内存CPU通过寄存器取指令内核在背后做内存映射和权限检查。你在命令行敲一条命令本质上也是在请求操作系统创建一个新进程并运行特定程序。所以“软件”从来不是一个孤立的文件它是在硬件和操作系统共同支撑下才“活”起来的。2. 抽象层次和操作系统层层封装才是计算机不崩的秘诀2.1 抽象层次为什么层层套娃反而更好用如果只有硬件和裸机指令人类根本写不出复杂系统。CPU电路里有两极管、三极管和逻辑门往上组合成算术单元和控制器再往上这些硬件用指令集面向汇编语言指令集之上有C语言C之上有操作系统API再往上才是各种高级语言和框架。每多一层底层就被封装一次上层只需要关心“怎么调用”不需要关心“通电后怎么翻转电平”。这就是抽象层次的价值。它很像一家公司最上面是业务部门最底下是供应链和生产车间中间隔着若干管理层和执行层。业务部门不会直接去和每一个车间工人沟通只需要通过标准化流程提需求。计算机也是一样你写一个“保存文件”的操作停留在高级语言层面就是一个函数调用下面会经过系统调用翻译成操作系统文件系统操作再经过驱动翻译成硬盘控制器的命令。哪一层出问题替换哪一层其他层不需要大改。抽象层次做得好最大的好处是“可替换性”和“可理解性”。比如在应用层你不需要知道文件存在固态硬盘哪个颗粒上在传输层你不必关心中间经过了几台路由器。每个层次都有明确的边界排查问题时也能逐层定位。当然抽象不是越多越好层太多会带来性能损失所以系统设计时要平衡“隔离复杂度”和“避免无谓开销”。你看到的很多中间件、容器、虚拟化技术本质上也是一层新的抽象只不过它们解决的问题更具体。2.2 操作系统四个核心模块进程、内存、文件、设备操作系统是承上启下的核心它最大的职责是“管理资源”。资源就那几种CPU时间、内存、文件存储空间、外部设备。对应地操作系统有进程管理、内存管理、文件系统和设备驱动四大块。进程管理负责把CPU时间分成时间片轮流分配给不同进程让单核CPU也能同时跑多个程序。每个进程有独立的地址空间里面又分线程线程共享进程的地址空间上下文切换比进程切换更快。操作系统里还有一个调度器决定下一个时间片给谁跑这就是任务调度的核心。只要有一台多核机器你就能看到进程在不同核心之间迁移迁移和切换也会产生开销所以并不是线程越多性能越好。内存管理做的事情更基础但更隐蔽。每个进程觉得自己拥有从零开始的连续地址空间实际上操作系统把物理内存分成页框再用页表映射到进程的虚拟地址空间。进程访问一个还没映射到物理内存的地址时会触发缺页异常由内核从磁盘加载相应页。这一套机制保证了两个进程不会随便踩到对方的内存也能让物理内存不够用时用虚拟内存顶一下。很多程序“内存泄漏”其实不是内存真的消失而是进程一直申请但不释放最终拖垮系统。文件系统和设备驱动则把五花八门的存储硬件和输入输出设备统一成“文件”和“设备节点”。你在Windows里看到C盘D盘在Linux里看到挂载点都是文件系统在组织块设备上的数据。设备驱动把键盘、鼠标、网卡、显卡等硬件封装成统一接口提供给上层调用。没有设备驱动你写一个打开网络连接的API背后根本不知道要控制哪个寄存器。2.3 用户态与内核态系统调用为什么是“正规办事窗口”操作系统还要防着应用程序“乱来”。所以CPU提供了特权级别内核态能访问所有指令和IO用户态只能执行受限指令。普通应用程序基本跑在用户态需要操作文件、网络、进程时得通过系统调用进入内核态让内核代表它完成操作然后返回结果。这个过程很像去政务窗口办事你不能进后台自己改系统记录必须提交表单、等待审批。为什么非要有这层限制因为如果每个应用都能直接操作硬件一个程序写错地址就能把整个系统搞崩。系统调用把不安全的操作拦截在内核边界内核里有完善的权限校验、参数检查、资源跟踪逻辑应用出了问题也顶多杀掉它自己的进程系统还活着。这也是操作系统稳定性的重要来源。当然进入内核态有开销。一次系统调用比普通函数调用慢很多因为要保存上下文、切换到内核栈、再做权限检查。所以很多高性能软件会尽量减少系统调用次数比如日志缓冲、批量读写、使用内存映射文件都是为了减少内核态切换带来的成本。你能听懂这句话说明对用户态和内核态已经有了实操层面的认识。3. 网络分层与网络协议数据包是怎么寄出去的3.1 分层模型寄快递和寄数据包是一回事网络比单机复杂得多因为数据要跨过无数设备。为了不让复杂度爆炸网络也按抽象层次来了。最经典的是OSI七层参考模型但实际工作中大家更多用TCP/IP四层模型应用层、传输层、网际层、网络接口层。OSI七层里的会话层和表示层在TCP/IP里基本被归入应用层或者由具体协议实现。我用寄快递给你类比你写收件地址应用层快递公司规划从哪个城市到哪个城市的干线运输网际层具体找哪辆车、哪个航班链路层路上怎么搬运物理层每层都会贴一个标签协议头最后到了收件人手里再一层层撕掉标签。TCP/IP分层核心职责典型协议/工具应用层面向具体业务的数据语义HTTP、DNS、DHCP、FTP传输层端到端连接、可靠或尽力交付TCP、UDP网际层地址寻址与路由IP、ICMP网络接口层物理传输和链路帧以太网、Wi-Fi、ARP不需要死记表关键是每一层的协议解决每一层的问题。HTTP关心的是“网页内容怎么表达”TCP关心的是“对方有没有收到”IP关心的是“这个包该往哪个网络走”以太网关心的是“这一跳怎么传过去”。出了问题你就能按层定位这是网络分层最大的价值。3.2 常见协议与封包/解包过程你平时说的“网络协议”其实就是每台机器都遵守的一种固定“交谈格式”。HTTP请求应用层把数据交给TCPTCP给数据加一个端口号与序号相关头部形成段段交给IPIP加源IP和目标IP地址形成数据包数据包再交给以太网层加上源MAC、目标MAC和帧校验形成帧。接收端顺序反过来每层剥掉自己那层的头部把数据交给上层。这里容易绕晕的两个点是端口和IP地址分别属于哪一层。端口属于传输层因为TCP和UDP要用端口区分同一台机器上不同进程IP地址属于网际层用来标识全球范围内的网络位置。还有一个容易混淆的协议是DNS它默认跑在UDP上但也能用TCP。你在浏览器输入一个域名第一步往往是DNS解析把域名换成IP地址然后才能建立TCP连接。3.3 一个分层定位网络故障的实例假设你遇到一个服务连不上不要直接怀疑“网断了”按分层来排查会快很多。先看应用层服务进程起没起、端口监听了没有、配置对不对。再看传输层本机到目标IP的端口通不通可以用相关网络命令测端口。再看网际层本机能不能ping通网关和远端IP如果网关都ping不通问题大概率在本地链路或无线连接如果远端IP通但端口不通可能是防火墙挡住端口。最后看链路层网线、交换机端口、无线信号是不是正常。这个过程本质上是在“二分排除”每一层都先排除自己再用工具定位到具体层。真正干活的时候我会先在本机ping网关再ping远端IP再测服务端口必要时抓包看有没有SYN包发出去。如果SYN包发出去但没有SYN-ACK回来基本上是远端防火墙或服务没起如果连SYN都没发出去本地路由和TCP栈就有问题。这些经验用一句话总结先分层再抱怨。4. TCP三次握手与四次挥手连接的开灯、关灯仪式4.1 三次握手为什么少一次不行多一次没用TCP是面向连接的可靠协议在传输数据前双方要先建立连接交换初始序列号。三次握手的过程用最简化的说法是客户端发送SYN随机生成一个初始序列号x服务端收到后回复SYNACK同时带上自己的初始序列号y并把确认号设为x1客户端收到后再发一个ACK确认号设为y1连接建立。很多人问为什么不能两次握手。关键在于防“历史连接”。想象一个场景客户端第一次发的SYN包因为网络拥塞卡了很久客户端等不及重发了一个SYN服务端回了SYNACK如果只有两次握手服务端认为连接建立成功立刻分配资源。但这时候旧的SYN包又到了服务端服务端没法判断这是旧包可能再建立一条无效连接白白消耗资源客户端也无感知。三次握手时客户端收到服务端的SYNACK后会检查自己有没有发起过对应的SYN能发现旧连接并发送RST终止它这才保证了连接唯一性和资源安全。理解了“为什么三次”也就理解了为什么没有四次。三次已经完成双方“你发我收”和“我发你收”两个方向的确认再握一次没有带来新的状态信息。现代操作系统还在握手阶段做了很多优化比如SYN Cookie机制通过不预留真正资源的方式防御连接泛洪但底层流程始终没变。4.2 四次挥手为什么断开连接比建立连接多一步TCP连接是“全双工”的数据可以两个方向同时流动所以关闭时也要两个方向分别关闭。主动关闭的一方发FIN表示“我这边数据发完了请关闭我的发送方向”被动方收到后先回ACK表示“我收到了你的关闭请求”但被动方可能还有数据要发给主动方所以它只能在数据发完后再发一个自己的FIN主动方收到FIN后再回最后一个ACK。这下总共有4个报文。看到这里你就能回答“为什么握手三次挥手四次”了握手时双方一上来都没有数据负担SYN和ACK可以合并成一个报文挥手时被动方的ACK和FIN在时间上分开了因为可能还有数据没发完。这是语义决定的数量差异不是故意绕。主动关闭方发出最后一个ACK后会进入TIME_WAIT状态要等两个最大段生存时间2MSL才完全关闭。为什么要等第一防止最后一个ACK丢了被动方会超时重发FIN主动方如果已经关闭就回应不了第二让这个连接上的所有旧数据包在网络中彻底消失避免被新连接的相同四元组误接收。所以TIME_WAIT不是异常而是TCP协议自我保护的正常状态。4.3 连接状态速查和现场排障经验真正排查TCP问题时看的不是抓包时间线而是连接状态机。你输入查看连接状态的命令会看到大量LISTEN、ESTABLISHED、TIME_WAIT、CLOSE_WAIT等状态。LISTEN代表服务端在等连接SYN_SENT是主动连接还没收到确认SYN_RCVD是服务端已收到SYN还没完成握手ESTABLISHED就是双方状态良好处于正常传输阶段。关闭阶段则有FIN_WAIT_1、FIN_WAIT_2、CLOSE_WAIT、LAST_ACK、TIME_WAIT。状态含义常见原因LISTEN服务端正在监听端口正常ESTABLISHED连接已建立数据传输中正常TIME_WAIT主动关闭方等待旧包消失短连接多CLOSE_WAIT被动关闭方等待应用调用close应用未关闭socketFIN_WAIT_2主动方等对方发FIN对端应用挂起LAST_ACK被动方等最后一个ACK网络丢包或对端异常最常踩的坑是CLOSE_WAIT大量堆积。开发人员如果用完连接不关闭服务端就永远停在CLOSE_WAIT连接越堆越多最后把文件描述符耗尽新连接都进不来。这个问题的根因是应用层逻辑泄漏不是TCP栈问题。另一种常见的是TIME_WAIT堆积多发生在高并发短连接场景虽然它不如CLOSE_WAIT致命但仍然会占用端口和内存。可以适当调整TCP参数或改用连接复用但不要为了改而改得先观察再调整。5. 批处理bat被低估的自动化利器能省半条命5.1 bat文件基本结构三分钟写一个能用的脚本聊完网络这层“高精尖”说个特别接地气的东西Windows下的批处理bat。很多人觉得它太老、太土不如Python或PowerShell洋气但实际工作中你难免遇到需要快速自动化Windows操作的时候。bat不用装解释器双击就能跑兼容性极强是老运维传下来的“保命工具”。一个最小的bat长这样echo off rem 这是一段注释 echo 开始备份... mkdir backup_20250101 copy C:\data\*.txt backup_20250101\ nul echo 备份完成 pause第一行echo off是把命令回显关掉否则每行命令都会先显示一遍很吵。rem是注释写在代码里提醒自己和别人。echo向控制台输出文本pause是等待按任意键防止窗口一闪而过。nul是丢弃输出让命令不刷屏。这几个东西组合起来你就能拼出很多实用脚本。5.2 三个我经常用的bat片段带解释第一个是批量重命名文件。比如你有一堆检验图片想统一改成带序号的文件名。用for循环加变量延迟扩张可以做到echo off setlocal enabledelayedexpansion set count0 for %%f in (*.png) do ( set /a count1 ren %%f image_!count!.png ) echo 已处理 !count! 个文件 pause注意这里写的是!count!而不是%count%。在括号块里%count%会在进入块时一次性展开成初始值导致每次循环你都用同一个文件名去重命名最后只剩下一个文件。setlocal enabledelayedexpansion开启延迟变量再用!var!引用才能拿到循环里实时变化的值。这个坑新手十个人里有九个会踩。第二个是启动开发环境的多个程序。用start开多个窗口分别跑前端、后端和日志工具省得每次手动开一遍echo off cd /d D:\work\myweb start web cmd /k npm run dev cd /d D:\work\myapi start api cmd /k python app.py echo 已启动 web 和 api 窗口cd /d不仅切换目录还切换盘符这个细节很多老手也容易忘。cmd /k表示执行完命令后保持窗口不关闭这样你能看到日志输出。如果某个服务启动失败你也不至于连窗口都找不到。第三个是权限检测。某些脚本需要管理员权限运行否则命令会失败。可以在脚本开头加一段检查echo off net session nul 21 if %errorlevel% neq 0 ( echo 请右键本脚本选择“以管理员身份运行” pause exit /b ) echo 当前已是管理员权限继续执行...net session nul 21是一个快速判断权限的写法非管理员执行会失败并刷新%errorlevel%。要注意exit /b只退出当前脚本不会把CMD窗口整个关掉这比直接在脚本末尾用exit更友好。5.3 写bat最容易踩的坑变量延迟、编码、路径空格bat语法看着简单真正运行起来比高级语言还“野蛮”。变量延迟是最大的坑前面已经演示过。编码是第二大坑bat文件默认按系统区域编码解析中文系统下一般要存成ANSI/GBK直接存成UTF-8很容易出现中文乱码甚至命令解析错乱。我的习惯是脚本注释和信息提示尽量用英文或者明确知道目标机器编码时才用中文这样最稳。路径带空格是第三大坑。C:\Program Files里有个空格你直接写cd C:\Program Files\xxcmd会把它拆成两段然后报错。正确做法是用引号包住整个路径cd /d C:\Program Files\xx。同理文件路径、参数里有空格时都要加引号。如果路径里还有、|这样的特殊符号最好用双引号全部括起来否则cmd会把符号当命令连接符。还有%errorlevel%的判断时机。有些命令执行后不会刷新错误级别或者刷新的值不是你想象中那个。测试某个命令是否成功最好在紧跟着的命令里用if errorlevel 1判断别隔好几行再查中间任何一条echo都可能覆盖错误级别。至于for循环里的%%i在命令行直接输入时要用%i在bat文件里用%%i这个双写百分号的规则也经常被当成书写错误实际上它是语法的一部分。6. 把基础串一遍一次网页请求的完整旅程6.1 从浏览器地址栏到服务器中间发生了什么现在我们把前面所有知识拼起来。你在浏览器输入一个网址并回车看起来只是一瞬间实际上背后经历了一段复杂的旅程。首先操作系统把浏览器的网络请求交给网络协议栈同时浏览器先发起DNS解析请求把域名翻译成IP地址。这一步数据走了UDP到达某个DNS服务器服务器用应用层协议把IP返回给浏览器。拿到IP之后浏览器作为客户端向服务器的某个端口发起TCP连接。于是你看到最经典的三次握手SYN、SYNACK、ACK。三次握手完成之后HTTP请求数据才能作为应用层载荷发送出去。这个请求在发送过程中被TCP划分成段、被IP封装成包、被以太网封装成帧经过路由器逐跳转发最终到达目标机器。目标机器的操作系统收到后层层解包把HTTP请求交给Web服务进程。Web服务解析完请求可能查数据库、做计算然后返回一个HTTP响应。响应再走同样的封包过程回到浏览器浏览器渲染页面。这一趟走完你会清楚地看到每一层抽象为什么存在。DNS解决“人记不住IP”的问题TCP解决“不可靠网络还要可靠传输”的问题IP解决“不同网络之间怎么寻址”的问题HTTP解决“浏览器和服务器之间怎么表达请求内容”的问题。每一层都在自己的边界内做自己的事谁也没有越界。6.2 为什么我建议你亲手抓一次包很多概念看了无数遍不如亲手抓一次包。你可以在本地起一个简单的测试服务用抓包工具监听对应端口再用浏览器访问一次。你会看到漂亮的三次握手序列客户端发出SYN服务端立刻回SYNACK客户端再回ACK。断开的时候你也会看到四个报文FIN、ACK、FIN、ACK可能还会看到TIME_WAIT状态。这些不是抽象概念是电信号经过网卡、内核协议栈之后被解析成的真实报文。抓过包之后很多曾经搞不清的问题会一下子贯通。比如为什么抓包经常看到“重传”为什么SYN能发出去但对方不回为什么连接会被RST空指针。你也能理解为什么网络故障必须逐层排查应用层再正常一旦TCP层没握手成功应用层什么都做不了TCP层正常如果IP层路由不对数据包仍然送不出去。我个人在实际操作中的体会是把基础串成一条线之后很多排障就不再靠猜了。遇到连接超时先想是哪一层卡住了写批处理脚本时先想清楚变量展开和路径引号看TCP状态时先想清楚是应用层问题还是协议栈问题。这些能力都不是背定义背出来的是靠一次一次抓包、一次一次排障、一次一次写坏脚本又修好之后长出来的。如果你正在学这些内容不妨先搭个本地环境从头到尾跑一次比收藏十篇资料都有用。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询