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

2017-01-11 08:01:40来源:作者:人点击

web im的实现方式有很多种:
1.普通轮询,原理通过js定时重复发送ajax请求服务端,获取数据后显示.
2.长轮询,ajax请求服务端,服务端有数据会立即返回,服务端无数据时,会一直等待,直到有数据了才立即范围.
3.socket长连接.

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

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

功能介绍:

对话双方都在线(浏览器没有关闭的情况下),对话即时推送.

支持离线发送消息.当离线方上线时,会自动接收离线消息.

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

预览




项目文件结构:
GetMessage.phpSendMessage.phpclient.phpjquery.min.jssql


准备工作:数据库
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); }


本文出自 “我的PHP之路” 博客,请务必保留此出处http://phpme.blog.51cto.com/663593/1890859

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台