22

SWOOLE开发实时聊天系统(十)用户断开聊天

 4 years ago
source link: https://studygolang.com/articles/27170
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

最后我们再处理一下用户断开连接的时候的处理工作。

首先,我们需要在websocket断开的时候,去调用MessageController中的close函数,传递当前用户的fd.

$this->server->on('close', function ($ser, $fd) {
            echo "server: close a fd  : fd{$fd}\n";
            $this->MessageController->closeFd($fd);
        });

在MessageController中,去调用处理用户登录注册所有逻辑的LoginService处理具体的业务逻辑,删除用户和直播的关系。其中包括删除user_id 对应的fd,group对应的fd等的内容。

//关闭连接
    public function closeFd($fd)
    {
        $loginService = new LoginService($this->server);
        $loginService->close($fd);
    }

然后我们去LoginService中完成逻辑处理:

public function close($fd) {
        try{
            $result=$this->removeFromRedis($fd);
            if(!$result){
                throw new \Exception('删除用户失败,请重试!');
            }
            //在这里也加上notify,如果有需要通知的内容,可以在前面直接写,不用再更改此处的业务逻辑
            $this->notify();
        }catch (\Exception $e){
            $this->result['status'] = 1;
            $this->result['msg'] = $e->getMessage();
            echo json_encode($this->result,JSON_UNESCAPED_UNICODE);
        }
        return $this->result;
    }

具体的实现方法如下:

private function removeFromRedis($fd){
        $user_id = pool::redis()->hGet(self::user_bind_redis_key, $fd);
        pool::redis()->hDel(self::user_bind_redis_key, $fd);
        //删除当前用户所对应的分组
        $rk = str_replace('fd', $fd, self::redis_key_user_group);
        $group = pool::redis()->get($rk);
        pool::redis()->del($rk);
        //删除分组中对应的用户
        if ($group) {
            $group = explode("_", $group);
            //从分组对应的用户中,删除当前用户
            $rk = str_replace(['first_topic', 'second_topic'], [$group[0], $group[1]], self::redis_key_group_user);
            $userlist = pool::redis()->get($rk);
            $userlist = explode(',', $userlist);
            $key = array_search($user_id, $userlist);
            array_splice($userlist, $key, 1);
            if (!$userlist) {
                pool::redis()->del($rk);
            } else {
                pool::redis()->set($rk, implode(",", $userlist));
            }
        }
        //删除fd绑定的用户。
        pool::redis()->hDel(self::fd_bind_user_redis_key, $user_id);
        return true;
    }

在这段逻辑中主要是通过fd来查找之前我们生成的所有缓存内容,将所有与当前fd相关的内容全部删除。也就使得用户与我们的业务脱离了关系。

当两个用户都连接之后,我们可以看到,redis中一共有如下几个Key:

1) "ws_topic_1_1"
2) "ws_user_2"
3) "ws_fd_bind_user_redis_key"
4) "ws_user_bind_fd_redis_key"
5) "ws_user_4"

我们打开其中的一个去查看,可以发现,两个用户ID正好对应两个fd

127.0.0.1:6379> hkeys ws_fd_bind_user_redis_key
1) "10086"
2) "10087"
127.0.0.1:6379> hget ws_fd_bind_user_redis_key 10086
"2"
127.0.0.1:6379> hget ws_fd_bind_user_redis_key 10087
"4"

然后我们试着关闭10087的用户

再去查看redis中的内容

127.0.0.1:6379> keys *
1) "ws_topic_1_1"
2) "ws_user_2"
3) "ws_fd_bind_user_redis_key"
4) "ws_user_bind_fd_redis_key"

127.0.0.1:6379> hkeys ws_fd_bind_user_redis_key
1) "10086"

127.0.0.1:6379> hkeys ws_user_bind_fd_redis_key
1) "2"
127.0.0.1:6379>

所有关于用户10087的内容都已经被删除了。

至此,整个业务流程全部完成。

项目已经放在了github上,欢迎大家批评指正。 https://github.com/gsbhx/swoole_chat

下一步,计划使用Golang实现一下这一功能。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK