drymoeuka282427675 2014-06-24 04:41
浏览 40
已采纳

AJAX轮询:为什么当两个不同的客户端同时发送两条消息时,只更新了一个客户端?

I am trying to create a Laravel 4 chat app that uses normal-polling. So far it's working fine but when I test it out in two browsers with two different accounts, I found that when I try to send a message from each client(browser) at the same time, client B receives client A's message but client A does not receive client B's msg. Refresh would of course, load client B's msg in client A. How do I solve this?

The reason why I use normal-polling instead of long-polling is because of concurrent connections problem whereby some legacy browsers only limit to 2 concurrent connections. This chat app is planned to accomodate maximum 25 users in a single chat session. I also can't use web sockets due to legacy browser issues. Please correct me if I'm wrong.

p.s. bonus points for better ways to implement this! Thank you!

Here is my client(Javascript) code that updates message.

updatemessages(){
...
 $.ajax({
            type: "POST",
            url: 'create/populate',
            data: {
                'from': lastMessages,
                'conv_id':conv_id
            },
            success: function(messages) {
                $.each(messages, function() {
                    appendMessage(this);
                });
            },
            error: function(xhr,textStatus,errorThrown) {
                console.log(xhr.responseText);
                console.log('something went wrong!');
                $(this).abort();
            },
            complete: function() {
                window.setTimeout(updateMessages, 2000);
            },
            dataType: 'json'
        });
}
updatemessages();

This is my server code (controller) that receives the message, compares it to the latest message in my db and if found latest message, retrieves it.

public function index()
    {
        $timestamps = Input::get('from'); //get timestamp of AJAX sent message
        $conv_id = Input::get('conv_id'); //get conversation id of AJAX sent conv_id
        $allMessages = Messages::with('User')->whereIn('conv_id',$conv_id);

        if(is_null($timestamps)){
           $messages = Messages::with('User')->whereIn('conv_id',$conv_id)->orderBy('created_at','desc');
        }else{
           asort($timestamps);
           $messages = $allMessages->where('created_at','>',end($timestamps));
        }

        return $messages->get()->reverse();
    }

This is another code that stores the new message into the database.

public function store()
    {
        $body = Input::get('message');
        $user_id = Input::get('user_id');
        $conversation = null;

            $conv_id = Input::get('conv_id');
            return Messages::create(array('body'=>$body,'conv_id'=>$conv_id,'user_id'=>$user_id));

    }
  • 写回答

2条回答 默认 最新

  • dpjpo746884 2014-06-26 02:46
    关注

    Carbon's answer did solve the problem just a little bit but the core problem was that I was using timestamp values with precision up to only seconds instead of a precision up to milliseconds. This was evident in

     $messages = $allMessages->where('created_at','>',end($timestamps));
    

    As you can see, that's the main reason why when A and B send message at the same time, they were not received because A's message timestamp is the same as B's message timestamp. So I created another column called milliseconds and everytime I create a new message, I would run

    $micro = round(microtime(true) * 1000);
    

    and save the new message like so :

    Messages::create(array(...other message datas...,'microseconds'=>$micro));
    

    Then in my load message function in the controller, instead of comparing with the timestamp of the last message that appear in the view, I used Carbon's answer to compare with the time of last polled.

    $currentPoll = round(microtime(true) * 1000); //get time in microseconds of time of current poll
    $lastPoll = Session::get('lastPoll');//get time of previous poll
    $messages = $allMessages->where('microseconds','>',$lastPoll)->orderBy('microseconds','desc');
    Session::put('lastPoll',$currentPoll);// update the lastPoll variable to be used in the next request
    

    Finally, in my javascript, I removed any functions that append the message to the view except the one in updateMessages function because only updateMessages is allowed to append the messages. This is to prevent my messages from displaying twice. True, when I send my message, my message does not appear straight away on my view but this is much better than not receiving any messages at all.

    and voila~! My problem is solved...

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 加一个K2暂停音乐的功能
  • ¥15 完成虚拟机环境配置,还有安装kettle
  • ¥15 2024年全国大学生数据分析大赛A题:直播带货与电商产品的大数据分析 问题5. 请设计一份优惠券的投放策略,需要考虑优惠券的数量、优惠券的金额、投放时间段和投放商品种类等因素。求具体的python代码
  • ¥15 有人会搭建生鲜配送自营+平台的管理系统吗
  • ¥15 用matlab写代码
  • ¥30 motoradmin系统的多对多配置
  • ¥15 求组态王串口自定义通信配置方法或代码?
  • ¥15 实验 :UML2.0 结构建模
  • ¥20 用vivado写数字逻辑实验报告撰写,FPGA实验
  • ¥15 为什么shp文件会有这种小方块?