• 请不要在回答技术问题时复制粘贴 AI 生成的内容
2656618087
V2EX  ›  程序员

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

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

    webim20.cn

    前台代码:

    github.com/webim
    2656618087
    2656618087
    OP
    Jul 29, 2013
    38
    这几天看了看,还是决定用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
    thursday
    Jul 29, 2013
    39
    socket.io 天生就好像是为了 聊天室而生。。 楼主 为何不试试看
    davepkxxx
    davepkxxx
    Jul 29, 2013
    40
    dwr是通 过长连接+定时断开重连 来实现的,如果你不想手动做这个事情,那么用dwr是最好的选择了,或者你也可以选择flash(不少移动浏览器不支持)、html5(ie6~8不支持)、awt(需要客户安装jar)来实现。
    isayme
    isayme
    Jul 29, 2013
    41
    tlk.io好像是nodejs+socket.io做的,目测很不错
    wity_lv
    wity_lv
    Jul 29, 2013
    42
    @2656618087 我想说,你在重造轮子。node.js 的 socket.io 模块已经把Pub/Sub这个事情处理的很好。
    如果你专注于技术学习,可以用servlet 3.0试试。 第一步需要使用底层api实现一个pub/sub模型,之后再基于这层进行聊天室的开发。
    2656618087
    2656618087
    OP
    Jul 29, 2013
    43
    这么说大概明白了。谢谢你 @wity_lv @isayme @davepkxxx @thursday
    照你说我那样做除了麻烦费事,其实也是可行的对不?我这个试完了 研究研究 socket.io 和 dwr 再次感谢。
    wity_lv
    wity_lv
    Jul 29, 2013
    44
    @2656618087 折腾吧,当时我也折腾过,后来选择了pushlet, 现在用socket.io.
    Actrace
    Actrace
    Jul 29, 2013
    45
    最近折腾了一个Ajax Online Chat Demo,楼主可以看看.
    http://try.maxfs.org
    几乎实时.
    Actrace
    Actrace
    Jul 29, 2013
    46
    地址错了,补充一下.
    http://try.maxfs.org/chat.php
    xdyl
    xdyl
    Jul 30, 2013
    47
    http://www.ptteng.com

    WebSocket实现的.
    gracechen
    gracechen
    Aug 3, 2013
    48
    楼主有兴趣我们邮件联系?[email protected]
    gracechen
    gracechen
    Aug 3, 2013
    49
    忘记问。。楼主和@nybux 在帝都吗?
    nybux
    nybux
    Aug 4, 2013
    50
    @gracechen 魔都
    gagahjt
    gagahjt
    Aug 6, 2013
    51
    nodejs+socket.io 做压力测试有什么好的方法和工具么?
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   4019 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 72ms · UTC 01:03 · PVG 09:03 · LAX 17:03 · JFK 20:03
    ♥ Do have faith in what you're doing.