Push推送
Push推送即:要求必须有一种方式使得服务端的消息可以即时让客户端收到。
实现的方式:
一、APP主动轮询:
APP开启一个服务,并定时到服务器上进行查询,该种方式实现简单,但是非常的消耗服务器资源,而且随着客户端数量的增加,对服务器资源的开销也会固定增加。这是因为轮询方式的实现,必然要求客户端定时的去向服务端进行查询,同时为了能让客户端可以及时获得最新的消息,那么轮询的间隔也必定不能太长。
服务器为了响应客户端的轮询,必然会消耗CPU等资源,因此当客户端数量较少,服务端必然能够及时处理并响应。但是随着客户端数量增多,在同一个轮询间隔内。要求能够得到响应的客户端数量也会增多。因此要求服务端的响应速度也会越来越高。然而服务端的处理速度最终是有限的,因此在同一个轮询间隔内,能够响应的客户端数量也会有一个上限。当客户端的数量超过这个上限之后。就无法使得客户端可以在设定的轮询间隔内得到及时响应。从而导致请求堆积。并且由于在轮询间隔内还会有请求到来。这样随着时间的推移。堆积的请求也会越来越多。服务器的可用资源会变少。这样又会导致处理速度变慢。形成恶性循环。最终服务器瘫痪。同时,客户端得到的响应时间也会因为堆积,而变长。最终导致整个系统变得响应时间长,服务器也不稳定。
举个形象的示例,服务端是一个服务机构,他有服务人员可以处理大家的请求,并且每个服务人员处理请求处理的时间是尽快,但不管怎么快,终归有一个极限。然后现在有一群客户会在固定的周期内去做请求。那么以固定周期除以服务人员处理请求的极限速度时间,就会得到每个服务人员周期内最大可以处理多少个客户,在乘上服务机构人员总数,就是服务机构周期内可以处理的极限客户个数。在极限内请求都可以得到及时处理。但是当超过极限后,就会造成超过部分必须排队安排到下一周期,于是响应周期变长。然而请求周期并为因此改变,因此在下一周期会有同样多的请求过来。于是在下下个周期超过的部分会更多,响应变的更长。形成恶性循环,导致累积请求越来越多。响应越来越慢。
同时为了维护队列,又需要安排服务人员,于是处理极限个数也会下降。这将加重服务器负担。随着时间推移,最终可以处理请求的服务人员被耗光全部去维护队列了。。服务器崩溃。。
当然以上都是计算的极限理想状况。虽然这种情况可以通过调整服务器资源总数,优化排队方式(比如超时放弃等等),调整请求周期等等进行改善。但是资源总是有限的,优
化也是要牺牲部分客户的响应的,请求周期也不可能无限拖长等等。所以这种方式受到本身系统设计的限制很大。
同时这种方式的效率也很低,因为不管服务了多少客户。其中有效服务,即有消息供应的服务其实很少。大部分都是无效的服务。这也是对服务器资源的浪费。
二、APP客户端建立服务器:
这种推送方式通过在APP客户端建立一个微型服务器,并将服务地址反馈到服务端,使得服务端在收到消息后,可以立即投递给对方。
这种工作方式有点类似于邮递员,客户依然是普通的居民,当他需要投递消息的时候将消息直接投递到邮局。邮局再查看你收件方是否有设置收件邮筒。如果有设置,那么邮局就将消息投递到收件方设置地址上的的邮筒内;如果没有设置邮筒,则先放入邮局自己的仓库内,待对方设置好后再存放进去。然后居民可以选择自查自己的邮筒或者邮筒自动通知。
这种方式的结构也比较简单,消耗的资源也比方式一少,效率也很高,稳定性好。不用排队,按需供应。即使同时要求服务的人员众多。但是也只保证在需要服务的时候才给对方服务。保证了所有的服务都是有效的服务。因此效率很高。
不过这种方式的问题就在于邮筒设置上。由于我们现在的ip资源有限,无法保证所有设备都有一个唯一的公网地址。因此地址被分成了公网地址,和局域网资源地址。同一个局域网的所有设备共用一个公网IP地址进行服务。而邮筒投递又是在公网内。我们自己的APP在局域网设置邮筒之后,不管是告诉邮局共用公网地址还是局域网地址,都无法保证服务。这是因为设置为局域网,邮局找不到或者找到的是找到的是服务器自己所在局域网的地址,因而无法保证服务;如果设置为公网地址,如果公网没有设置服务转接(通常都是不设置的)。那么找到了地址,该地址也不存在邮筒。
由于受到上述原因的IP资源的限制。所以难以实现。
三、通过在客户端和服务端之间建立长链接的方式
在了解这种方式前,先来简单的了解一下什么是TCP/IP。
了解过网络通信机制的同学都知道在网络通讯中有国际标准的7层蛋糕和实际使用的5层蛋糕,但是不管是那种标准在TCP/IP这一层都是相同的,我们在进行网络编程的时候,也通常是从这一层开始。也就是说,我们进行网络编程的时候就是用这一层来传输数据的。至于像HTTP协议这种,其实他们都是一种应用协议。他们会有自己的数据格式。
举个例子来说,IP/TCP就是邮局的信封。而HTTP等等应用协议的内容都是写在信纸上然后放到信封里寄给对方的。和寄邮件一样,进行网络应用编写的开发人员一般都不关心邮件系统是怎么工作的。我们只需要知道,我们把自己的邮件内容填写好,放到信封,填好地址收件人等丢入邮筒,然后一段时间后这封信就会出现在对方手里,而对方收到信后也不需要知道,这封信是怎么过来的,经历了些什么。他要做的就是记下发件人的地址以及发件人,然后撕开信封查看邮件内容。
在以上过程中,可以看出邮局并不关心,你的邮件内容是什么或者是什么格式的。同时使用邮件系统的人也并不关心邮件是经历了些什么。他只关心,邮件内容是什么。两者之间的接口就是发件人名字地址和收件人名字地址。对应到TCP/IP里面。收发件人的地址就相当于收发IP地址,而收发件人名字则相当于收发端口,邮件内容则相当于TCP/IP报文。这就是TCP/IP和上下层之间连接接口。
而TCP/IP协议本身则除了规定以上的对上层接口之外,还规定了自己的系统怎么工作,又怎么和更下层的协议交互,还有IP地址格式等等内容。不过这些我们都不需要关心。就好像我们不需要关心邮局是怎么转运邮件的一样。因为我们不是邮局系统的开发人员。
简单讨论了TCP/IP之后,接下来简单讨论下HTTP协议等等应用协议。
就像刚才提到过的TCP/IP协议像邮局一样提供了一个信封给我们传输自己的信件,那么信件除了是普通的家书,那么也照样可以是其它的按照协议约定构造起来的一封文书。比如律师函,offer,合同协议,贺卡,照片,U盘等等。不管是什么样的内容,当我们拿到邮件后,都可以按照约定的方式进行解读,得到我们需要的信息。比如从合同协议里,我们可以解读出,合同的签订时间,签约双方,公证法律效力等等。与之类似,HTTP等应用协议也是如此,它约定了一种信息的组织方式。然后通过这种约定可以进行信息的互换。获得双方都能解读的内容。为什么要进行约定呢?假设一下如果你油价的一张手绘的贺卡,但对方却尝试当成律师函进行解读。显然大多数时候都解读不出来有用的信息。而我们之所以能够正确进行解读,就是因为我们拿到内容之后,能够看明白是什么东西,然后尝试用那种格式进行解读。得到对方要传递的信息。
而HTTP等应用协议正是做了这样约定。约定了信息的传输格式。包括请求行,请求头,空白行作为头的结束,以及请求体,以及文件的编码(好比邮件内容使用的语言,中英文俄文等等,只有用适当的语言去解析才能读出有效的信息)等等,当然还有响应格式。而请求行也有约定的格式来提供包括请求方法,请求资源,协议版本等等信息。总之应用协议就是约定了一种完整的信息的撰写,排列格式。以方便双方传递信息。
综上,我们可以看出无论HTTP等应用协议是怎样的最终都是使用TCP/IP构建的传输渠道来进行信息传输的。所以TCP/IP才是信息传输的渠道,而HTTP等应用协议则是约定了信息的组织格式。并且它不关心信息的传输渠道是怎么组建的。
接下来我们来说说长链接和短链接:
有了上面的TCP/IP传输渠道的认识之后,我们再来试着理解一下长链接和短链接。
在TCP/IP中文件的传输有两种方式,一种是提供不保证送达的UDP协议,一种是提供可靠送达的TCP协议。你可以把这两种方式类比为邮局的平邮和挂号信。。虽然都是邮局提供的传输服务。但是服务质量不一样。不过和邮局不同的是,平邮和挂号信共用一个邮箱系统,而TCP/IP的两种传输协议却有各自独立的邮箱系统,因此在TCP/IP中即使ip地址端口号相同,采用tcp和udp传输到达的目的地也是不同的。除非他们恰好都是同一个人在使用。
UDP协议寄送消息的时候,只管发,不管对方能不能收到。你可以想象成二战时,敌军从飞机上向敌军的后方亲属分发敌军前线战士的相片。。。只管丢出去。。对方有木有这个收件人,这个收件人是死是活都不管。只管丢出去。然后敌军的亲人有可能收到他们的照片。。可以看出这种寄送方式没有任何可信的渠道。消息的传递只是尽可能传达。
TCP协议的传输方式则完全不同,TCP协议在传输之前,邮局系统会首先通过自身内部的一套握手机制确保收发双方渠道的畅通。具体的说就是:
一、发件方邮局系统先向收件方邮局发个请求链接的消息;
二、如果收件方邮局系统收到了请求,就回一个确认给收件方;
三、发件方收到确认之后,确认自己这一面的信息能收也能发,于是确认系统正常。于是再回一个确认给收件方。
四、收件方收到确认后,确认自己的信息收发也是正常的,于是确认建立链接。相反如果没有收到,则表明可能渠道由问题。于是就会关闭链接。并告知发件方。
一、发件方邮局系统先向收件方邮局发个请求链接的消息;
二、如果收件方邮局系统收到了请求,就回一个确认给收件方;
三、发件方收到确认之后,确认自己这一面的信息能收也能发,于是确认系统正常。于是再回一个确认给收件方。
四、收件方收到确认后,确认自己的信息收发也是正常的,于是确认建立链接。相反如果没有收到,则表明可能渠道由问题。于是就会关闭链接。并告知发件方。
五、在收发双方邮局都确认渠道正常后,他们才开始为上层应用提供数据传输服务。否则发件方就会告知发件方客户,现在没渠道TCP用不了。
六、再然后如果渠道建立就开始欢快的互发消息了。如果没建立就只能遗憾的回去等渠道。
七、互发消息一段时间后,发件双方任一方觉得没必要发消息了。就会向邮局请求关闭链接。邮局给对方邮局发起关闭报文,对方邮局收到后,回给发起方邮局一个确认,同时给发起方也发送一个关闭请求。发起方会先后收到一个关闭确认,和一个关闭请求,并给对方回个确认。对方会收到一个确认。于是双方都确认链接已经关闭了。
你可以把关闭链接这一段形象的理解为,一对情侣本来聊的挺欢,吵架后,一方不想过了。于是对对方说“老子要分手”,对方听到后说“分就分”,说完又加上一句“老子早就想分了”,然后发起方也确认到“分就分”。。。
从上面的过程中,我们可以看到TCP通信过程中,会有一个信息的确认送达过程,以此保证信息的可靠传输。因此在建立链接之初会有三次握手保证收发双方通信渠道的正常。而在关闭链接时也有四次握手确认渠道关闭。
由上可见,长链接和短链接里面的这个链接正是指的这个TCP通信的渠道。而长短链接则是因为这个渠道维护时间的长短不同而作出的区分。
详情见下:
短链接:一般指建立链接之后,经过短时间的数据交换后,就会进入关闭的链接。这种链接适用于数据交换集中,并且无后续数据的情况。
长链接:这种链接在建立之后,会一直尽量维持通道的有效和畅通。适用于数据交换比较分散,或者需要长期进行的情况。
下面就来简单的说说长链接:
长链接的建立和普通链接的建立是一样的也是经过三次握手之后就会达成有效链接。但是在链接建立之后,无论是服务端还是客户端都会尽力的去保持这个通道的畅通,而不是去关闭。但是作为服务端来说,由于需要和众多的客户端进行通信,因此需要保持的链接也会非常多。这些链接都会占用一定的资源。因此,为了提高服务端的资源利用率。要有一种办法来检测和去除那些已经无效的链接。通常的办法就是定期的通过这个渠道发送保持激活的数据包。这种数据包既可以是服务端发送给客户端也可以是客户端给服务器发。不过无论哪一种方式最终的目的都是使双方能够确认这条链接还有效。而对于那些无效的链接则需要在超出激活周期或者检测到无效后被释放资源。
以上的过程和轮询有点类似,但与之不同的是,保持激活的周期可以调的相对较长,并且激活过程的数据交换也很快,所以产生的无效数据交换很少。与之相反的,只有当有效数据来临之后,才会需要进行密集的数据交换。从上可以看出。这种方式与轮询相比,交换效率高,响应快,实现稍微复杂。而与第二张方式相比,则不受资源限制。
另外由于像HTTP协议等应用比较广泛的协议,本身也有长链接保活机制,因此给予这些协议进行开发也更方便快捷。