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 android报错 brut.common.BrutException: could not exec (exit code = 1)
  • ¥15 nginx反向代理获取ip,java获取真实ip
  • ¥15 eda:门禁系统设计
  • ¥50 如何使用js去调用vscode-js-debugger的方法去调试网页
  • ¥15 376.1电表主站通信协议下发指令全被否认问题
  • ¥15 物体双站RCS和其组成阵列后的双站RCS关系验证
  • ¥15 复杂网络,变滞后传递熵,FDA
  • ¥20 csv格式数据集预处理及模型选择
  • ¥15 部分网页页面无法显示!
  • ¥15 怎样解决power bi 中设置管理聚合,详细信息表和详细信息列显示灰色,而不能选择相应的内容呢?