设为首页 收藏本站
查看: 547|回复: 0

[经验分享] php+ajax长轮询实现web即时聊天

[复制链接]

尚未签到

发表于 2018-12-14 11:40:47 | 显示全部楼层 |阅读模式
  web im的实现方式有很多种:
  1.普通轮询,原理通过js定时重复发送ajax请求服务端,获取数据后显示。
  2.   长轮询,ajax请求服务端,服务端有数据会立即返回。服务端无数据时会一直等待,直到有数据了才立即返回。
  3.socket长连接。
  

  

  特征分析:
  方法1:实现起来最容易,定时重复请求服务端会产生无意义的http连接,消耗服务端资源,实时性较差.
  方法2:实现起来较容易,会减少无效的ajax请求产生的http连接,能即时返回数据,但服务端会一直挂着,会消耗一定的资源,处理并发能力不强,比较适合于中小型应用服务.(comet)
  方法3:门槛较高,需了解socket通讯协议,是http实现长连接的最佳方式,也是真正意义上的server push技术.
  

Comet技术简介

    以即时通信为代表的web应用程序对数据的Low
Latency(低延时)要求,传统的基于轮询的方式已经无法满足,而且也会带来不好的用户体验。于是一种基于http长连接的“服务器推”技术便被hack出来。这种技术被命名为Comet,这个术语由DojoToolkit 的项目主管Alex Russell在博文
Comet: Low Latency Data for the Browser首次提出,并沿用下来。
  其实,服务器推很早就存在了,在经典的client/server模型中有广泛使用,只是浏览器太懒了,并没有对这种技术提供很好的支持。但是Ajax的出现使这种技术在浏览器上实现成为可能,google的gmail和gtalk的整合首先使用了这种技术。随着一些关键问题的解决(比如 IE
的加载显示问题),很快这种技术得到了认可,目前已经有很多成熟的开源Comet框架。
  以下是典型的Ajax和Comet数据传输方式的对比,区别简单明了。典型的Ajax通信方式也是http协议的经典使用方式,要想取得数据,必须首先发送请求。在LowLatency要求比较高的web应用中,只能增加服务器请求的频率。Comet则不同,客户端与服务器端保持一个长连接,只有客户端需要的数据更新时,服务器才主动将数据推送给客户端。

  

  本文介绍第二种实现方法
  案例名称:web即时聊天(ajax长轮询方式实现)
  项目地址:https://github.com/zhangrenjie/web_im_ajax

  功能介绍:


  •   对话双方都在线(浏览器没有关闭的情况下),对话即时推送.
  •   支持离线发送消息.当离线方上线时,会自动接收离线消息.
  •   采用确认机制确保数据推送成功.
  •   采用超时退出机制,降低服务器资源浪费.

  

  

  ~~本项目只注重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即时获取并显示聊天内容
  

  页面基本结构





   
   
  

  功能1:发送内容操作

    //-------------发送消息---------
    $(function () {
        var reciver_uid = ;
        var sender_uid = ;
        $('#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 = '';
                        send_message_str += '您对' + send_data.reciver_uid + '说:' + send_data.message;
                        send_message_str += '';
                        $('#message-list').append(send_message_str);
                    } else {
                        console.log('发送失败!!');
                    }
                }, 'json');
            }
        });
    });
  

  

  处理发生消息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:即时获取并显示聊天内容(注意:客户端使用了递归跟服务端自动应答)

    var reciver_uid = ;
    var sender_uid = ;
    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['id']);
                            message_str += '' + messages['sender_uid'] + '在' + messages['send_time'] + '的时候对您说:' + messages['content'] + '';
                        }
                        $('#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);
    }
  

  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);   
}  

  

  





运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-651314-1-1.html 上篇帖子: php编译安装及fastcgi使用 下篇帖子: PHP课程总结20170110
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表