php+ajax长轮询实现web即时聊天

web im的实现方式有很多种:

1.普通轮询,原理通过js定时重复发送ajax请求服务端,获取数据后显示.

2.长轮询,ajax请求服务端,服务端有数据会立即返回,服务端无数据时,会一直等待,直到有数据了才立即范围.

3.socket长连接.

特征分析:

方法1:实现起来最容易,定时重复请求服务端会产生无意义的http连接,消耗服务端资源,实时性较差.

方法2:实现起来较容易,会减少无效的ajax请求产生的http连接,能即时返回数据,但服务端会一直挂着,会消耗一定的资源,处理并发能力不强,比较适合于中小型应用服务.(comet)

方法3:门槛较高,需了解socket通讯协议,是php实现长连接的最佳方式,也是真正意义上的server push技术.

本文介绍第二种实现方法

案例名称:web即时聊天(ajax长轮询方式实现)

项目地址:https://github.com/zhangrenjie/web_im_ajax

功能介绍:

  1. 对话双方都在线(浏览器没有关闭的情况下),对话即时推算.
  2. 当一方不在线时,支持离线发送消息.当离线方上线时,会自动接收离线消息.

~~本项目只注重php服务端的实现机制和性能优化,前端界面粗糙请忽略.适合初中级php程序员学习借鉴,欢迎各位指教交流~~

预览

项目文件结构:

GetMessage.php
SendMessage.php
client.php
jquery.min.js
sql

准备工作:数据库

mysql> desc message;
+-------------+------------------+------+-----+---------+----------------+
| Field       | Type             | Null | Key | Default | Extra          |
+-------------+------------------+------+-----+---------+----------------+
| id          | int(10)          | NO   | PRI | NULL    | auto_increment |
| reciver_uid | int(10) unsigned | NO   | MUL | 0       |                |
| sender_uid  | int(10) unsigned | NO   |     | 0       |                |
| content     | varchar(1000)    | NO   |     |         |                |
| create_time | int(10) unsigned | NO   |     | 0       |                |
| status      | tinyint(1)       | NO   |     | 0       |                |
+-------------+------------------+------+-----+---------+----------------+

客户端Client.php

实现功能:1.发送聊天信息,2获取并显示聊天内容

页面基本结构

<div id="message-list">
<!--这里显示对话内容-->
</div>

<div id="message-send">
<!--这里填写对话内容,并发生-->
    <input type="textarea" id="message-box"/>
    <input type="button" id="submit-message" value="发送消息">
</div>

功能1:发送内容操作

<script type="text/javascript">
    //-------------发送消息---------
    $(function () {
        var reciver_uid = <?php echo $reciverUid;?>;
        var sender_uid = <?php echo $senderUid;?>;
        $(‘#submit-message‘).on(‘click‘, function () {
            var message_content = $(‘#message-box‘).val();
            if (message_content != ‘‘) {
                $(this).attr(‘disabled‘, ‘disabled‘);
                var send_url = ‘./SendMessage.php‘;
                var send_data = {
                    ‘message‘: message_content,
                    ‘reciver_uid‘: reciver_uid,
                    ‘sender_uid‘: sender_uid,
                };
                $.post(send_url, send_data, function (response) {
                    if (response.status == 1) {
                        $(‘#message-box‘).val(‘‘);
                        $(‘#submit-message‘).removeAttr(‘disabled‘);
                        var send_message_str = ‘<li style="text-align: right;padding-right: 10px;">‘;
                        send_message_str += ‘您对‘ + send_data.reciver_uid + ‘说:‘ + send_data.message;
                        send_message_str += ‘</li>‘;
                        $(‘#message-list‘).append(send_message_str);
                    } else {
                        console.log(‘发送失败!!‘);
                    }
                }, ‘json‘);

            }
        });
    });
</script>

处理发生消息SendMessage.php

实现功能:保存发送信息

$link = mysqli_connect(    
    ‘127.0.0.1‘,  /* The host to connect to 连接MySQL地址 */    
    ‘root‘,      /* The user to connect as 连接MySQL用户名 */    
    ‘‘,         /* The password to use 连接MySQL密码 */    
    ‘web_im‘);    /* The default database to query 连接数据库名称*/    
if (!$link) {    
    printf("Can‘t connect to MySQL Server. Errorcode: %s ", mysqli_connect_error());    
    exit;    
}    
//只能用函数来判断是否连接成功    
if (mysqli_connect_errno()) {    
    echo mysqli_connect_error();    
}  
  
$senderUid = (int)$_POST[‘sender_uid‘];    
$reciverUid = (int)$_POST[‘reciver_uid‘];    
$message = str_replace([‘ ‘, ‘,‘], ‘‘, $_POST[‘message‘]);    
$time = time();
    
$sql = "insert into message values(NULL ,‘{$reciverUid}‘,‘{$senderUid}‘,‘{$message}‘,‘{$time}‘,‘1‘)";    
$result = mysqli_query($link, $sql);    
$insertId = mysqli_insert_id($link);    
if ($insertId) {    
    $returnArr = [‘status‘ => 1,‘info‘ => $insertId,];    
} else {    
    $returnArr = [‘status‘ => 0,‘info‘ => ‘‘,];    
}    
echo json_encode($returnArr);    
mysqli_close($link);    
exit();

再回到客户端Client.php的功能2

功能2:获取并显示聊天内容(注意:客户端使用了递归跟服务端自动应答)

<script type="text/javascript">
    var reciver_uid = <?php echo $senderUid;?>;
    var sender_uid = <?php echo $reciverUid;?>;
    var url = ‘./GetMessage.php‘;
    $(function () {
        get_message_reply(url, reciver_uid, sender_uid, ‘get_message‘, ‘‘);
    });

    //获取消息并应答
    //get_get_message_reply()
    //param request_type  请求类型 详解:
    //      get_message   获取信息
    //      comfrim_read  确认已经读取了信息
    function get_message_reply(url, reciver_uid, sender_uid, request_type, send_data) {
        var setting = {
            url: url,
            data: {
                ‘request_type‘: request_type,
                ‘reciver_uid‘: reciver_uid,
                ‘sender_uid‘: sender_uid,
                ‘send_data‘: send_data,
            },
            type: ‘post‘,
            dataType: ‘json‘,
            success: function (response) {
                if (response.status == 1) {
                    if (response.response_type == ‘is_read‘) {
                        //将消息写入到消息盒子
                        var messages = response.info;
                        var message_str = ‘‘;
                        var id_arr = new Array();
                        for (var i in messages) {
                            id_arr.push(messages[i][‘id‘]);
                            message_str += ‘<li>‘ + messages[i][‘sender_uid‘] + ‘在‘ + messages[i][‘send_time‘] + ‘的时候对您说:‘ + messages[i][‘content‘] + ‘</li>‘;
                        }
                        $(‘#message-list‘).append(message_str);
                        //确认收到消息
                        get_message_reply(url, reciver_uid, sender_uid, ‘comfrim_read‘, id_arr);

                    } else if (response.response_type == ‘is_connecting‘) {
                        //继续获取消息
                        get_message_reply(url, reciver_uid, sender_uid, ‘get_message‘, ‘‘);
                    }
                }
            }
        };
        $.ajax(setting);
    }
</script>

NOTICE:下面是核心中的核心

服务端推送消息GetMessage.php

set_time_limit(0);    
$maxInvalidCount = 30;    
$link = mysqli_connect(    
    ‘127.0.0.1‘,  /* The host to connect to 连接MySQL地址 */    
    ‘root‘,      /* The user to connect as 连接MySQL用户名 */    
    ‘‘,         /* The password to use 连接MySQL密码 */    
    ‘web_im‘);    /* The default database to query 连接数据库名称*/    
if (!$link) {    
    printf("Can‘t connect to MySQL Server. Errorcode: %s ", mysqli_connect_error());    
    exit;    
}    
//只能用函数来判断是否连接成功    
if (mysqli_connect_errno()) {    
    echo mysqli_connect_error();    
}

    
$requestType = $_POST[‘request_type‘];    
switch ($requestType) {    
    case ‘get_message‘://客户端请求读取消息    
        break;    
    case ‘comfrim_read‘://客户端确认已经读取了信息,服务端需要更新读取状态    
        $idsArr = $_POST[‘send_data‘];    
        $ids = implode(‘,‘, $idsArr);    
        $sql = "update message set status = 2 where id in ({$ids})";    
        mysqli_query($link, $sql);    
        mysqli_close($link);    
        break;    
    default:    
        break;    
} 

   
$sql = "select * from message where reciver_uid=‘{$_POST[‘reciver_uid‘]}‘ and sender_uid=‘{$_POST[‘sender_uid‘]}‘ and status=‘1‘";    
$i = 0;    
while (true) {    
    //读取数据    
    $result = mysqli_query($link, $sql);    
    if ($result) {    
        $returnArr = [];    
        while ($row = mysqli_fetch_assoc($result)) {    
            $row[‘send_time‘] = date(‘Y-m-d H:i:s‘, $row[‘create_time‘]);    
            $returnArr[] = $row;    
        }    
        if (!empty($returnArr)) {    
            //返回结果    
            $data = [    
                ‘status‘ => 1,    
                ‘response_type‘ => ‘is_read‘,    
                ‘info‘ => $returnArr,    
            ];    
            echo json_encode($data);    
            mysqli_free_result($result);    
            mysqli_close($link);    
            exit();    
        }    
    }
        
    $i++;    
    //需要给客户端发送确认信息是否还在连接服务器,客户端无回应则整个过程结束    
    if ($i == $maxInvalidCount) {    
        $data = [    
            ‘status‘ => 1,    
            ‘response_type‘ => ‘is_connecting‘,    
            ‘info‘ => ‘‘,    
        ];    
        echo json_encode($data);    
        mysqli_close($link);    
        exit();    
    }    
    //file_put_contents(‘./test.log‘, date(‘Y-m-d H:i:s‘) . "已经执行了{$i}次" . "\r\n", FILE_APPEND);    
    sleep(1);    
}
时间: 2024-12-26 20:52:46

php+ajax长轮询实现web即时聊天的相关文章

ajax长轮询实现即时聊天室

前段js: //处理ajax长轮询 $(function(){ ask_order(); function ask_order(){ var ask_action = "{:U('index/order_commet',array('time'=>10,'desk_id'=>$desk_id))}"; $.ajax({                    type:"GET",                    dataType:"jso

用大白话揭开Ajax长轮询(long polling)的神秘面纱

在看这篇Ajax长轮询之前可以先看看Ajax轮询技术(没有长),有助于理解: Ajax长轮询属于Ajax轮询的升级版,在客户端和服务端都进行了一些改造,使得消耗更低,速度更快. "不间断的通过Ajax查询服务端". 来,小二,先上代码~: Reception.html //客户端 <html> <head> <title></title> <script src="http://lib.sinaapp.com/js/jqu

ajax长轮询 (转)

javaWeb项目中需要一个实时提醒的功能,也就是某人做了某一操作,可以立即提醒到当前在线的用户 最开始想在用户做了操作后,储存一个状态到数据库中然后用每隔几秒用ajax去请求后台查询数据库来确定是否显示提醒窗口 提醒窗口使用jquery easyui 的messager 在右下角弹出如下图 后查得可通过AJAX长轮询的方法来解决频繁对后台的请求,进一步减小压力 在实现过程发现AJAX的多次请求会出现多线程并发的问题又使用线程同步来解决该问题 个人对ajax长轮询的一点愚见 ajax请示后台时,

轮询、长轮询与Web Socket的前端实现页面数据实时

Web Socket 应用场景:实现即时通讯:如股票交易行情分析.聊天室.在线游戏等,替代轮询和长轮询 1.轮询 轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP request,然后由服务器返回最新的数据给客户端的浏览器.这种传统的HTTP request 的模式带来很明显的缺点 – 浏览器需要不断的向服务器发出请求,然而HTTP request 的header是非常长的,里面包含的有用数据可能只是一个很小的值,这样会占用很多的带宽. var xhr = new XMLHtt

轮询、长轮询与Web Socket的前端实现

Web Socket 应用场景:实现即时通讯:如股票交易行情分析.聊天室.在线游戏等,替代轮询和长轮询 轮询 轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP request,然后由服务器返回最新的数据给客户端的浏览器.这种传统的HTTP request 的模式带来很明显的缺点 – 浏览器需要不断的向服务器发出请求,然而HTTP request 的header是非常长的,里面包含的有用数据可能只是一个很小的值,这样会占用很多的带宽. var xhr = new XMLHttpR

PHP实现Ajax长轮询

传统的AJAX轮询方式,客服端以用户定义的时间间隔去服务器上查询最新的数据.种这种拉取数据的方式需要很短的时间间隔才能保证数据的精确度,但太短的时间间隔客服端会对服务器在短时间内发送出多个请求. 反转AJAX,就是所谓的长轮询或者COMET.服务器与客服端需要保持一条长时间的请求,它使得服务器在有数据时可以返回消息给客户端. 这里使用AJAX请求data.php页面获得'success'的值,请求的时间达到80秒.在这80秒中若没有从服务端返回'success'则一直保持连接状态,直到有数据返回

php+ajax 长轮询

最近在做项目时要做一个即时提醒功能,第一次做没思路.就百度了下.发现好多都说的模糊不清.我整理了下发出来大家指点下 jquery 代码: 这里使用使用ajax请求test页面获取success的值,请求超时时间为20秒.在20秒内若没数据返回则一直保持连接 $(function(){ $("#btn").bind('click',{btn:$('#btn')},function(e){ $.ajax({ type: 'POST', dataType: 'json', url: 'tes

Ajax长轮询

前台代码: <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Wait.aspx.cs" Inherits="Web监听.Wait" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xht

继续ajax长轮询解决方案--递归

如果使用for,会有一种情况发生,就是ajax的执行会大于其他的动作的执行,那么这样的一段代码就不能实现了 for(var i=0;i<20;i++){ console.log('你好') $.ajax(--) } 怎么办呢? 递归吧,很多老程序员都是这样干的,于是,代码: currentIndex = 0; function ajax(){ if(currentIndex>=20){ return; } var url = 'url'; console.log(i); $.ajax({ ty