前段时间公司要求做聊天室,在网上看到那篇经典的基于推技术的聊天室。于是开始动手。先说下我的思路,再说我碰到的一些问题,希望得到大虾们的帮助。
    我的思路:
    客户端就不说了,只有浏览器,不过要支持http1.1协议。
    服务器端:
    1.数据库:因为这个聊天室跟我们的一个网站以及论坛有关系,所以我用到了数据库,其实数据库也非常简单,就只有一个聊天室表以及一个聊天室类型表,会员表我直接拿论坛的表来用。
    2.主要的类:对于这个聊天室,我构造如下几个主要的类,聊天室类(ChatRoom),聊天者类(Chater),发言内容类(Content),监听线程类(ListenThread,主要监听各个聊天室的端口),socket解析线程类(SocketParseThread),发送线程类(SendThread),socket列表类(SocketList,通过chatroom构造),发言列表类(ContentList,通过chatroom构造)。
    3.流程,系统首先从数据库得到聊天室信息,构造聊天室类,并且放入聊天室列表。在构造聊天室的时候,启动ListenThread线程;然后当有用户进入的时候,得到一个socket,启动SocketParseThread线程,这是一个主要的聊天控制类,在这个线程里面,解析用户的请求,比方说可能是登陆,发送聊天内容,离开,屏蔽某个人等等。举个例子,假如用户登录聊天室,此时会构造Chater类并放入ChaterList中,同时返回一个框架页面给客户端,并且关闭socket,比方说返回<frame name="**",src="/pubjoin?roomid=**&chaterid=**"..>,假如我们的框架有四个页面(显示公共聊天内容,个人聊天内容,在线列表,发言区),浏览器收到这个框架页面,同时会有四个socket进来,此时初始这四个页面,其中前三个socket会一直连接,保存在SocketList中,SocketParseThread在运行的时候,根据用户的不同命令会构造Content类并放入ContentList中,这是会启动SendThread线程。SendThread主要从ContentList中取出发言内容,并且遍历SocketList,把发言内容发给Socket。下面说说我遇到的问题
1,通过上面的流程,我们可以看到系统同时可能有很多线程在运行,也会有很多socket连接被保持,服务器能承受吗?
2,我如何判断保存在SocketList中的socket是否仍然保持连接,例如用户关闭浏览器,我怎么得到这个消息?
3,在程序中每一个socket进来都会有很多判断,如果碰到异常我该如何处理,我打算继承一个Exception类,定义自己的错误类型,目前还没想好。
4,关于客户端的问题,大家可以看到,我在服务器端没有做任何页面,客户所得到的页面都是通过socket直接写的,这就为客户端的一些操作带来了困难,例如客户端如何分屏?如何刷新在线列表?如何刷新聊天内容?整个聊天室服务程序,完全可以不用web服务器来发布。我曾经想过直接在服务器端监听80端口,然后启一个线程生成聊天室首页,但是考虑到服务器可能还需要发布别的网站,所以聊天室首页以及管理端(主要是管理聊天室的一些属性,跟数据库相关,对聊天没有影响)我还是通过web服务器发布。这些都是次要的,上面列出的问题,恳请大虾们给出解答!

解决方案 »

  1.   

    问你个问题,浏览器访问服务器后建立socket,服务器利用这个socket发送显示内容给浏览器,发完数据后,如果不关闭这个socket,浏览器能够获得显示内容吗?我曾经自己做过,但是是发现不关socket浏览器就不显示。让我郁闷了好长事件。
      

  2.   

    不会吧,你是不是把thread写在循环里面拉!
      

  3.   

    fire1_0:我也碰到过你说的socket不关闭,浏览器不能显示页面的问题,不过我已经解决了。
    star_str:在监听线程里面,如果有socket进来,我会启动SocketParseThread线程,尽管监听线程是一直在运行,但是对SocketParseThread没有影响啊
      

  4.   

    对于客户端的问题,大家给点思路啊,我曾经想过直接在服务器端把页面做好,然后客户端进来的时候,在框架里面把src指到那些页面,但是那样好像建立不了socket连接并且src还要用绝对路径。如果我直接用服务器写页面,在客户端,比方说我发言的时候要贴图,那些图片路径我又如何让客户端得到?
      

  5.   

    怎么没人关注啊?高手看看啊。现在主要是客户端的问题,我用js写重写页面,只要一重写页面,socket连接就断开了,有没有什么好办法啊?
      

  6.   

    上述问题已经解决。对javascript不熟啊,唉。我想知道的是,能不能从服务器写一段代码过来,让页面自动刷新,这个主要是针对在线列表的。
      

  7.   

    kehtong(xufan):
    "我也碰到过你说的socket不关闭,浏览器不能显示页面的问题,不过我已经解决了"你是怎么解决的?还有这个问题的原因是什么?
    谢谢。
      

  8.   

    1,聊天室是很占资源的。
    2, 严格讲、浏览器关闭事件无法准确得到。
    4, 例如客户端如何分屏?如何刷新在线列表?如何刷新聊天内容?——你做的是BS聊天室、必然需要大量javascript来操控客户端页面的!我作过CS聊天室、不过是很久以前了、
    在网上找一个聊天室DOWN它的javascript应该可以找到如何让客户端浏览器自动定时刷新(如2秒刷新一次在线列表)。另外BS结构决定了BS聊天室的稳定性比较差、也比较脆弱。
      

  9.   

    公共聊天信息扔APPLICATION里面去、私聊的扔SESSION里面、不知道对不对。
      

  10.   

    javalin3012:
        对于客户端的操作,大部分我都解决了。javascript代码很少很少,一个比较困难的问题是在线列表的刷新。如果让页面定时刷新来获取在线列表,的确是很简单,但是定时刷新屏幕会闪烁,我不想那样做。对于用户能够操作的,我希望是由用户来触发,比方说用户刷屏,分屏,这些动作是随意的,用户可选可不选,
        但是对于在线列表,尽管用户也可以刷新,但是他不知道何时该刷新,如果定时刷新,在线列表在某时总是会有偏差的,而在线用户的变化,服务器总是可以马上得到,所以这项工作我想交给服务器来做。我的问题是服务器如何触发用户的在线列表更新。
        对于我的这个程序来说,用户的在线列表页面跟服务器总是保持了socket连接,尽管是这样,由于客户端仅仅是浏览器,所以在线列表那个页面仅仅是在跟服务器建立socket连接的时候请求了一次服务器,以后的工作都是服务器给它写数据。服务器可以给页面写javascript,我想知道的是有没有javascript代码不需要触发,也就是说,现在,服务器知道了在线列表多了或者少了人,他给每个用户的在线列表页面发一段javascript代码,这段代码实现页面的刷新,这样就实现了在线列表的更新。
        不知道有没有这样的代码?
      

  11.   

    javalin3012:
       至于你说的公共信息,私聊信息放的地方,我的程序没有session。对于每个聊天室,我都有一个唯一的ContentList实例根他对应,所有的聊天信息都是放在这里面。ContentList里面存放的是Content,Content的属性包括(fromchater--Chater对象,tochater--Chater对象,chattime-String,issecret-boolean,contents-String),这个类已经能够完全说明这个聊天信息该发给谁。所以只需要一个发送线程就够了,无所谓把聊天信息分开放。
      

  12.   

    在线列表定时刷新的问题解决了,效果可以说跟QQ差不多,不是采用客户端刷新的方式,而是直接通过服务器向客户端写javascript代码,屏幕毫无变闪烁。我想这就是所谓的推技术的一个方便所在,可以随时对客户端进行操作。