深入理解什么是端口(port)
个人简历封面制作
深⼊理解什么是端⼝(port)
每当看到有⼈的简历上写着熟悉 tcp/ip, http 等协议时, 我就忍不住问问他们: 你给我说说, 端⼝是啥吧! 可惜, 很少有⼈能说得让⼈满意... 所以这次就来谈谈端⼝(port), 这个熟悉的陌⽣⼈.
在此过程中, 还会谈谈间接层, naming service 等概念, IoC, 依赖倒置等原则以及 TCP
协议的⼀些重点知识.
常见端⼝
在我们的⽇常开发过程中, 特别是后端的开发⼈员, 即便他没有真正理解端⼝的细节, 他还是会听过见过各类的端⼝, 这个东西⼏乎⽆处不在, ⽐如:
mysql 缺省⽤的 3306 端⼝,
redis 的 6379 端⼝,
tomcat 默认⽤的 8080 端⼝,
ssh ⽤的 22 端⼝,
等等...
当然我们最关注的还是 web 相关的端⼝, 涉及的主要为 80 和 443 两个端⼝, 下⾯就来重点说说.端⼝是必须的吗?
在本地 web 开发调试过程中, 我们可能都碰到过端⼝, ⽐如或许是/最著名的 8080 端⼝, ⼀般我们会这样去访问本地的 web 程序:
localhost:8080
但⼀旦 web 程序部署到了正式的⽹站中, 端⼝似乎就消失了, 正式的⽹址中就不需要端⼝了吗?答案是否定的, 在这⾥起作⽤的是缺省值.
⽐如你访问我的⽹站: xiaogd, 这个 url 中似乎没有端⼝, 但其实是有的, 它有⼀个默认值 443, 所以完整的形式实际是这样的:
xiaogd:443.
你可以通过 Chrome 的开发⼈员调试⼯具看到这⼀点:
怎么恢复qq好友可以看到, ip 地址后⾯跟着⼀个 443
如果你输⼊⼀个错误的端⼝, ⽐如 80, 像这样: xiaogd:80, 结果就是⽆法访问.
但是如果你改成 xiaogd:80, 它⼜可以访问了.
注意, 因为我服务器后台配置了 http ⾃动跳转 https 的 301 重定向, 所以最终浏览器
会再次跳转到 xiaogd:443.
注意勾选 'Preserve log' 以保留⽇志, 可以看到第⼀个 80 端⼝的请求会被响应⼀个
301 跳转, 并指⽰跳转⽬标, 也即是 Location 字段中的 https 请求, 浏览器接收此跳转
指⽰并重新发起 https 请求, 也即是图中第⼆个 xiaogd 的请求. 所以地址栏最终还
是会变成 https 的, 特此说明.
此时如果你输⼊ xiaogd:443, 它⼜不能访问了...
那么原因是什么呢? 你到规律了没有?
注意⼀个是 http, ⼀个是 https.
协议的缺省端⼝
当你没有显式的在 url 中输⼊端⼝时, 浏览器实际上会根据所⽤的协议来为你指定⼀个缺省端⼝:
如果是 http 协议, 就使⽤ 80 端⼝
如果是 https 协议, 就使⽤ 443 端⼝
如果你⾃⼰输⼊端⼝呢? 那就⽤你输⼊的端⼝, 你输⼊啥就是啥, 输错了, 访问不了那就是你的责任了, 谁让你瞎搞来着?
本来不⽤你劳神的, 你偏要脱裤⼦放屁, 搞不好⾃然就是画蛇添⾜, 弄巧成拙了.
⽐如上⾯的⽤了 http 却输⼊了 443, 或者⽤了 https 却输⼊了 80, 就⽆法成功访问了.
另外, 如果你胡乱地输⼊⼀个⽐如 9527, xiaogd:9527, ⾃然也是⽆法访问的, 原因也很简单, 因为我的服务器上根本没有在 9527 端⼝上进⾏监听.
即便我有在 9527 端⼝上监听, 提供的也未必是 web 服务, 使⽤的协议可能既不是
http, 也不是 https, 所以你⽤浏览器试图去访问也可能会碰壁的.
当然了, 我是完全可以在服务器上的 9527 端⼝上再部署⼀个 web 服务的, ⽐如放⼀个 apache 或 tomcat server 之类的 web server 监听在那个端⼝上, 再放通防⽕墙, 安全组之类的, 也是可以访问的. 只是我没有这么去做⽽已.
那么为啥⼤家都不在那些奇奇怪怪的端⼝上提供 web 服务呢? 原因其实也很简单, 为了⽅便⽤户, 同时也减轻了⽤户的认知负担.
其实关于⽤户, 你只要记住两点就好了:
1. ⽤户是傻⽠
2. ⽤户是懒汉
深刻地理解了这⼀点, 你才可能成为⼀个好的程序员(包括但不限于产品经理, 设计师...)欧服
其实呀, 何⽌了省略了端⼝呀, 你看看现在的地址栏, 不但 http, https 这些协议省了, 最末尾的斜杠/ 省了, 甚⾄连 www 都省了...
是的, 我也帮你们省了 www, 事实上你通过 www.xiaogd/ 也能访问到, 但如
果通过 xiaogd/ 就能访问到, ⼜何苦去再去录⼊三个达不溜呢?
必须得承认, 缺省的存在是有很⼤的帮助的, 这其实是进步; 但另⼀⽅⾯, 这些缺省有时也会给不明就⾥的开发⼈员带来了⼀些困惑, 好像端⼝不是必要的, 但其实不是这样的.
为什么需要端⼝?火车票放票时间
那为什么⼀定要端⼝这个东西呢? 它到底起了什么作⽤, 想必很多同学想要了解, 下⾯就来说说为什么, ⽽⼀个⾸先需要了解的概念就是进程间通讯(所谓的 IPC(inter-process communication)
进程间通讯(IPC)
你在浏览器地址栏输⼊某个⽹站的域名, 然后回车, 就⽣成了⼀次请求, 然后服务器响应你的请求,浏览器再把结果渲染出来, 你就能最终看到到⼀个⽹页.
如果你曾经 ping 过⼀个域名, ⽐如你现在 ping 我的域名 xiaogd, 你就能得到⼀个 ip 地址, 118.89.55.54:
有了 ip, 浏览器⾃然就能到我的主机, 但还是有个问题, 我的主机上运⾏着好多的进程, 好多的服务, 除了最常见的 web 服务, 我可能还有 ftp 服务, mysql 服务等等不⼀⽽⾜.
简单地讲, 如果⼀个请求只有 ip 地址这⼀信息, 操作系统将不知道把这个请求交给哪个进程去处理, 如果是你来设计整个系统, 你想象⼀下, 是不是这样?
如果你仅仅是输⼊域名, 经过 DNS 解析后, 只能得到⼀个 IP 地址.
所谓的⼀次请求, 从⼀个⽐较底层的⾓度去看, 就是⼀次进程间的通讯.
它可以是 navicat 客户端与 mysql 数据库服务的⼀次通讯, 也可以是 winScp 客户端与 vsftpd FTP 服务的⼀次通讯等等.
以上⾯的具体为例, 可以说就是 Chrome 浏览器这个本地操作系统上的进程与我的服务器上的⼀个叫做 Nginx 的进程间的⼀次通讯.
那么, 所谓的端⼝, 其实可以简单地视作为进程 ID.
当然, 它与进程 ID 还是有不同的, 下⾯再分析, 或者⽬前你可以认为端⼝就是进程 ID
工商银行网银的影⼦.
也即是说, 如果仅有域名(ip), 是⽆法定位到⼀个进程的, 通讯的发起⽅不但需要给出 ip, 还需要给出端⼝, 只有这样, 服务器才能知道由哪个进程去响应.
端⼝, ⼀个间接层
那么问题⼜来了, 为什么引⼊端⼝, ⽽不是直接使⽤进程 ID 呢? 这个原因想想也不难明⽩, ⼤概有这么⼏点原因:
1. 作为客户端⽆法知道服务端对应进程的 ID
2. 服务端对应进程重启后 ID 会改变
3. ⼀个⽹站的 web 进程 ID 是这个, 另⼀个⽹站的可能⼜是另⼀个
⾃然, 原因是很多的, 我也是随便的列举了⼀些, 你或许还能想到更多. ⽽为了解决这些个问题, 就引⼊了端⼝这⼀间接层(indirection).
计算机世界⾥有⼀句名⾔: 任何计算机问题均可通过增加⼀个间接(indirection)层来解
决.(Any problem in computer science can be solved with another layer of
indirection. -- David Wheeler)
这个名⾔其实还有后⾯⼀句: But what usually will create another problem.(但通常会
带来另⼀个问题)
这⾥所谓另⼀个问题, ⽐如它会使得层次结构复杂化, 交互效率下降等等. 当然了, 这
就是架构师们要去权衡的问题了, 很多时候, 架构就是关于平衡的艺术. 打死都不肯引
⼊任何的间接层, 这是⼀个极端; ⽽⼀上来就引⼊好多个间接层, 这⼜是另⼀个极端.
如果没有这个间接层, 客户端要与服务端通讯, 就要知道服务端对应进程的 ID, 也即是客户端是依赖于服务端的:
显然, 这种模式对于 web 这种⼀个服务端对应⼤量客户端访问的情形是极不适应的,
端口被占用你都不知道有谁可能会来访问你的⽹站! 你根本⽆法告诉它们.
⽽有了端⼝这⼀间接层, 对于 web 的情形, 这种依赖被倒置了, 客户端总是把请求发送到 80(或443) 端⼝, 这些成为标准的⼀部分, 并要求服务端反过来去适应, 服务端去监听端⼝的通讯并处理, 变成了⼀种反向依赖.
如果⼀个进程想要提供 web 服务, 它启动之后就要去绑定(binding) web 相关的端⼝,
如果端⼝已经被其它进程绑定了(即所谓占⽤了), 就会绑定失败; ⼜或者被⾃⾝前⼀个
未完全退出的进程占据着, 也会绑定失败, 在开发过程中你可能会遇到类似的问题, ⼀
个 web 进程没有关闭, 你⼜试图启动另⼀个, ⽽两者都⽤了相同的端⼝, 就会产⽣冲
突.
并在其上持续的监听(listen), 同时在有请求到来的时候去响应(response). 这样⼀来, 进程 ID 的问题就消解了:
这类似于⼀个接⼝回调, 浏览器只需要⾯向接⼝索取服务, ⽽⽆需知道接⼝服务的具
体提供者, 这些细节被端⼝层所封装并隐藏起来了.
端⼝这⼀间接层的存在解耦(decouple)了客户端与服务端之间的强依赖, 整个体系变得很灵活.
可以把端⼝视作⼀般编程概念中的接⼝(interface), ⽽想 Nginx, apache, tomcat 等等
可以认为是这个接⼝的不同实现(Implementation).
端⼝与现实世界的⼀个类⽐
为加深理解, 可以举⼀个现实世界中的例⼦. 相信⼤家都有过去市民中⼼办事的经历, ⽐如去办理居住证, 护照, 社保等等业务, 你通常会收到⼀个⼩纸条让你去某个窗⼝办理对应业务, 这个窗⼝其实就类似于端⼝了:
⽐如 80 窗⼝就对应港澳台通⾏证业务
那么你要办港澳台通⾏证, 你就奔向 80 号窗⼝就完了. 你不要去问门⼝保卫处的王⼤爷, 到底是哪位同志办理这个业务.
今天可能是⼩明在办理, 隔了⼏天, ⼩明可能受伤了, 流⾎了, ⼜轮到⼩红在那⾥办理,
⼜过段时间, ⼩红也出意外了, 流产了, ⼜轮到⼩张在办理, ⼜过段时间, ⼩张被发现在
办理业务过程中徇私舞弊, 流放了...
等等, 如果此时你的同事问你怎么办港澳台通⾏证, 你需要知道这些个⼈事变动的细节吗? 根本不

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。