WEBQQ的实现的几种方式
1、HTTP协议特点
首先这里要知道HTTP协议的特点:短链接、无状态!
在不考虑本地缓存的情况举例来说:咱们在连接博客园的时候,当tcp连接后,我会把我自己的http头发给博客园服务器,服务器端就会看到我请求的URL,server端就会根据URL分发到相应的视图处理(Django的views里)。最后给我返回这个页面,当返回之后连接就断开了。
短连接:
服务器为什么要断开?很多情况下我还会打开页面,我请求一次连接断开了为什么会这样?为什么不建立长期的连接?这个是HTTP设计的考虑,在大并发的情况下,如果连接不断开,我不知道你什么时候点,你可能立刻就点有可能10分钟1个小时或者其他时间点,那么你就会占着这个连接(是很浪费的,并且连接是有限的),所以当返回后server端就会断开这个连接。
无状态:
服务器不保存客户端的任何状态,每一次客户端连接服务器的时候都要把相关的信息发给客户端告诉客户端你是谁,服务端不会保存你是谁?
那么问题来了,为什么我们在登录京东之后登录一次之后,服务器就不会让咱们在登录了,根据咱们之前的博客的Session和Cookie。服务器端会在用户登录的时候,在服务器端生成一个sessionID(有有效期)并且返回给客户。客户端会把这个seesionID存到Cookie里。这样登录之后就不需要再输入密码!
2、WEBqq通信实现
首先看下面的图
根据WEBQQ的工作来看下,首先C1要发送一条数据给C2首先得通过WEB Server进行中转,首先咱们这知道了,正常情况下当C1发送给WEB Server之后,WEB Server就直接返回了,WEB Server就断开了C1的连接了,那么WEB Server会主动给C2发送信息吗?
WEB 服务器默认是被动接收请求的,如果你没打开浏览器,博客园可以给你发信息吗?即便你打开了浏览器,你获取到数据之后就断开了,你看到的是本地缓存的数据。 你和服务器之间就没有联系了。如果服务器想把数据发送给C2那的等C2连接过来,服务器一看有一条C2的数据然后发给C2.那么问题又来了?他知道C2什么时候连接过来吗?服务端不知道C2什么时候连接过来服务端又想能时时把数据发送给C2怎么做呢?《轮询》
轮询方式:
短轮询:
C2客户端有个循环,去Server端取数据。不断的循环去取(会对Server端造成压力)
C2客户端有个时间段的循环,每隔1分钟去取一次,但是不是时时的,这样也不好。
长轮询:
上面的方式也是不可取的那怎么做呢:有没有这么一种方法:当C2请求过来接收的时候,Server端没有C2的数据,Server端没有办法主动让C2等着那怎么办呢?把C2的请求挂起,当有数据的时候在把数据立刻返回,并且多久还是没有数据就把这个链接返回!
这样所有的链接就变成有意义的请求。我不给他断开他就不会发新的请求!
本质上还是轮询,但是他发请求的频率就非常低了!
但是有个问题:他本质上还是一个短链接(这里慢慢想下其实不难理解),如果消息频繁的话,他还是不断的重新建立链接。这样也会对服务器造成影响!每收一条消息都得往返两次。他其实也是不够高效的。
真正的WEBQQ就是用的这个原理来实现的!(因为WEB Socket只有部分浏览器支持(H5标准)IE不支持,在中国的这个环境下IE使用率还是较高的所以不能普及,所以这个方法还是OK得)
还有一个方法就是,真正的长连接,在浏览器上起一个Socket客户端然后连接到服务端,他俩建立一个Socket通道,这样就和Socket Server和Socket Client一样这样他们之间的数据传输就是,时时的了!这个就叫做WEB Socket!!!!!
Socket Server和Socket Client和WEB Socket的区别就是WEB Socket启动在浏览器上! 0 0 !
比如我们在支持H5的浏览器上比如Google的浏览器轻松起一个WEB Socket,但是这个不仅仅要客户端支持,Server端也得支持才可以!
sock = new WebSocket("ws://www.baidu.com")
WEB QQ 表结构
首先用户的好友在哪个表里?在用户表里那么他就的关联自己了并且是多对多的关系,你可以有多个朋友,你朋友也可以有多个朋友!
classUserProfile(models.Model):'''用户表'''
#使用Django提供的用户表,直接继承就可以了.在原生的User表里扩展!(原生的User表里就有用户名和密码)
#一定要使用OneToOne,如果是正常的ForeignKey的话就表示User中的记录可以对应UserProfile中的多条记录!
#并且OneToOne的实现不是在SQL级别实现的而是在代码基本实现的!
user =models.OneToOneField(User)#名字
name = models.CharField(max_length=32)#属组
groups = models.ManyToManyField("UserGroup")#朋友
friends = models.ManyToManyField('self',related_name='my_friends')
然后在建立一个APP然后APP名称为:web_chat 他调用WEB里的UserProfile用户信息,然后在web_chat的models里新创建一个表:QQGroup!(复习不同APP间的Model调用~)
#/usr/bin/env python#-*- coding:utf-8 -*-
from __future__ importunicode_literalsfrom django.db importmodelsfrom web.models importUserProfile#Create your models here.
classQQGroup(models.Model):'''QQ组表'''
#组名
name = models.CharField(max_length=64,unique=True)#注释
description = models.CharField(max_length=255,default="The Admin is so lazy,The Noting to show you ....")'''下面的members和admins在做跨APP关联的时候,关联的表不能使用双引号!并且在调用,Django的User表的时候也不能加双引号。'''
#成员
members = models.ManyToManyField(UserProfile,blank=True)#管理员
admins = models.ManyToManyField(UserProfile,blank=True,related_name='group_admins')'''如果在一张表中,同样调用了另一张表同样的加related_name'''
#最大成员数量
max_member_nums = models.IntegerField(default=200)def __unicode__(self):return self.name
这里:mem