TCP 协议 - 网络世界的"靠谱快递员" 📦

date
Nov 14, 2025
slug
nodejs-tcp
status
Published
tags
Node.js
summary
嘿各位!今天咱们聊聊 TCP(传输控制协议),这个让网络通信变得靠谱的幕后英雄。
type
Post

TCP 是什么?先打个比方 📬

想象你要给朋友寄一本书,有两种快递可选:
普通快递(IP协议)
  • 把书撕成100页,每页单独寄
  • 可能乱序到达(第50页先到,第1页后到)
  • 可能丢几页
  • 便宜但不靠谱 😅
靠谱快递(TCP协议)
  • 保证每一页都到
  • 保证按顺序到(1、2、3...100)
  • 丢了会重发
  • 有点慢但放心
TCP 就是网络世界的"靠谱快递员"

TCP 的核心特性:为啥它这么靠谱?🛡️

1. 面向连接(Connection-Oriented)

TCP 不是"扔了就走",而是建立连接、维护连接、关闭连接
就像打电话:先拨号接通,然后聊天,最后说拜拜挂断 ☎️
而底层的 IP 协议是面向数据报的,每个数据包独立传输,互不相关。
IP 更像发短信:一条一条发,不管对方收没收到,也不管顺序

2. 保证顺序传递

你发送:"我爱Node.js"
TCP 保证对方收到的也是:"我爱Node.js"
而不是:"js我爱Node." 😱
怎么做到的?
每个 IP 数据包都包含:
  • 连接标识符
  • 数据流顺序信息
假设一条消息分成 4 部分,服务器收到第 1 和第 4 部分后,会等待第 2 和第 3 部分。
就像拼图,缺了中间几块,会等齐了再拼完整 🧩

3. 面向字节(Byte-Oriented)

TCP 完全不关心你发的是什么字符、什么编码。
  • ASCII:每个字符 1 字节
  • Unicode:每个字符 4 字节
都可以!TCP 只管传字节流。
就像快递员不管你箱子里装的是书还是衣服,只管送 📦
这种灵活性让 TCP 适用性极强。

4. 可靠性(Reliability)

TCP 基于确认和超时机制:
  1. 发送数据
  1. 等待确认消息(ACK)
  1. 如果超时未收到 → 重发
就像你发完微信,看到对方"已读"才放心。没"已读"?再发一遍! ✅

5. 流控制(Flow Control)

两台电脑速度差异很大怎么办?
TCP 会确保快的不会压垮慢的
就像你倒水,杯子快满了就慢点倒,不会一股脑全倒进去溅出来 🚰

6. 拥塞控制(Congestion Control)

TCP 会控制传输速率,避免网络拥堵。
就像高速公路堵车时,大家都开慢点,避免更堵 🚗

Telnet:测试 TCP 的神器 🔧

Telnet 是个早期网络协议,现在主要用来测试 TCP 连接
虽然因为安全问题已经被 SSH 取代,但绝大部分操作系统都内置了 telnet 客户端。

有趣的特性

Telnet 发现服务器不是 Telnet 协议时,不会报错或断开,而是自动降级到纯 TCP 模式
这让我们可以用它测试任何 TCP 服务!

实验:用 Telnet 访问 HTTP 服务器

先写个简单的 HTTP 服务器:
运行:node web-server.js
然后用 Telnet 连接:
连接成功!但没看到 "Hello World",为什么?
因为还没发 HTTP 请求!在终端输入:
Boom! 服务器响应出现了:

我们做了什么?

  1. ✅ 建立 TCP 连接
  1. ✅ 创建 HTTP 请求
  1. ✅ 接收 HTTP 响应
  1. ✅ 验证了 TCP 特性(数据按序到达)

实战项目:基于 TCP 的聊天程序 💬

理论讲够了,咱们撸代码!

项目需求

做个简单的聊天服务器:
  • 连接后显示欢迎语和当前在线人数
  • 输入用户名
  • 可以向其他用户发送消息

为什么按回车键?

Telnet 会立即发送你输入的每个字符。按回车是为了发送 \\n 字符,作为消息分隔符
就像发微信,按发送键才真正发出去 📱

第一步:创建项目

第二步:理解 net.Server API

运行:node index.js
用 Telnet 连接:telnet 127.0.0.1 3000
成功!控制台显示 "new connection!"

核心概念

  • createServer 的回调会在每次新连接时执行
  • 回调接收一个 Stream 对象(既可读又可写)
  • listen异步的,可以传回调函数
http.Server 其实继承自 net.Server,现在理解"HTTP 建立在 TCP 之上"了吧? 🏗️

第三步:接收连接并发送欢迎语

添加计数器:
重启服务器,用 Telnet 连接,看到欢迎语了!
第二个客户端连接时,计数器显示 1

第四步:处理断开连接

为什么用 close 而不是 end
  • end:客户端正常关闭连接时触发
  • close任何情况下连接关闭都触发(包括错误)
更稳妥的选择! 🛡️

第五步:监听 data 事件

在客户端输入 "hi",服务器控制台输出:
收到的是 Buffer!因为 TCP 是面向字节的。

设置编码

不想每次都转换?设置编码:
现在输出的就是字符串了!

第六步:状态管理和用户验证

引入 users 对象追踪所有连接:
每个连接保存昵称:
现在新用户加入时,所有人都能看到通知!

第七步:发送聊天消息

两个客户端可以聊天了!🎉

第八步:圆满完成

抽象广播函数:
简化代码:
完成! 一个功能完整的聊天服务器 ✨

进阶:IRC 客户端 🤖

前面写了服务器,现在写个客户端
IRC(Internet Relay Chat)是基于 TCP 的聊天协议。

理解 net.connect API

连接到服务器:

实现部分 IRC 协议

连接到 irc.freenode.net#node.js 频道:
注意:IRC 命令以 \\r\\n 结尾(就像 HTTP 头一样)。
运行后,你的 IRC 客户端就连上真实的 IRC 服务器了!

作为练习

你可以尝试:
  1. 解析接收到的 data,提取聊天消息
  1. 实现一个 IRC 机器人,自动回复命令
  1. 当有人说 "date" 时,回复当前时间

小结 📝

这一章我们:
✅ 理解了 TCP 的核心特性(连接、顺序、可靠性)
✅ 用 Telnet 测试了 TCP 服务
✅ 用 Node.js 写了一个聊天服务器
✅ 实现了一个 IRC 客户端

关键知识点

TCP 特性
  • 面向连接(建立、维护、关闭)
  • 保证顺序(数据按序到达)
  • 面向字节(不关心编码)
  • 可靠性(确认 + 重传)
  • 流控制(快的等慢的)
  • 拥塞控制(避免网络堵塞)
Node.js API
  • net.createServer():创建 TCP 服务器
  • net.connect():创建 TCP 客户端
  • conn.setEncoding():设置编码
  • conn.write():发送数据
  • 事件:connectdatacloseerror

重要概念

共享状态的并发:多个连接修改同一个变量(countusers
Stream:既可读又可写的对象
分隔符\\r\\n 用于区分消息边界

下一步 🚀

现在你对 TCP 中的数据传递、数据块构建已经很清楚了,下一章我们会学习 HTTP——TCP 上层的协议。
到时候你会发现,理解了底层的 TCP,学习 HTTP 会轻松很多!
就像你学会了骑自行车,学摩托车就容易了 🏍️
好了,今天的分享就到这里!现在你已经掌握了网络编程的基础,可以构建各种实时通信应用了 💪
记住:HTTP、WebSocket、数据库连接...很多东西都基于 TCP。掌握了 TCP,你就掌握了网络编程的根基!
有问题欢迎留言,咱们下次见!📡✨

彩蛋:常见问题 🤔

Q: TCP 和 UDP 有什么区别?
A: TCP 是"靠谱快递"(保证送达、保证顺序),UDP 是"扔了就走"(快但不保证)。游戏、视频通话常用 UDP,网页、文件传输用 TCP。
Q: 为什么 HTTP 基于 TCP?
A: 因为网页需要完整传输。少一个字节,页面可能就坏了。TCP 的可靠性正好符合需求。
Q: close 和 end 有什么区别?
A: end 是正常关闭,close 包括所有关闭情况(正常+异常)。生产环境推荐用 close
Q: 为什么要 setEncoding?
A: 因为 TCP 传输的是字节流(Buffer),设置编码后自动转成字符串,省得每次手动转换。
继续加油!🔥

© 拾光 2025 - 2026

粤ICP备2025472574号