一个完整的软件系统大多数情况下是由多个进程共同协作进行的,哪怕它们在同一台服务器上。所以,进程之间如何进行高效的通信至关重要。
单个应用程序 + 单个数据库这套基础开发套餐我相信每个人都经历过,甚至在初期它们还有可能部署在同一台服务器上。
既然应用程序和数据库分属于两个不同的进程,所以这个问题本质上还是两个进程之间的通信问题。
两个进程之间如果要通信,很显然必须要建立一个连接,通过它来相互传输数据。
原则上,如果两个进程在同一台服务器上,有很多种方式可以进行相互通信。
不过在分布式系统中,不同的进程很多时候被部署在不同的服务器上,所以我们这次只聊基于 TCP/IP 的通信方式,因为对大家来说这是最普遍会用到的方式,不管是应用程序间的远程调用(RPC)还是应用程序与数据库间的调用(DAL),皆是如此。
通过套接字(socket)建立连接
socket 与 TCP/IP 之间是唇齿相依般的关系,联系紧密,先来看下维基百科对 socket 的定:
socket 是计算机网络中用于在节点内发送或接收数据的内部端点。
具体来说,它是网络软件 (协议栈) 中这个端点的一种表示,包含通信协议、目标地址、状态等,是系统资源的一种形式。
它在网络中所处的位置大致就是下面的黑色部分,应用层与传输层之间。
其中的传输层就是 TCP/IP 所在的地方,而你平时通过代码编写的应用程序大多属于应用层范畴,socket 在这里起到就是连接应用层与传输层的作用。
socket 的诞生是为了应用程序能够更方便的将数据经由传输层来传输,所以它本质上就是对 TCP/IP 的运用进行了一层封装,然后应用程序直接调用 socket API 即可进行通信。
那么它是如何工作的呢?
它分为 2 个部分,服务端需要建立 socket 来监听指定的地址,然后等待客户端来连接。而客户端则需要建立 socket 并与服务端的 socket 地址进行连接。
这图展示的就是建立 TCP/IP 连接的过程,经典的叫法为“三次握手”的过程。顾名思义,这个过程中来回产生了三次网络通信。
接下来的数据传输过程就简单很多,发送数据就是客户端往服务端通信,服务端处理完之后的数据返回则相反。
值得注意的是,传输的过程涉及到数据 Copy,不过这些 Copy 是必不可少的。其中的发送缓冲区和接收缓冲区就是套接字缓存 (socket buffer)。
连接使用完之后需要关闭,不过 TCP/IP 连接关闭过程比创建更复杂一些,次数多了一次,这就是经典的“四次握手”过程。
简单总结一下 socket。
socket 是进程间数据传输的媒介,为了保证连接的可靠,你需要特别注意建立连接和关闭连接的过程。
为了确保准确、完整的数据传输,客户端和服务端来回进行了多次网络通信才得以完成连接的创建和关闭,这同时也是你在运用一个连接时所花费的额外成本。
基于 socket 我们可以选择建立长连接或者短连接,在实际运用中两者都有可能被用到。
长连接
长连接,也叫持久连接,在TCP层握手成功后,不立即断开连接,并在此连接的基础上进行多次消息(包括心跳)交互,直至连接的任意一方(客户端OR服务端)主动断开连接,此过程称为一次完整的长连接。HTTP 1.1相对于1.0最重要的新特性就是引入了长连接。
短连接
短连接,顾名思义,与长连接的区别就是,客户端收到服务端的响应后,立刻发送FIN消息,主动释放连接。也有服务端主动断连的情况,凡是在一次消息交互(发请求-收响应)之后立刻断开连接的情况都称为短连接。
注:短连接是建立在TCP协议上的,有完整的握手挥手流程,区别于UDP协议。
如何快速区分当前连接使用的是长连接还是短连接
1、凡是在一次完整的消息交互(发请求-收响应)之后,立刻断开连接(有一方发送FIN消息)的情况都称为短连接;
2、长连接的一个明显特征是会有心跳消息(也有没有心跳的情况),且一般心跳间隔都在30S或者1MIN左右,用wireshark抓包可以看到有规律的心跳消息交互(可能会存在毫秒级别的误差)。
什么时候用长连接,短连接?
1、需要频繁交互的场景使用长连接,如即时通信工具(微信/QQ,QQ也有UDP),相反则使用短连接,比如普通的web网站,只有当浏览器发起请求时才会建立连接,服务器返回相应后,连接立即断开。
2、维持长连接会有一定的系统开销,用户量少不容易看出系统瓶颈,一旦用户量上去了,就很有可能把服务器资源(内存/CPU/网卡)耗尽,所以使用需谨慎。
我们回到前面提到的维基百科对 socket 的定义,其中说到socket 包含通信协议、目标地址、状态等。
实际当你在基于 socket 进行开发的时候,这些包含的具体资源主要就是这 5 个:源 IP、源端口、目的 IP、目的端口、协议,有个专业的叫法称之为“五元组”。
在一台计算机上只要这五元组的值不重复,那么连接就可以被建立。然而一台计算机最多只能开启 65535 个端口,如果现在两个进程之间需要通信,作为服务端的 IP 和端口必然是固定的,因此单个客户端理论上最多只能与服务端同时建立 65535 个 socket 连接。
如果除去操作系统和其它进程所占用的端口,实际还会更少。所以,一旦使用不当,在很短的时间内建立了大量连接,端口很容易被占用完。这不但会导致自身无法正常工作,还会影响到同一台计算机上的其它进程。
看清socket编程
https://www.cnblogs.com/fengff/p/10984251.html
跨进程通信,到底用长连接还是短连接
https://www.pianshen.com/article/4900105171