常说的监听某个端口,是什么意思?怎么理解?

 点击上方“分布式实验室”关注公众号

回复“1”抽取纸质技术书

今天这篇文章,想用一个故事和你讲讲端口监听是怎么回事。耐心往下看。

在学生会大楼的角落里,有一家咖啡店,在咖啡店的角落里有两个学生。利兹敲打着她哥哥在她搬到大学时给她的那台破旧的手摇MacBook的键盘。在她左边的长椅上,蒂姆在一个装订成卷的笔记本上写着公式。他们之间有一杯半空的常温咖啡,莉兹不时地喝上一口以保持清醒。

蒂姆写到一半就停笔了,把这张纸从笔记本上撕下来,揉成一团,放在其他揉成一团的小纸片旁边。

“Shit,现在几点了?”他问到。

利兹看了看她笔记本上的时钟,“刚过两点”。

蒂姆打了个哈欠,又开始在新的一页上面涂鸦,但利兹打断了他。

“蒂姆”

“什么?!”,蒂姆回答说,夸张地表达了他对刚开始写就被打断的恼怒。

“在一个端口上监听是什么意思?”

“呃嗯……”

“我必须为net写这个网络服务器的东西”,net是Computer Networks 201的缩写,这是蒂姆在上学期上的一门课。

“是的,我记得那门课。”

“所以我在一个端口上监听连接。”

“80端口”,蒂姆自信地回答,希望通过抢先回答她的问题来缩短谈话时间。

“实际上,我们应该监听8080,这样它就可以在没有root的情况下运行,但这不是重点。”

“哦,对了。那是什么?”

“好吧,监听一个端口是什么意思?”

“它意味着其他进程可以在该端口上连接到它。”蒂姆对这个问题显得很困惑。

“是的,我知道这一点,但怎么做?”

蒂姆考虑了几秒钟才回答。

“我猜操作系统有一个大的端口表,以及在这些端口上监听的进程。当你绑定到一个端口时,它就会在该表中放一个指向你的套接字的指针。”

“是的,我猜。”利兹说,语气中带着犹豫和不满意。

两人回到了他们各自的工作中。沉默了一段时间后,蒂姆小声嘀咕了一句胜利的 “是的!”,并在一张打印的纸上划掉了一个数字。他终于找到了他在微积分作业中一直纠结的一个证明。

利兹趁机再次引起他的注意。

“嘿,蒂姆,看,我正在同时运行绑定在同一端口的两个进程。”

她调整了两个包含Python代码的窗口的大小。

# server1.py
import socketsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('127.0.0.1', 8080))
sock.listen()
print(sock.accept())

然后在它旁边是另一个程序:

# server2.py
import socketsock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('127.0.0.1', 8080))
print(sock.recv(1024))

然后她向他展示了这两个程序在各自的终端窗口中运行,通过Shell连接到大学的cslab3Debian服务器。

蒂姆将笔记本电脑转向自己。他打开第三个终端,停顿了一会儿,搜索他疲惫的大脑,然后输入netcat 127.0.0.1 8080。

netcat 运行后立即退出。在另一个终端窗口中,正在运行的 python server1.py 程序退出,打印。

(<socket.socket fd=4, family=AddressFamily.AF_INET,
type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8080),
raddr=('127.0.0.1', 59558)>, ('127.0.0.1', 59558))

他边研究server1.py代码,边自言自语。

“好的,服务器绑定了一个端口,接受了第一个连接它的套接字,然后退出。我明白了,所以它打印的元组是accept调用的结果,然后它立即退出。但是现在......”,将鼠标光标移到显示 server2.py 的编辑器上,“……这一个甚至在听吗?”

他在与之前相同的终端中再次运行netcat 127.0.0.1 8080 -v,结果打印出来如下:

netcat: connect to 127.0.0.1 port 8080 (tcp) failed: Connection refused

“看”,他说,“你的代码中存在一个错误。server2仍在运行,但你从未调用listen。它实际上没有对8080端口做任何事情。”

“当然是,看”,利兹说,抢回了她的笔记本电脑。

她在“netcat”命令的末尾加了一个-u,然后点击回车。这一次,它没有给出一个错误或立即退出,而是等待键盘输入。她对Tim这么快就认为她的代码有问题感到恼火,她敲出了timmy,知道这个绰号让他很不爽。

netcat会话无声无息地结束了,同时,python server2.py程序退出打印。

b'timmy\n'

蒂姆意识到利兹试图与他作对,但没有理会,不想让她满足于对他的挑衅。他向键盘做了个手势。利兹把笔记本扭向他的方向,他输入man netcat',调出netcat的手册,其中描述该工具为“TCP/IP瑞士军刀”。他向下滚动到-u标志,文件将其简单描述为 “UDP模式”。

“啊”,他说,因为他突然想起了什么。“我明白了,server1是通过TCP监听,server2是通过UDP监听。这一定是SOCK_DGRAM的意思。所以它们是不同的协议。我猜操作系统为每个端口都有一个单独的表格。我没想到net涵盖了UDP,直到后来。”

“是的,我提前读了。”

“当然。你怎么会有时间提前阅读,却没有时间在早晨到期前完成这些作业呢?”

“我也可以问你关于Counter Strike的问题”,莉兹反问道。

蒂姆哼了一声。

他们又继续默默地工作了几分钟,然后莉兹打破了沉默。

“嘿,蒂姆,看看这个。我可以在同一个端口上监听两个进程,即使它们都是TCP。”

蒂姆从他的工作中抬起头来。这次利兹在屏幕上只有一个Python程序,而且是在两个终端中运行:

# server3.py
import socketsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
sock.bind(('127.0.0.1', 8080))
sock.listen()
print(sock.accept())

利兹解释说:“看,这个命令显示什么进程正在监听一个端口”。她输入了lsof -i:8080,然后点击回车。

程序打印:

> lsof -i:8080
COMMAND    PID USER   FD   TYPE   DEVICE SIZE/OFF NODE NAME
python3 174265 liz     3u  IPv4 23850797      0t0  TCP localhost:http-alt (LISTEN)
python3 174337 liz     3u  IPv4 23853188      0t0  TCP localhost:http-alt (LISTEN)

“当你连接到它时会发生什么?”,蒂姆问道,这次他的声音中带着一点真正的好奇心。

“看吧。”

利兹运行了一次netcat localhost 8080,其中一个服务器进程退出,而另一个则继续运行。然后她再次运行,另一个进程退出。

蒂姆的注意力转到了代码上,他把手指放在屏幕附近,读了一遍。莉斯讨厌被弄脏的屏幕,她说:“别紧张!”并把他的手推了回去。“我不会碰它”,他抗议道。他做了一个夸张的表演,让自己的手保持一个安全的距离,他指着setsockopt一行,问道:“嘿,这是什么巫术?”

“那是设置一个套接字选项,允许端口被重复使用。”

“哼,这在教科书上有吗?”

“不知道,我在Stack Overflow上找到的。”

“我不知道你可以这样重复使用一个端口。”

“我也不知道”,她停顿了一下,考虑了一下。“所以操作系统不能只是有一个端口到套接字的表格,它必须是一个端口到套接字的列表的表格。然后为UDP建立第二个表格。也许还有其他协议的。”

“是的,这听起来很对”,蒂姆同意。

“嗯”,利兹说,突然听起来不太确定。

“什么?”

“呃,没关系”,她说,她开始认真地敲打。

蒂姆回到他的任务上,几分钟后,他又划掉了一个问题。他快要完成了,他的神情也放松了一些。利兹将她的笔记本电脑向他倾斜,说“看看这个”。她给他看了两个程序:

# server4.py
import socketsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('127.0.0.2', 8080))
sock.listen()
print(sock.accept())

在它的旁边。

# server5.py
import socketsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('127.0.0.3', 8080))
sock.listen()
print(sock.accept())

“这些不是一样的吗?”蒂姆问道,一边研究它们。

“看一下绑定的IP。”

“哦,所以你是在同一个端口上监听,但有两个不同的IP。这能行吗?”

“似乎是的。而且我可以连接到他们两个。”

利兹运行netcat 127.0.0.2,然后netcat 127.0.0.3,给他看。

蒂姆思考了一下。“所以让我看看。操作系统必须有一个表,从每个端口和IP组合,到一个套接字。实际上,有两个:一个用于TCP,另一个用于UDP。”

“是的”,利兹点点头。“而不是只有一个套接字,可以是多个。但要注意这个。”她把服务器代码中的IP改为 0.0.0.0。

# server6.py
import socketsock socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('0.0.0.0', 8080))
sock.listen()
print(sock.accept())

“现在,当我运行绑定到127.0.0.2的服务器时,我得到了这个”,她继续说。

Traceback (most recent call last):File "server5.py", line 4, in <module>s.bind(('127.0.0.2', 8080))
OSError: [Errno 99] Cannot assign requested address

“但是”,她总结道,“如果我运行netcat 127.0.0.2 8080,就会连接到0.0.0.0上的服务器”,并给他看。

“对,0.0.0.0意味着'绑定所有本地IP',讲课时没有讲到吗?而以127.开头的地址是本地回环IP,所以它们被它绑定是有道理的。”

“是的,但它是如何工作的?大约有1600万个IP是以127.开头的。它不会用所有的人做一个大表,对吗?”

“我猜不是。”他没有答案,于是改变了话题。“那么无论如何,HTTP服务器的情况如何?”这是个反问句,他知道她没有写过一行实际的任务代码。

“是的,是的”,她回答说,已经潜心于另一个实验。

又过了一段时间。蒂姆刚刚完成他的任务,闲来无事地查看他手机上的时间。他考虑回家去睡他那凹凸不平的宿舍床垫。他感觉了一下,觉得长椅也差不多舒服,于是把头向后仰,靠在高高的垫子椅背上。

他正盯着天花板,半梦半醒间,莉兹捅了捅他,说:“蒂姆,看看这个”。

她给他看了另一个程序。

# server7.py
import socketsock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
sock.bind(('::', 8080))
sock.listen()
print(sock.accept())

“看看这个。这是一个IPv6服务器。”

蒂姆打了个哈欠,靠了过来。此时,早晨的阳光已经开始透过他们所坐的长椅后面的窗户出现。另外两个学生在凌晨时分已经悄悄地离开了,店里今天的第一位顾客已经到了,正在等待她的外带咖啡。

“冒号是什么来着?”蒂姆问道。

“这是IPv6中八个零的简称,与IPv4中的 0.0.0.0 含义相同”。

“所以这是说要监听所有本地的IPv6 IP?IPv6是这样工作的吗?”

“是的,基本上是这样。”

她输入netcat "::1" 8080 -v,解释说:“::1是IPv6的回环地址。它就像'家'。”

“所以就像常规IP中的127.0.0.1”

“IPv4。是的,没错。但要注意这个。根据lsof,我只在IPv6上收听,看到了吗?”利兹运行lsof -i :8080,打印出一行。

COMMAND    PID USER   FD   TYPE   DEVICE SIZE/OFF NODE NAME
python3 455017 liz     3u  IPv6 25152485      0t0  TCP *:http-alt (LISTEN)

“但是",利兹继续说,“我可以通过一个IPv4的IP连接到它。”

netcat 127.0.0.1 8080 -v

“哼”,蒂姆喃喃道。“那另一种方式呢?你能从一个IPv6 IP连接到一个IPv4服务器吗?”

“不,看这个。”

她运行了python3 server6.py,然后netcat "::1" 8080 -v,打印出了:

netcat: connect to ::1 port 8080 (tcp) failed: Connection refused

蒂姆问:“如果你试图在IPv6上开始监听8080,而那个IPv4服务器仍在运行,会发生什么?”

利兹给他看,运行python server7.py。

Traceback (most recent call last):File "server7.py", line 4, in <module>s.bind(('::', 8080))
OSError: [Errno 98] Address already in use

“但看看这个”,她说,拉出了另一个代码列表。

# server8.py
import socketsock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)
sock.bind(('::', 8080))
sock.listen()
print(sock.accept())

她指着setsockopt一行,解释说:“当我添加这个时,我可以从不同的进程监听同一端口上的IPv6和IPv4。”

她运行python server8.py,然后lsof -i :8080。

COMMAND    PID USER   FD   TYPE   DEVICE SIZE/OFF NODE NAME
python3 460409 liz     3u  IPv6 25188010      0t0  TCP *:http-alt (LISTEN)
python3 460813 liz     3u  IPv4 25191765      0t0  TCP *:http-alt (LISTEN)

蒂姆清点了利兹给他看的东西。“所以当你在一个端口上监听时,你实际上是在监听一个端口、一个IP、一个协议、和一个IP版本的组合?”

“是的,除非你在所有的本地IP上监听。如果你在所有IPv6 IP上监听,你也会在所有IPv4 IP上监听,除非你在调用绑定之前特别要求不要这样做。”


“对。因此,操作系统必须有一个从端口和IP对到套接字的哈希图,用于TCP或UDP、IPv4或IPv6的每个组合。”

“到一个套接字的列表”,利兹纠正说。“还记得我是如何监听不止一个的吗?”

“哦,是的。”

“但它还必须处理对所有'家庭'IP的监听,并且能够从一个IPv4 IP上找到一个监听IPv6的套接字。”

“不管怎么说,我得把这个交上去”,蒂姆说着,指了指他手中松散的文件集。“你打算在交稿前完成那个HTTP服务器吗?”

利兹耸耸肩:“我有一个空闲的晚间时间可以利用。”

蒂姆摇了摇头,像极了老父亲般的不赞成。

丽兹翻了个白眼,说:“走吧,蒂姆。”

“下周同一时间?”

“是的。”

推荐阅读:《案例:vivo基于Java技术栈的实时监控系统》


点击下方卡片关注分布式实验室,和我们一起

关注分布式最佳实践

42c9d0a2b993e95693771b8862336da9.png

 点击上方卡片关注分布式实验室,掌握前沿分布式技术

新的一年,想一起学习K8s、考CKA证书吗?来,这里有最好的学习方案,线下3天封闭式培训,15人小班课,考不过免费复训。Kubernetes实战班上海站3月25日开班,扫描下方二维码了解详情。

c848967b2662c7268746a73fd614d253.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/256350.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

RWKV – transformer 与 RNN 的强强联合

在 NLP (Natural Language Processing, 自然语言处理) 领域&#xff0c;ChatGPT 和其他的聊天机器人应用引起了极大的关注。每个社区为构建自己的应用&#xff0c;也都在持续地寻求强大、可靠的开源模型。自 Vaswani 等人于 2017 年首次提出 Attention Is All You Need 之后&am…

chatgpt赋能python:Python中的或运算:学习这个重要概念

Python中的或运算&#xff1a;学习这个重要概念 或运算是Python编程语言中一个重要的概念。了解如何使用或运算可以帮助程序员编写更有效和有意义的代码。在此文章中&#xff0c;我们将介绍Python中或运算的基础知识以及如何使用它来编写各种类型的代码。 什么是或运算&#…

智慧工厂主题 Meetup 线下报名+福利开启!IoTDB X EMQ 构建数据平台赋能智能制造...

随着全球制造业的竞争日益激烈&#xff0c;智慧工厂成为当今制造业的重要趋势之一。智慧工厂采用了先进的物联网、大数据等科技手段&#xff0c;以期通过智能化、数字化管理和生产&#xff0c;实现高度自动化和高效生产。因此&#xff0c;如何通过计算分析挖掘生产数据价值&…

《计算机组成原理》唐朔飞 第8章 CPU的结构和功能 - 学习笔记

写在前面的话&#xff1a;此系列文章为笔者学习计算机组成原理时的个人笔记&#xff0c;分享出来与大家学习交流。使用教材为唐朔飞第3版&#xff0c;笔记目录大体与教材相同。 网课 计算机组成原理&#xff08;哈工大刘宏伟&#xff09;135讲&#xff08;全&#xff09;高清_…

常用方法——7.JS 给数组排序 es6

let arrObj[{"name": "银行转账","value": 2}, {"name": "支付宝支付","value": 1}, {"name": "微信支付","value": 0} ] arrObj.sort((a,b)>{ return a.value-b.value})//升序…

JS数组对象排序(es6)

效果&#xff1a;升序&#xff1a; 降序&#xff1a; 升序是&#xff1a;a.value-b.value 降序是&#xff1a;b.value-a.value 代码&#xff1a; let arrObj[{"name": "银行转账","value": 2},{"name": "支付宝支付","…

微信小程序根据日期和时间进行排序

一、前言 最近接手了一个小程序的项目&#xff0c;有这样一个需求要对列表进行日期和时间的排序&#xff0c;于是小试牛刀&#xff0c;操作了一番&#xff0c;终于搞出来&#xff0c;在这里给大家总结分享一下经验&#xff0c;希望对大家有一定的帮助。 二、需求分析&#xf…

代码覆盖率

在做单元测试时&#xff0c;代码覆盖率常常被拿来作为衡量测试好坏的指标&#xff0c;甚至&#xff0c;用代码覆盖率来考核测试任务完成情况&#xff0c;比如&#xff0c;代码覆盖率必须达到80&#xff05;或 90&#xff05;。于是乎&#xff0c;测试人员费尽心思设计案例覆盖代…

【零散技术】微信小程数组排序

序言:时间是我们最宝贵的财富,珍惜手上的每个时分 目录 一&#xff1a;业务功能 二&#xff1a;代码实现 在国内&#xff0c;微信小程序的生态已经完全渗透至各行各业&#xff0c;无一幸免。 今天分享一个常用组件的功能&#xff1a;排序 一&#xff1a;业务功能 以订单排序…

js--数组排序

微信扫码关注公众号 &#xff1a;前端前端大前端&#xff0c;追求更精致的阅读体验 &#xff0c;一起来学习啊关注后发送关键资料,免费获取一整套前端系统学习资料和老男孩python系列课程 学习资源推荐 js [1,5,3].sort(function (a,b) { return a-b; }) //[1,3,5] [1,5,3].s…

数组方法 sort() 排序错乱问题

一、问题 在JavaScript中&#xff0c;数组使用sort()后发现有排序不正确的情况&#xff0c;如下&#xff1a; let arr [1, 2, 3, 10, 20, 30] arr.sort() console.log(arr) // [1, 10, 2, 20, 3, 30] 二、原因 其实&#xff0c;sort方法会调用每个数组元素的toString方法得…

Js数组排序函数:sort()

原文链接&#xff1a;https://blog.csdn.net/qq_37936542/article/details/78979521 js原生的 sort() 排序函数使用起来很方便 语法&#xff1a;arrayObject.sort(fun) 数组对象.sort(排序函数) 如果调用该方法时没有使用参数&#xff0c;将按照字符编码的顺序进行排序。…

JS常用的6种数组排序

目录 1&#xff0c;冒泡排序2&#xff0c;快速排序3&#xff0c;插入排序4&#xff0c;选择排序5&#xff0c;希尔排序6&#xff0c;归并排序7&#xff0c;六种方法的集合 1&#xff0c;冒泡排序 冒泡排序又称为交换排序。原理是从第一个元素开始&#xff0c;比较相邻元素的大小…

JS数组排序技巧汇总(冒泡、sort、快速、希尔等排序)

本文实例总结了JS数组排序技巧。分享给大家供大家参考&#xff0c;具体如下&#xff1a; 1、冒泡排序 var temp 0; for (var i 0; i < array.length; i) { for (var j 0; j < array.length - i; j) { if (array[j] > array[j 1]) { temp array[j 1]; array[j 1…

js数组按照下标对象的属性排序

微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 根据数组中某个参数的值的大小进行升序 <script type"text/javascript">function compare(val) {return function (a, b) {var value1 a[val];var value2 b[val];return value1…

JavaScript-数组乱序

前言 对数组进行排序对我们来说很容易就能够实现&#xff0c;但是你有考虑过如何对一个有序的数组实现乱序&#xff0c;即随机排序吗&#xff1f; 数组乱序在实际开发过程中是可能碰到的&#xff0c;下面我们一起看看如何实现数组乱序。 欢迎关注我的微信公众号&#xff1a;前…

微信小程序:Array数组的操作

Array 对象方法 方法描述concat()连接两个或更多的数组&#xff0c;并返回结果。copyWithin()从数组的指定位置拷贝元素到数组的另一个指定位置中。entries()返回数组的可迭代对象。every()检测数值元素的每个元素是否都符合条件。fill()使用一个固定值来填充数组。filter()检…

js 数组排序

代码改变世界 Posts - 29, Articles - 0, Comments - 62 Cnblogs Dashboard Login HOMECONTACTGALLERYRSS 那时候的我github&#xff1a;https://github.com/lwzhang js中的数组对象排序 2014-04-27 19:15 by 那时候的我, 66416 阅读, 2 评论, 收藏, 编辑 一、普通数组排序…

微信小程序——数组操作 (增加删除修改遍历)map、filter、forEach、find的用法、二维数组,排序,求和、指定长度数组赋值

一、数组的操作 Array.push() ->在数组后面继续插入内容 Array.pop() ->拿走数组最后一个内容 Array…shift()->拿走数组的第一个内容 (unshift也是拿走最后一个) Array.reverse()->对数组从大到小排列 Array.sort()->对数组从小到大排列** Array.splice(起始…

js数组排序实用方法集锦

js数组排序实用方法集锦 前言&#xff1a; 据说程序员三个月就能忘记自己写的代码&#xff0c;所以最好是在有空的时候及时做些总结&#xff0c;记录下来&#xff0c;这样后边遇到类似问题的话&#xff0c;就可以直接先查看自己的博客了。写技术博客&#xff0c;对自己是一种总…