这个不好插入图片,看我另一个博客上的吧
http://blog.csdn.net/wangchangshuai0010/article/details/7335732
上学期做了一个java版本的QQ,下面我把课程设计报告中的一些内容拿出来,供大家参考一下
下面概要讲述一下我在设计完成服务器模块和设计客户端后台中遇到的问题及解决方案。
服务器:
1、服务器使用什么机制,是线程还是进程?
2、数据库如何设计能使服务器访问的效率提高?
3、如何处理大量用户同时访问服务器?
4、服务器与客户端之间选择何种心跳模型?
客户端:
1、客户端聊天到底使用什么模式,是C/S模型还是P2P?
2、客户端之间通信有何种模型?
3、。。。。?
4、。?
这里仅仅列举了很小一部分问题,但这些问题的解决与否在此项目中至关重要,直接决定做出来的课程设计是否高效,是否能经得起各种测试的考验,尤其是压力测试(对于服务器)。
那么下面我简单讲述一下我的解决方案:
1、服务器使用什么机制,是线程还是进程?
服务器中最重要的差不多就是线程活进程的使用,在并发处理大量用户的请求时,线程或进程发挥着不可替代的作用,在此项目中我选择了使用线程来完成服务器的设计,线程较进程有如下优点:
1)、它是一种非常"节俭"的多任务操作方式。操作系统启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这是一种"昂贵"的多任务工作方式。而运行于一个进程中的多个线程,它们彼此之间使用相同的地址空间,共享大部分数据,启动一个线程所花费的空间远远小于启动一个进程所花费的空间,而且,线程间彼此切换所需的时间也远远小于进程间切换所需要的时间。当然,在具体的系统上,这个数据可能会有较大的区别;
2)、线程间方便的通信机制,由于同一进程下的线程之间共享数据空间(此处非常重要),所以一个线程的数据可以直接为其它线程所用,这不仅快捷,而且方便;
3)、使多CPU系统更加有效。操作系统会保证当线程数不大于CPU数目时,不同的线程运行于不同的CPU上;
4)、改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行部分,这样的程序会利于理解和修改。
鉴于以上四条线程的优点,我最终还是选择了用线程机制来完成服务器的设计。
2、数据库如何设计能使服务器访问的效率提高?
? ? ? 数据库的设计对于要访问数据库的用户请求非常重要,好的数据库设计方案往往能使服务器的效率几十倍甚至上百倍(实际数据测得),反之,差的数据库模式可能是服务器在应答大量用户请求时崩溃,或是客户端超时率增大很多,用户体验直接降到低谷,更谈何别人使用你的软件。所以对于数据库的设计,我把它放到了相当高的地位,其实说实话,后来的优化,数据库的改善是最提高服务器效率的最有效的方法。
早期的数据设计思路如下:
? ? ? 当用户申请帐号时,服务器选出能被申请的下一个帐号作为申请的帐号,将此帐号作为唯一标识给用户创建一个数据库,即每个人的数据(除了基本信息外)都用一个数据库来存储。
图片见附件1.jpg
这种模式看似挺清晰,但这极大的降低了效率,这种设计方法在服务器在接收到用户请求需要访问数据库时,不通的用户就要进入不通的数据库,如果此时还需要该用户的一些基本信息,那么在数据库切换时耗时很长,在实际测试中用户申请失败的概率很大,用户的感受就不言而喻了,同样服务器的价值几乎全部丧失,此种设计方法很失败。
经过很长时间的思考,我想到了另外一种模型,即把用户群的基本信息放入到main数据库各表中,用户群其他的全部信息表放在users数据库中。
图片见附件2.jpg
在实际压力测试中,尤其是申请好友操作中此更改,显著提高了效率,比如原来同时申请100个帐号,最多只有28个申请成功,其他的均超时,而此番修改后,申请100个帐号,只需不到两秒,用户体验就显著提高了。
3、如何处理大量用户同时访问服务器?
这是最令人头疼的事情,作为服务器压力测试不过关,其他的都免谈。服务器是干什么的,当然就是为处理用户的请求的,请求的人数少的时候你怎么做都行,但大量用户同时发送请求时,可不是你想怎么做就怎么做了,对于这个问题,我提出了一些解决方案。
1、先保证服务器不崩溃,即保证内存、cpu等正常工作
保证此项不出问题,就得控制好多线程的开辟、启动、终止的 关系,此服务器用的机制是线程机制,即当服务器接收到用户的 请求时,服务器会开辟一个子线程,用来处理此请求,处理完请 求就终止线程。但问题出来了,当很多用户访问时,比如1000个,10000个甚至更多的时候,服务器会在很短的时间内开辟如此多的线程,请试想一下,服务器能不崩溃吗?肯定会崩溃,除非你是巨型机,呵呵。。。所以现在要解决这个问题,当我想到这个问题时,我很纠结啊,该怎么办呢?后来问了问魏老师,他提出的是在线程数量达到一定数量时,让请求排队,的确,虽然这样可能导致排队的请求超时,但毕竟服务器正常运行是重中之重,所以我根据魏老师的思路稍微修改了一下,从而达到了不让服务器崩溃的效果。
2、如何使用户快速得到一些经常访问的信息
这个看似不大重要的设计点却对服务器优化起着很重要的作用,比如说用户的密码、用户的ip 和 一些 port ,这些数据经常被用到,如果每次都去硬盘中的数据库中去读取的话,这样浪费在IO上的时间就会增加很多。所以,我提出的解决方案是将常用但占用内存较少的数据预读到数据库中,保证在IO上浪费的时间尽可能的少。
图片见附件3.jpg
4、服务器与客户端之间选择何种心跳模型?
心跳对很多人来说是一个挺陌生的概念,但实际上心跳在很多地方得到应用,如并行运算工作组还有此次的即时聊天领域,它在这些领域发挥着不可替代的作用,通过心跳可以自动检测完成很多功能,比如此次项目的监测用户的状态改变与“假死”和“真死”等等,同时此模块也是系统运行中运作最频繁的一部分,因此处理好此模块将很的降低服务器的压力。
当今的心跳检测模型大约有以下几种:
1、推模型
图片见附件4.jpg
2、拉模型
图片见附件5.jpg
3、推拉混合式
此模式就是上述两种模式的有机组合,即正常情况下用推模型,客户端每隔一段时间便向服务器发送心跳包,告诉服务器客户端当前的状态;假如客户端由于断电、任务管理器强制关闭导致意外关闭时,客户端不能再想服务器发送心跳包,但遗憾的是客户端也无法发送自己下线的心跳报,此时服务器检测到客户端三次没有发过来心跳,于是服务器主动想客户端发送询问,来最终判断客户端是否在线,此模型充分发挥了推模型的省资源高效率、拉模型准确性高的优势,所以我最终选择了此模型。
早期的心跳模型设计和后期的心跳改进不大,改动了接收存储心跳的位置,即从硬盘转到了内存,但也大大降低了服务器的压力,毕竟心跳是服务器中最繁忙的部分,稍微一优化便可以产生很大的性能提升。
客户端:
1、客户端聊天到底使用什么模式,是C/S模型还是P2P?
这个问题在我刚开始做的时候和很多人一样认为,既然是C/S结构,聊天肯定经过服务器的中转发往另一个客户端。当少量的用户在线聊天是此模型的效率不是很差而且在网络不好时会发挥其优势,作为一个为公众做的软件,服务的群体毕竟不是一个两个,而是成千上万,我们都知道即时聊天工具最繁忙的无外乎就是聊天模块,问题来了,这么多人都通过服务器中转,服务器能承受的了吗?呵呵,我还是那句话,服务器得非常非常。。。强大。。。此时我想如何能降低服务器的压力呢,那答案就是客户端之间通过P2P的方式进行通信
图片见附件6.jpg
2、客户端之间通信有何种模型?
这问题就真正涉及到聊天的具体环节了,怎么样才能做到软件工程要求模块的内聚性强、耦合度低呢?这里就要是功能模块独立化,这个思想正好用在了聊天的实现上,同时也是受TCP/IP 分层协议的启发得出的模型。
图片见附件7.jpg
这种模型保证了功能模块的独立化,非常清晰,各层之间功能独立,各自完成各自的工作。自我感觉这种聊天内部模型比较出色。
个人见解,请大家提些意见或建议,勿扔板砖,谢谢!
?
代码下载说明:http://wangchangshuai0010.iteye.com/blog/1450424
?