大多数网络讨论都是一堆缩略语。忘掉配置细节吧——其中的核心洞见是什么?
- 网络关乎通信
- 文本是最简单的通信方式
- 协议(Protocol)是读写文本的标准
在细节之下,网络其实就是一场 IM(即时通讯)对话。下面是我希望有人在我学习计算机如何通信时告诉我的内容。
TCP:文本层
传输控制协议(Transmission Control Protocol,TCP)提供了一个方便的假象:我们可以“直接”在两台计算机之间发送文本。TCP 依赖于 更底层 并且可以发送二进制数据,但暂时忽略这一点:
- TCP 让我们能在计算机之间即时通信(Instant Message)
我们用 Telnet 来 IM,它是网络界的“记事本”:telnet 使用 TCP 发送和接收纯文本。它是一个没有广告和陌生好友请求的聊天客户端,清净自在。
让我们用 telnet (或 putty,一个更好的工具):
telnet google.com 80
[connecting...]
Hello Mr. Google!
我们连接到 google.com 的 80 端口(Web 请求的默认端口),并发送消息“你好,Google 先生!”。我们按了几次回车,等待回复:
<html>
...
<h1>Bad Request</h1>
Your client has issued a malformed or illegal request
...
</html>
格式错误?非法? 强大的 Google 不高兴了。它没理解我们,并返回了 HTML 说明了这一点。
但是,我们进行了一次对话:文本发过去,文本返回来。换句话说:

协议(Protocol):要填写的表单
非结构化的聊天太随意了——服务器怎么知道我们想要做什么?我们需要一个 协议 (标准的通信方式)才能说得清楚。
我们一直都在使用协议
- 把“收件人”和“发件人”地址写在信封上的特定位置
- 填写银行表单(账号、存款金额等写在特定位置)
- 说“Roger”或“10-4”表示无线电请求已被理解
协议让通信变得清晰。
案例研究:HTTP 协议(Protocol)
我们在每个 url 中都能看到 HTTP: http://google.com/。这是什么意思?
- 连接到服务器 google.com(使用 TCP,默认端口 80)
- 请求资源“/”(默认资源)
- 使用超文本传输协议格式化请求
HTTP 是请求资源时要填写的“表单”。使用 HTTP 格式,上述请求看起来像这样:
GET / HTTP/1.0
记住, 它只是文本!我们正通过一次 IM 会话,用如下格式请求一个文件:[命令] [资源] [协议名/版本]。
这个命令被“IM”给了服务器(你的浏览器会附加额外信息,这是后话)。Google 的服务器返回了如下响应:
HTTP/1.0 200 OK
Cache-Control: private, max-age=0
Date: Sun, 15 Mar 2009 03:13:39 GMT
Expires: -1
Content-Type: text/html; charset=ISO-8859-1
Set-Cookie: PREF=ID=5cc6…
Server: gws
Connection: Close
<html>
(Google web page, search box, and cute logo)
</html>
哎呀。底部是供浏览器显示的 HTML。但顶部的那些乱七八糟的是什么?
嗯,假设我们只是拿到了要显示的原始 HTML。但如果有错误呢:服务器崩溃了、文件不存在,或者 google 就是不喜欢我们?
有些 元数据 (关于数据的数据)很有用。当我们在 Amazon 订一本书时 我们期望有一张装箱单 描述了订单:预期的收件人、价格、退货信息等。你不会想要一本光秃秃的书直接扔在门口。
协议也是类似的:接收方想知道一切是否正常。这里我们看到了臭名昭著的状态码,比如 404(资源未找到)或 200(一切正常)。这些头部不是真正的数据——它们是服务器附带的装箱单。
来自协议(Protocol)的洞见
研究现有的、流行的系统是理解工程决策的好方法。这里有几个例子:
二进制 vs 纯文本
二进制数据 二进制比文本更高效,但更难调试和生成(你知道怎么用几个十六进制编辑器?)。底层协议作为互联网的主干,使用二进制数据来维持性能。应用层协议(HTTP 及以上)使用文本数据以便于互操作。你不会就字节序问题和 HTTP 发生宗教战争。
有状态 vs. 无状态
有些协议是有状态的,这意味着服务器会记住与客户端的对话。例如,使用 SMTP 时,客户端打开连接并一次发出一个命令(比如向邮件添加收件人),然后关闭连接。有状态通信在具有多个步骤或条件的交易中非常有用。
无状态通信更简单:你将整个交易作为一次请求发送。每条“即时消息”独立存在,不需要其他消息。HTTP 是无状态的:你可以请求网页而无需向服务器介绍自己。
可扩展性
我们无法事先想到所有事情。我们如何为旧协议扩展新用户?
HTTP 有一个简单而有效的“头部”结构:一种看起来像“Header:Value”的元数据前缀。
如果你不认识发送过来的头部(新客户端,旧服务器),就忽略它。如果你期望某个头部但没看到(旧客户端,新服务器),就使用默认值。这就像在调查中加入一个“还有什么要告诉我们的吗?”部分。
纠错与可靠性
像 TCP 这样的底层协议的工作是确保数据可靠传输。但高层协议(如 HTTP)需要确保它是 正确 数据。错误如何处理和传达?客户端可以直接重试,还是服务器需要重置状态?
HTTP 自带一组错误码来处理各种情况。
可用性
网络化的妙处在于它在一台计算机上也能工作。Memcached 是一个很棒的缓存数据服务。你猜怎么着?它使用普通的旧文本命令(通过 TCP)来保存和检索数据。
你不需要复杂的 COM 对象或 DLL——你启动一个 Memcached 服务器,输入文本,输出文本。它是语言中立且易于访问的,因为任何像样的操作系统都支持网络。你甚至可以用 telnet 连入 Memcached 来调试它。
无线路由器类似:它们有一个可通过 HTTP 访问的控制面板。没有“路由器配置程序”——你只需用浏览器连接它。路由器提供网页,当你提交数据时,它会进行必要的配置更改。
像 HTTP 这样流行的协议你可以 假设 用户有一个客户端。
分层协议
协议可以分层。我们可能写一份简历,它是更大申请的一部分,而申请被塞进信封里。每个片段有自己的格式,对其他片段毫不知情。你的信封不关心简历——它只想要收件人和发件人地址写正确。
许多协议依赖 HTTP,因为它使用如此广泛(而不是像 Memcached 那样从零开始,它需要效率)。HTTP 有定义明确的方法来定义资源(URL)和命令(GET 和 POST),所以为什么不利用它们呢?
Web 服务正是这样做的。SOAP 协议将 XML 塞进 HTTP 命令中。REST 协议拥抱 HTTP,并尽可能使用现有的动词。
记住:这一切都是人为约定的
网络涉及 人类约定。因为纯文本无处不在且易于使用,它是大多数协议的基础。而 TCP 是交换文本最简单、支持最广泛的方式。
记住一切都是纯文本的 IM 对话 帮我理解那些不可避免的网络问题。有时候你需要深入 HTTP 才能弄明白 压缩 和 缓存.
不要只死记细节;要把协议(Protocol)看作解决通信问题的策略。祝你网络愉快。