V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
2656618087
V2EX  ›  程序员

web在线聊天室该怎么做呢?

  •  
  •   2656618087 · 2013-07-22 10:19:44 +08:00 · 12829 次点击
    这是一个创建于 3931 天前的主题,其中的信息可能已经有所发展或是发生改变。
    本程序员想做个在线聊天室。能放在公网上的。现在不知道用什么实现方式。项目是javaee的 JSP项目。请有相关经验的前辈指点一二!
    现在小程序员有看过DWR,servlet3.0配合前台ajax,发现都能实现,更倾向与servlet3.0的异步服务器推,但是看到有个网站用的这种方式实现,结果聊天室经常出问题。请前辈们帮忙分析分析,该用什么实现呢!最好是支持人数多、性能好的! 小弟先谢过了!
    51 条回复    1970-01-01 08:00:00 +08:00
    nybux
        1
    nybux  
       2013-07-22 11:05:48 +08:00
    我实现的是http长连接推送的,用golang实现的,由于测试程序的性能问题,测试了2万个并发没有问题。
    lidashuang
        2
    lidashuang  
       2013-07-22 11:07:04 +08:00
    websocket
    lch21
        3
    lch21  
       2013-07-22 11:11:32 +08:00
    现在都用QQ, 微信聊天, web聊天室很少人用了吧
    网上也有不少开源的web聊天室程序
    2656618087
        4
    2656618087  
    OP
       2013-07-22 11:17:29 +08:00
    @nybux 我写了个前台ajax,进入聊天室时通过ajax(startComet一个函数)开始长轮训,目的是请求后台使此用户请求加入到后台用户列表中,此请求就一直挂起,等待有消息推过来 再执行success方法 处理接收到的消息,complete后再发出下一次轮询请求,以此循环。 有个sendmessage函数是负责发送消息的,后台收到此请求,通知列表用户并发送消息至前台。现在主要问题是后台我不知道该怎么写,想用servlet3.0的异步对象AsyncContext 将每个用户的AsyncContext对象缓存起来 就相当于用户列表。但是具体不知道怎么写 怎么入手。能指点下么?给点代码片段 看看可否!谢谢了
    2656618087
        5
    2656618087  
    OP
       2013-07-22 11:18:16 +08:00
    @lch21 我没找到合适我的!之前看了个开源的auto-comet 但是他不更新 我也没细看!
    2656618087
        6
    2656618087  
    OP
       2013-07-22 11:19:39 +08:00
    @lidashuang 能讲讲实现思路吗?
    还有个问题就是 我想着这东西不复杂 估计会写的人 一天就搞定了!但是我后台不会写 都琢磨了好久了 没写出来!
    nybux
        7
    nybux  
       2013-07-22 11:24:30 +08:00
    你的程序里面要存储一张表,就是对应的用户id和asynccontext的表。
    当要给指定用户发消息的时候,就通过用户id把对应的asynccontext对象取出来,返回发送消息。
    我用golang写的。用的是channel阻塞。原理和asyncservlet不太一样。
    2656618087
        8
    2656618087  
    OP
       2013-07-22 11:35:59 +08:00
    @nybux 我的聊天记录不保存,我之前简单做了个用户id和asynccontext在一个javabean asynUser里保存,然后用一个map存放key为房间id value是一个list里面就放的是此放假所有的asynUser对象,但这样老出问题,并发问题、还有就是发送消息时还没给这个房间的asynccontext发送完,下一条消息已经到达,就导致部分用户接收不到消息。对java的同步、锁什么的不太了解 这块也不到底是不是这样处理的。最烦的就是asynccontext对象 相当于发一次消息 就销毁一次 接着ajax轮询请求,后台再创建个asynccontext对象。麻烦的
    nybux
        9
    nybux  
       2013-07-22 12:01:31 +08:00
    并发问题是程序逻辑写的不合理,要好好再设计一下。这类程序的开发,我一般都是2线程的,一个线程负责网络收发,一个线程负责业务逻辑。所以在业务这块,我是单线程的,一般来说仅仅是聊天转发,一个cpu core足够处理了,而且也没有锁的问题。
    参考资料:http://www.eecs.harvard.edu/~mdw/proj/seda/
    2656618087
        10
    2656618087  
    OP
       2013-07-22 12:19:22 +08:00
    @nybux 好的 谢谢 我看看
    Yuansir
        12
    Yuansir  
       2013-07-22 13:58:17 +08:00
    试试 socket.io
    xdeng
        13
    xdeng  
       2013-07-22 15:07:22 +08:00
    @nybux go版发来玩玩啊
    thursday
        14
    thursday  
       2013-07-22 15:27:21 +08:00
    nodejs socket.io 很简单
    verfino
        15
    verfino  
       2013-07-22 16:28:23 +08:00
    用浏览器实现 确实推荐下 Node.js的socket.io
    paloalto
        16
    paloalto  
       2013-07-22 17:36:35 +08:00
    2656618087
        17
    2656618087  
    OP
       2013-07-22 17:54:51 +08:00
    @thursday 不太会这玩意!入门资料提供吗?
    hoorace
        18
    hoorace  
       2013-07-22 18:23:29 +08:00
    使用node.js + socket.io比较快就做出来的,网上的demo也比较简单可以帮助你。只是浏览器的兼容问题需要改写一些框架的源码;由于node的内存回收机制不太清楚,outofmemory的情况时有发生。如果业务量不大或者练手,可以考虑。
    目测小米的客服也是node.js开发的!
    我参与了okhqb.com的右侧的联系客服,是node.js+socket.io+redis开发的!
    verfino
        19
    verfino  
       2013-07-22 18:25:33 +08:00
    @hoorace Node.js 的 socket.io 貌似对浏览器近乎是全兼容的....(ie6,7,8 chrome firefox safari)
    hoorace
        20
    hoorace  
       2013-07-22 18:27:36 +08:00
    @verfino 用了你就知道了,某些浏览器的一些细节,需要你修改socket.io的源码。我至少修改过3处。
    wudikua
        21
    wudikua  
       2013-07-22 18:49:16 +08:00
    redis pub/sub 都写好了现成的推送,自己写个长连接服务器,配合前端long polling接受数据,ajax get发送数据就行了。
    fansgentle
        22
    fansgentle  
       2013-07-22 19:07:26 +08:00
    @thursday +1 我的快要上线了,占位~~
    wity_lv
        23
    wity_lv  
       2013-07-23 07:42:38 +08:00
    @verfino
    @hoorace
    @paloalto
    试试我这个:
    https://github.com/lvjian700/node-pusher
    基于socket.io,项目很简单,仅用来做数据推送:
    web, java, ios 客户端都有。

    Web端:
    $(function() {
    var url = 'http://localhost:3000/';
    var room = '/column';

    var pusher = new Pusher(url);

    pusher.sub(room, function(data) {
    console.log('subscribe /column room success.');
    console.log(data);
    });

    pusher.on('news', function(data) {
    console.log('receive data from xx room.');
    console.log(data);
    });

    $('#btnSent').click(function() {
    var text = $('#message').val();
    pusher.pub(room, 'news', {sender: 'lvjian', msg: text});

    $('#message').val('');
    });
    });

    Java端:
    public class Sample {

    static String to = "/column";
    static String event = "news";

    public static void main(String[] args) throws MalformedURLException, JSONException {

    Pusher pusher = new Pusher("http://127.0.0.1:3000/");

    // This line is cached until the connection is establisched.
    for(int i = 0; i < 10; i++) {
    JSONObject json = new JSONObject();
    json.put("msg", "haha");

    pusher.pub(to, event, json.toString());

    try {
    Thread.sleep(500);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }

    }

    System.exit(0);
    }

    }

    iOS(尚未整理,直接用的Socket.IO for Cocoas)
    _socketIO = [[SocketIO alloc] initWithDelegate:self];
    NSString *host = [RKObjectManager sharedManager].baseURL.host;
    [_socketIO connectToHost:host onPort:3000];
    [_socketIO sendEvent:@"sub" withData:@{@"topic" : @"/changji"}];
    //...
    - (void) socketIO:(SocketIO *)socket didReceiveEvent:(SocketIOPacket *)packet {
    //这里接收事件
    }



    @nybux 求测试方案,我想对node-pusher服务做个性能测试。
    nybux
        24
    nybux  
       2013-07-23 07:50:14 +08:00   ❤️ 1
    我的测试程序是用nodejs写的,不过感觉性能不是很好

    #!/usr/bin/node
    var net = require('net');
    var count = 0;
    var maxUser = 5000;

    function sendRequest(client, i) {
    client.write('GET /poll?uid=-' + i.toString() + ' HTTP/1.1\r\nCookie: ASP.NET_SessionId=' + i.toString() + '\r\n\r\n')
    }

    function poll(uid) {
    var client = new net.Socket();
    client.connect(8080, '127.0.0.1', function() {
    setTimeout(function(){
    sendRequest(client, uid);
    }, Math.random() * 3000);
    });
    client.on('data', function(data) {
    count++;
    msg = data.toString().split('\r\n\r\n')[1];
    if (msg != "") {
    //console.log('recv,' + uid + ':{' + msg + '}');
    }
    setTimeout(function(){
    sendRequest(client, uid);
    }, Math.random() * 3000);
    });
    client.on('close', function() {
    console.log(uid.toString() + ':close!!!!');
    client = new net.Socket();
    poll(uid);
    })
    }

    setInterval(function() {
    console.log('msg count:' + count);
    }, 5000);

    for (i = 1000; i < 1000 + maxUser; ++i) {
    poll(i)
    }
    2656618087
        25
    2656618087  
    OP
       2013-07-23 08:44:09 +08:00
    @fansgentle 你是怎么做的呢
    andyhu
        26
    andyhu  
       2013-07-23 09:14:14 +08:00
    @hoorace 修改的都是哪里?建议创建个pull request贡献回去吧
    fansgentle
        27
    fansgentle  
       2013-07-23 09:25:22 +08:00
    @2656618087 NodeJS、Socket.io、ExpressJS、Bootstrap、NoSQL ...
    yushuiyouyue
        28
    yushuiyouyue  
       2013-07-24 10:07:33 +08:00
    我做了一个是用java+redis来完成的。
    redis里面来存放user和用户的消息。客户端使用ajax向服务器发送消息和获取消息
    timepast
        29
    timepast  
       2013-07-24 10:51:56 +08:00
    PushLets
    rainchen
        30
    rainchen  
       2013-07-24 17:12:46 +08:00
    5分钟在线开发一个聊天室
    https://www.firebase.com/tutorial/
    wity_lv
        31
    wity_lv  
       2013-07-24 17:32:49 +08:00
    @timepast pushlet 还是别推荐了, 上手难度不小。
    2656618087
        32
    2656618087  
    OP
       2013-07-25 16:17:01 +08:00
    @yushuiyouyue 前台ajax到时好写 ,后台 不怎么会写,求点学习代码。可否发到[email protected]邮箱,十分感谢
    2656618087
        33
    2656618087  
    OP
       2013-07-25 16:17:30 +08:00
    @rainchen 这是什么情况?
    2656618087
        34
    2656618087  
    OP
       2013-07-25 16:18:27 +08:00
    @yushuiyouyue 给点代码!后台的,十分感谢 我后台也是java的
    2656618087
        35
    2656618087  
    OP
       2013-07-25 16:19:29 +08:00
    @yushuiyouyue 给点代码!后台的,十分感谢 我后台也是java的。谢谢了!
    az402
        36
    az402  
       2013-07-25 16:21:41 +08:00
    CometD
    erylee
        37
    erylee  
       2013-07-25 19:18:58 +08:00
    直接用哥的:

    webim20.cn

    前台代码:

    github.com/webim
    2656618087
        38
    2656618087  
    OP
       2013-07-29 09:38:04 +08:00
    这几天看了看,还是决定用servlet3.0的异步。计划是这样,每个人进入聊天室房间,调用一个servlet,都把这个异步对象AsyncContext存入一个map里,key为房间id,value为存放AsyncContext的list,发送消息调用messageServlet 将收到的消息存入一个list内,message model有房间ID用于区别该消息是那个房间那个人发的。后台再写个timer定时器,每1秒检查message list里是否有新消息,如果有就调用该房间的所有异步AsyncContext对象 散播消息。我理解这个就是一次轮询完成。客户端收到消息,然后再重复上面的过程建立一次新的轮询。不知道这样做的话可行吗?timer 一秒检查一次 会对服务器 有压力吗?求指导
    @erylee @az402 @yushuiyouyue @rainchen @timepast @yushuiyouyue @nybux @wity_lv @paloalto @thursday @xdeng @lidashuang @lch21
    thursday
        39
    thursday  
       2013-07-29 09:54:55 +08:00
    socket.io 天生就好像是为了 聊天室而生。。 楼主 为何不试试看
    davepkxxx
        40
    davepkxxx  
       2013-07-29 10:10:03 +08:00
    dwr是通 过长连接+定时断开重连 来实现的,如果你不想手动做这个事情,那么用dwr是最好的选择了,或者你也可以选择flash(不少移动浏览器不支持)、html5(ie6~8不支持)、awt(需要客户安装jar)来实现。
    isayme
        41
    isayme  
       2013-07-29 10:33:07 +08:00
    tlk.io好像是nodejs+socket.io做的,目测很不错
    wity_lv
        42
    wity_lv  
       2013-07-29 11:18:07 +08:00
    @2656618087 我想说,你在重造轮子。node.js 的 socket.io 模块已经把Pub/Sub这个事情处理的很好。
    如果你专注于技术学习,可以用servlet 3.0试试。 第一步需要使用底层api实现一个pub/sub模型,之后再基于这层进行聊天室的开发。
    2656618087
        43
    2656618087  
    OP
       2013-07-29 15:33:57 +08:00
    这么说大概明白了。谢谢你 @wity_lv @isayme @davepkxxx @thursday
    照你说我那样做除了麻烦费事,其实也是可行的对不?我这个试完了 研究研究 socket.io 和 dwr 再次感谢。
    wity_lv
        44
    wity_lv  
       2013-07-29 16:19:58 +08:00
    @2656618087 折腾吧,当时我也折腾过,后来选择了pushlet, 现在用socket.io.
    Actrace
        45
    Actrace  
       2013-07-29 20:19:30 +08:00
    最近折腾了一个Ajax Online Chat Demo,楼主可以看看.
    http://try.maxfs.org
    几乎实时.
    Actrace
        46
    Actrace  
       2013-07-29 20:20:01 +08:00
    地址错了,补充一下.
    http://try.maxfs.org/chat.php
    xdyl
        47
    xdyl  
       2013-07-30 11:17:06 +08:00
    http://www.ptteng.com

    WebSocket实现的.
    gracechen
        48
    gracechen  
       2013-08-03 20:49:26 +08:00
    楼主有兴趣我们邮件联系?[email protected]
    gracechen
        49
    gracechen  
       2013-08-03 20:50:00 +08:00
    忘记问。。楼主和@nybux 在帝都吗?
    nybux
        50
    nybux  
       2013-08-04 08:00:45 +08:00
    @gracechen 魔都
    gagahjt
        51
    gagahjt  
       2013-08-06 15:52:57 +08:00
    nodejs+socket.io 做压力测试有什么好的方法和工具么?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5453 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 36ms · UTC 07:43 · PVG 15:43 · LAX 00:43 · JFK 03:43
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.