在网上看了很多帖子,也一直没有时间去看操作系统底层设计,之前一直想不通监听端口这个概念到底在程序层面怎么实现的,今天将我的猜想总结在这里,如有不对,欢迎拍砖,这里纯属记录下自己的整体构想。
第一点:操作系统启动
如果我们要用java启动一个应用,那么就会有一个程序死循环,这个死循环,会一直在调度有没有待执行的操作,猜想,操作系统启动之后,应该也有一个死循环,且频率很高,能定时处理程序,时序调度,在操作系统中应该非常复杂。
第二点:网络控制
计算机网络里面都有IP和端口号两个概念,前者是给主机用的,后者是给主机中的网络进程用的,所以,一个进程如果想从操作系统的网络层面收到消息,那么就应该将自己注册到操作系统中去,也就是往操作系统的这段程序的追加一段代码。
形式应该是
port['8080'].push( () =>{ xxx }),port['8080']是放8080数字,后面的代码是往这个数字里追加一段很长很长的代码(代码打包后都很大),实际操作应该就是把某个代码的指针头扔过来即可,实际运行时,再在内存里组织上下文。
同一个端口号不能注册多个事件,所以这里的push应该用的不太严谨,应该就是Map键值对的方式进行注册的,一台机器你只能启动一个端口,再次启动会报端口占用,好处是避免消息被截停?如果允许多监听,就像javascript的hook技术,的确是有信息泄露的风险。
第三点:操作系统拉起程序
我之前的直观感受是我写的这个程序启动后,收到消息开始运行的,实际上是我的这段程序只是操作系统的一个启动进程,代码是挂载到操作系统的,也即控制反转,我的所有代码都是嵌套在操作系统代码里面的,有了消息,操作系统通过调用进程,让进程执行具体的函数,这样的思考才是合理的。
第四点:端口对应的是进程
端口对应的是一个独立的进程,如果启动多个进程请求同一个端口,写入的数据都是同一个进程处理,入库的也是同一个文件
第五点:单台机器多用户开启的多软件怎么实现的?
进程间通信,这个是如何实现的,我还没具体了解,每个软件使用的用户目录是隔离的,文件也是隔离,也即相当于这个用户启动了一个应用的新进程,而应用内部使用的是进程间通信机制,所以数据互不干扰
第六点:如果一个应用本身启动了一个server.listen('8080') 子服务
这就是最近碰到的问题,在进程间通信上,讲解来回通信,如果通信横跨多个进程,就会有多个on/send代码,每个进程间都会有一个,这样2-3中进程间就会有大量处理这种通信中转的代码,微服务链路的跟踪也是这个概念,一旦进程间通信链路多了,异常报错就不好跟踪。
为了缩短通信链路,就想到了启动一个中心服务,也即注册到操作系统级别,给各个进程进行中转。
但一台机器只允许一个进程监听一个端口,如果一台机器多个用户,同时启动监听同一端口号的服务,就会抛出端口已被占用异常,此外,其他用户的数据都会写到第一个启动服务的用户数据里。
第七点:使用动态端口解决同机多用户问题
不过这也是个风险点,其他软件开发者也有这样的想法,不过端口号六万多个,理论上还是够用的
第八点:启动服务耗费大量内存吗?
理论上启动一个服务不会耗费cpu,因为就是将一段代码挂载到操作系统上,如果有发到该端口的消息,操作系统拉起具体的回调函数而已,这和你自己写一个while死循环完全不是一个概念,while死循环,是真耗费cpu的,所以能写服务肯定要写服务也不能写while循环的服务,后者是low到家了。
内存的耗费要看你这个服务框架是否是轻量级,代码多少直接决定了占用内存的多少,但是这个占用量也是极少的,一个http-server,或者一个Express框架顶多几M就就行了,最重要的执行服务时,内存要及时释放,要以传参方式给,不能引用父作用域,导致变量无法释放,只会一直上涨,造成内存溢出。