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 乘性高斯噪声在深度学习网络中的应用
  • ¥15 运筹学排序问题中的在线排序
  • ¥15 关于docker部署flink集成hadoop的yarn,请教个问题 flink启动yarn-session.sh连不上hadoop,这个整了好几天一直不行,求帮忙看一下怎么解决
  • ¥30 求一段fortran代码用IVF编译运行的结果
  • ¥15 深度学习根据CNN网络模型,搭建BP模型并训练MNIST数据集
  • ¥15 C++ 头文件/宏冲突问题解决
  • ¥15 用comsol模拟大气湍流通过底部加热(温度不同)的腔体
  • ¥50 安卓adb backup备份子用户应用数据失败
  • ¥20 有人能用聚类分析帮我分析一下文本内容嘛
  • ¥30 python代码,帮调试,帮帮忙吧