swoole實現多對多羣聊(三)

這次來是因爲上篇文章swoole實現多對多羣聊進階篇的pdo鏈接有效時間好像不是那麼的長!!!導致數據完全丟失!!!
通過測試,發現pdo鏈接在一個小時左右後就不會再往數據庫插入數據了,而且sql語句執行也不會報錯,具體什麼情況一時間還不清楚,然後開始找是不是pdo鏈接不支持長鏈接,百度了一下,果然需要配置才能實現長鏈接
PDO有一項參數,名爲PDO::ATTR_PERSISTENT是個booleans值,默認不開啓,
屁顛屁顛的開啓跑去測試後發現,還是不行,還是會斷開,這我又想不通了,如果斷開,執行sql理應會報錯啊,然後在try catch 語句下手

try {
    $stmt = $this->pdo->prepare($sql);
    $stmt->execute();
} catch (Exception $e) {
    $this->pdo = new PDO(
        "mysql:host=********;dbname=******;charset=utf8;",
        "********",
        "********",[\PDO::ATTR_CASE => \PDO::CASE_NATURAL]
    );
}

這裏的意圖是,如果執行sql報錯,我就從新初始化pdo鏈接,不過結果也不盡人意,執行sql什麼事都沒有,數據庫沒有記錄,也不報錯,想來想去,只能是小弟搞得鬼了,要把小弟拉出去祭天!

上篇文章中的小弟相關的代碼

//創建token找幾個小弟
$this->ws->set([
    'worker_num' => WORKER_NUM,
    'task_worker_num' => TASK_WORKER_NUM,
]);

//token線程監聽
$this->ws->on("task", [$this, 'onTask']);
$this->ws->on('finish',[$this,'onFinish']);

我就想,會不會是小弟線程導致的問題,pdo鏈接被他吃掉了,後來一看代碼

/**
 * 監聽用戶鏈接事件,鏈接時需要帶用戶id與房間id參數,再把用戶存到房間域中
 */
public function onOpen($server, $request){
    //加入房間域
    $this->redis->hset($request->get['room'], $request->get['uid'], $request->fd);
    //加入組集合
    $this->redis->sadd('group', $request->get['room']);

	//鏈接後,插入一條日誌
	self::recordLog($request->fd, $request->get['uid'], $request->get['room'], "add");

}

在用戶開始鏈接websocket的時候,我也會去數據庫插一條記錄,並沒有用到小弟,所以小弟的嫌疑就沒了…
這下就沒轍了,只好換跳思路實現功能了,跑到swoole官網,找到了異步MySQL客戶端相關的介紹,本着試一試的心態,把代碼貼進去

	public $pdo = null;
	public $dbdata = null;
	public $sql = null;

	public function __construct()
	{
		...//其他代碼
		$this->pdo = new swoole_mysql();
	    $this->dbdata = array(
	        'host' => '******',
	        'port' => 3306,
	        'user' => '*********',
	        'password' => '*******',
	        'database' => '*********',
	        'charset' => 'utf8', //指定字符集
	        'timeout' => 2,  // 可選:連接超時時間(非查詢超時時間),默認爲SW_MYSQL_CONNECT_TIMEOUT(1.0)
	    );
		...//其他代碼
	}
	
	...//其他代碼
	
	//房間記錄 fd-uid-room
	private function recordLog($fd, $uid, $room_id, $type)
	{
	    switch ($type){
	        case "add":
	            $this->sql = "***********";
	            break;
	        case "close":
	            $this->sql = "**********";
	            break;
	    }
	    try {
	        $this->pdo->connect($this->dbdata, function ($db, $r) {
                if ($r === false) {
                    var_dump($db->connect_errno, $db->connect_error);
                    die;
                }
                $this->pdo->query($this->sql, function(swoole_mysql $db, $r) {
                    if ($r === false)
                    {
                        var_dump($db->error, $db->errno);
                    }
                    elseif ($r === true )
                    {
                        var_dump($db->affected_rows, $db->insert_id);
                    }
                    $db->close();
                });
            });
	    } catch (Exception $e) {
	        echo "recordLog error";
	    }
	}

	public function onTask($server, $task_id, $from_id, $data)
    {
        switch ($data['type']){
            case "change":
                self::push_room($data['room'], $data);
                break;
        }
        return true;
    }
	
	/**
     * 監聽關閉事件的回調
     */
	public function onClose($ser, $fd)
    {
        //退出房間清除redis
        $group = $this->redis->sMembers('group');
        foreach ($group as $v) {
            $fangjian = $this->redis->hgetall($v);
            if(empty($fangjian)) continue;
            foreach ($fangjian as $k => $vv) {
                if ($fd == $vv) {
                    $this->redis->hdel($v, $k);
                    self::recordLog($vv, $k, $v, "close");
                    break 2;
                }
            }
        }
    }

具體代碼大家可以參考上一篇文章swoole實現多對多羣聊進階篇,代碼都是大同小異,這裏可以看到,我沒有讓小弟去處理onclose事件了,因爲測試中,線程不能調用swoole_mysql的事件,所以小弟還有有嫌疑的,這裏就不先追究了,代碼改完後運行,第一次鏈接,插入一條記錄,間隔兩小時後,第二次鏈接,發現可以實現功能效果!
日誌記錄
完事收工!之前的代碼出錯的原因值得深入調查,但是目前還沒有查到,大家知道的可以評論告訴一下下我(認真臉)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章