今天,主要做了IM即时通讯功能中,用户登陆后,将cookie传递过来的用户信息,发送给wokerman服务器,然后操作redis保存。
一、将用户信息传给workerman简单实现
基本思路就是:通过引入jquery.cookie.js,获取用户登陆后的cookie,建立ws长连接,在客户端js操作,当连接打开时,将cookie发给workerman服务器,服务器处理信息,首先要给每个客户端添加序号,然后解密用户信息。
实例
//当客户端同服务器建立长连接时分配给客户整数序号
$ws_worker->onConnect = function ($connection) {
global $global_uid;
$connection->uid = ++$global_uid;
};
// 当收到客户端发来的数据后返回hello $data给客户端
$ws_worker->onMessage = function($connection, $data)
{
//解密cookie
$aes = new AES();
$user_josn = $aes->decrypt($data);
$user_info = json_decode($user_josn, true);
print_r($user_info);
};
//当连接关闭时
$ws_worker->onClose = function($connection)
{
echo "connection closed\n";
};
运行实例 »
点击 "运行实例" 按钮查看在线实例
二、安装redis插件
移动到目标文件夹下 /Applications/MAMP/bin/php/php5.4.45/include/php/redis
cd到php文件夹,输入
./configure
如果产生一下错误的话
PHP ConfigureError: Please specify the install prefixoficonvwith–with-iconv=
那就使用此命令
然后
cd redis
/Applications/MAMP/bin/php/php5.4.45/bin/phpize
./configure --with-php-config=/Applications/MAMP/bin/php/php5.4.45/bin/php-config
make
make install
编译成功后,我们就需要吧so文件复制到MAMP中
sudo cp -p modules/redis.so /Applications/MAMP/bin/php/php5.4.45/lib/php/extensions/no-debug-non-zts-20100525
然后修改php的ini配置文件
在最后或者在Extensions的地方,加上一句
extension=redis.so
三、php操作redis,优化之前代码前台在index.php页面js发送信息,这里新建一个空对象,然后把信息类型type,用户信息user,放在对象里,转成json格式,传给后台。后台三个事件 onConnect onMessage onClose 分别对应三个命名函数handle_connection handle_message handle_close。
实例
//建立连接
function handle_connection ($connection) {
global $global_uid;
$connection->uid = ++$global_uid;
}
//服务器收到客户端消息时
function handle_message ($connection, $data) {
global $chat;
$data = json_decode($data, true);
$chat->process_msg($data);
$chat->connection($connection);
}
//连接断开
function handle_close () {
echo "connection closed\n";
}
运行实例 »
点击 "运行实例" 按钮查看在线实例建立Chat类专门处理消息,然后建connection方法建立websoket process_msg处理各类消息,process_login
专门处理登陆信息,将需要初始化的操作放在构造函数里。
构造函数里,包括AES解密类,redis插件加载及连接,序列号初始化,redis哈希表的key
连接的序列号作为哈希表的field,需要强调下,通过类外的handle_connection方法,在建立连接时通过自增序列号赋值给$connection的自定义属性uid,由于是长连接,那么在连接不断开的情况下$connection就一直存在,相当于全局变量,那么赋给他的自定义属性uid就一直存在,通过类内的connection方法将该对象传递给类内,然后在收到消息是,执行该方法,就作为类内的属性,然后就可以在类内用了
实例
//消息处理类
class Chat{
public function __construct () {
$this->aes = new AES();
$this->redis = new Redis();
$this->redis->connect('127.0.0.1', 6379);
$this->ws_uid = 0;
$this->hash_wsuid_user_key = 'chater_user_list';
$this->connection = '';
}
//建立websoket连接
public function connection ($connection) {
$this->connection = $connection;
}
//处理消息
public function process_msg ($data) {
if ($data['type'] == 'login') {
$this->process_login($data['msg']);
}
}
//处理登陆的信息
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);
}
}
运行实例 »
点击 "运行实例" 按钮查看在线实例
四、总结redis插件很费劲,但是通过不断的查阅资料和反复的实验成功了,需要耐心
课程上业务实际上简单,但是实现过程,需要通过对象化来实现,具体来说,处理消息在类外用一个方法,具体逻辑通过建立类,然后类内的方法来实现,这个类主要是判断消息的type,如果是登陆类信息就交给专门的业务处理方法,然后在业务类里专门处理业务,这样整个代码就很对象化,逻辑严谨,代码简洁。