Blogger Information
Blog 42
fans 2
comment 0
visits 53939
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
IM即时通讯(私聊功能的实现)2019年3月14日
小明的博客
Original
1728 people have browsed it

今天,主要实现IM即时通讯的私聊功能。前台:点击弹出对话框,点击+发送信息。后台:信息发送给服务器,服务器处理后将信息发送给指定用户。

一、前台

功能:点击好友,弹出对话框,点击+发送信息。

实现:给用户头像绑定点击事件,触发chating方法,该方法主要为,通过ajax的get方法把点击的用户的uid发送给chat.php并且跳转,然后执行回调函数,回调函数是layer的弹出层插件,这个chat.php是index.php的弹出曾属于一个页面。chat.php中,通过传过来的uid,连接数据库,找到该用户的信息,取出nickname作为title。然后给+绑定点击事件,调用sends方法,该方法是将对话框中的消息内容和传过来的uid值(通过隐藏域保存),传给index.php的private_msg方法处理。private_msg方法是把消息的type  to_uid  msg组合成data对象,然后转成json传给服务器。

代码:

实例

// 和TA聊天
	function chating(uid){
	    $.get('/chat.php', {uid:uid}, function (res) {
            layer.open({
                type:1,
                title:false,
                closeBtn:0,
                area:['100%', '100%'],
                content:res
            });
        }, 'text');
    }
//私聊发送消息
    function private_msg(to_uid,msg){
        var data = new Object();
        data.type = 'private_msg';
        data.to_uid = to_uid;
        data.msg = msg;
        ws.send(JSON.stringify(data));
    }

运行实例 »

点击 "运行实例" 按钮查看在线实例

chat.php

实例

<?php
	require_once __DIR__.'/lib/common.php';
	require_once __DIR__.'/lib/Db.php';
	//获取get传过来的uid
    $uid = (int)get('uid');

    //连接数据库
    $db = new Db();
    $title = '';
    //获取点击朋友的信息
    $user = $db->table('member')->where(array('uid'=>$uid))->item();

    $title = $user['nickname'];

?>

<style type="text/css">
	.layui-layer-page{background: #f1f1f1;}
	.chat-header{margin-top: 1rem;text-align: center;}
	.chats{position: fixed;bottom: 0px;height: 3.5rem;line-height: 3.5rem;background: #f1f1f1;width: 100%;padding: 0.5rem 0rem;border-top: 1px solid #ddd;}
	.chats i{font-size: 1.5rem;}
	.chats .layui-col-xs1{text-align: center;line-height: 2.8rem;}
	.chats .txt-chat{overflow-y: auto;background: #fff;height: 2rem;line-height: 1rem;padding: 5px;margin-right: 5px;}
	.msgs{margin-bottom: 3.8rem;}
</style>

<input type="hidden" id="uid" value="<?php echo $uid;?>">
<!--头部菜单-->
<div class="layui-container">
	<div class="chat-header">
		<i class="layui-icon" style="float: left;" onclick="chat_close()"></i>
		<span><?php echo $title;?></span>
		<i class="layui-icon" style="float: right;"></i>
	</div>
</div>
<hr>
<!--消息区-->
<div class="msg_list" id="msg_list">
	
</div>

<!--聊天区-->
<div class="chats layui-container">
	<div class="layui-col-xs1"><i class="layui-icon"></i></div>
	<div class="layui-col-xs9"><div class="txt-chat" contenteditable="true"></div></div>
	<div class="layui-col-xs1"><i class="layui-icon" style="font-size: 1.4rem;"></i></div>
	<div class="layui-col-xs1"><i class="layui-icon" onclick="sends()"></i></div>
</div>

<script type="text/javascript">
	// 关闭chat
	function chat_close(){
		layer.closeAll();
	}

	// 发送消息
	function sends(){
	    var to_uid = $('#uid').val();
	    var msg = $('.txt-chat').html();
        private_msg(to_uid, msg);
	    $('.txt-chat').html('');s
    }

</script>

运行实例 »

点击 "运行实例" 按钮查看在线实例

二、后台

功能:服务器收到消息后,然后转发给目标用户。

实现:在连接刚建立时,服务器记录用户登陆信息建立redis哈希表(连接序号和用户信息对照表)之外,还需要建立用户数据库uid和服务器连接序号对应哈希表,方便服务器分配发送信息。服务器收到数据后,通过Chat类的process_msg方法判断data['type'],如果是私聊类型,那么交给process_private_msg处理,该方法调用发送过来的数据,通过之前建立的用户uid和服务器连接序号对照表,找到目标用户uid的服务器连接序号(ws_uid),然后获取到发送源用户的nickname,avatar,发送事件等数据,通过循环遍历找到连接序号和目标用户的ws_uid相符的连接对象$conn 然后该连接将发送源用户的相关信息,一对一的发送给目标用户客户端,最后在前端收到数据后,调用onmessage事件,渲染出来。

实例

//处理登陆的信息
    private function process_login ($data) {
        $user_json = $this->aes->decrypt($data);
        $user_info = json_decode($user_json, true);
        if ($user_info['uid'] <= 0) {
            return;
        }
        $this->redis->hSet($this->hash_wsuid_user_key, $this->connection->uid, $user_json);
        $this->redis->hSet('chat_uid_wsuid_list', $user_info['uid'], $this->connection->uid);
    }
    //处理私聊的信息
    private function process_private_msg ($data) {
        global $ws_worker;
        //1、通过传过来的目标用户的uid找到服务器给连接对象分配的ws_uid
        $ws_uid = $this->redis->hGet('chat_uid_wsuid_list', $data['to_uid']);

        //拿到发送者用户详细信息
        $send_user_json = $this->redis->hGet($this->hash_wsuid_user_key, $this->connection->uid);
        $send_user_info = json_decode($send_user_json, true);
        //2、通过ws_uid找到目标用户在服务器上的连接对象
        $connection_list = $ws_worker->connections;
        foreach ($connection_list as $conn) {
            if ($conn->uid == $ws_uid) {
                $data['nickname'] = $send_user_info['nickname'];
                $data['avatar'] = $send_user_info['avatar'];
                $data['send_time'] = date('Y-m-d H:i:s');
                $conn->send(json_encode($data));
                break;
            }
        }
    }
}

运行实例 »

点击 "运行实例" 按钮查看在线实例

实例

ws.onmessage = function (ev) {
            console.log(ev.data);
            var obj_msg = $.parseJSON(ev.data);
            var html = '<div class="item">\
						<img class="avatar" src="'+obj_msg.avatar+'">\
						<div class="userinfo">\
							<p ondblclick="menu(this)"><span class="username" >'+obj_msg.nickname+'</span><span class="layui-badge-rim times">'+obj_msg.send_time+'</span></p>\
							<div class="msg"><div class="layui-badge" style="height: 100%;max-width: 200px;background:#fff;color:#333">'+obj_msg.msg+'</div></div>\
						</div>\
					</div>';
            $('#msg_list').append(html);

        }

运行实例 »

点击 "运行实例" 按钮查看在线实例

三、总结

  • 我写代码遇到的坑

实例

function handle_message ($connection, $data) {
    global $chat;
    $chat->connection($connection);
    $data = json_decode($data, true);
    $chat->process_msg($data);
}

运行实例 »

点击 "运行实例" 按钮查看在线实例

之前的处理数据在给连接对象赋序号之前,所以导致最后在将数据(uid和wsuid数据表)存入redis时,第一个uid下没有ws_uid;

  • 在调试中要耐心,掌握了整个流程看到出错结果,往回倒退,抽丝剥茧,满满滴就能找到问题所在。


Correction status:Uncorrected

Teacher's comments:
Statement of this Website
The copyright of this blog article belongs to the blogger. Please specify the address when reprinting! If there is any infringement or violation of the law, please contact admin@php.cn Report processing!
All comments Speak rationally on civilized internet, please comply with News Comment Service Agreement
0 comments