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 网络科学导论,网络控制
  • ¥100 安卓tv程序连接SQLSERVER2008问题
  • ¥15 利用Sentinel-2和Landsat8做一个水库的长时序NDVI的对比,为什么Snetinel-2计算的结果最小值特别小,而Lansat8就很平均
  • ¥15 metadata提取的PDF元数据,如何转换为一个Excel
  • ¥15 关于arduino编程toCharArray()函数的使用
  • ¥100 vc++混合CEF采用CLR方式编译报错
  • ¥15 coze 的插件输入飞书多维表格 app_token 后一直显示错误,如何解决?
  • ¥15 vite+vue3+plyr播放本地public文件夹下视频无法加载
  • ¥15 c#逐行读取txt文本,但是每一行里面数据之间空格数量不同