1. 程式人生 > >php從零搭建即時通訊(二.專案架構)

php從零搭建即時通訊(二.專案架構)

零.序言

經過上面一系列的學習,我們已經學會了gatewaywork的基本使用,下面讓我們來動手將我們這個即時通訊的專案的骨架搭建起來吧

一.資料結構的定義

在上面我們已經說了,客戶端與服務的資料互動,只能是字串,

為了方便我們將那些字串格式化為json

在這個專案內,我們會進行非常多的資料互動,那麼為了我們能在編碼時的規範,我們將所有的互動的資料都定義為以下的資料結構

$data = [
   "type" => "say_txt",//傳遞的型別		
   "from_uid" => 10,//傳送者的uid		
   "to_uid" => 20,//接收者的uid		
   "data" => "我是10,你好啊20"//想要傳遞的資料
];   

然後每次傳送我們都將按著這個結構去生成對應的資料,然後格式化為json,進行資料互動

二.伺服器的架構

因為這個專案的原理是這樣

客戶端所有的接受,傳送等操作,都不是直接給他想要傳送的那個客戶端,

而是先發送給伺服器,伺服器進行相應的操作以後,再有伺服器傳送給想要傳送的那個客戶端,

例如A向B傳送一個hellow world

不能直接A把資料給B

而是應該,A把資料先給伺服器

伺服器進行相關的操作

伺服器再把資料傳給B

所以伺服器的onmessage方法(伺服器接受到客戶端傳來訊息時觸發)會相當使用的相當頻繁

下面就讓我們具體看看onmessage函式的通用邏輯模板應該怎麼編寫吧

最開始它長這樣

/**
    * 當客戶端發來訊息時觸發
    * @param int $client_id 連線id
    * @param mixed $message 具體訊息
    */
   public static function onMessage($client_id, $message)
   {
	//code...
   }

然後我們知道$message引數就是客戶端傳來的資訊是json格式,

所以我們不能直接拿來用,

我們先把jons格式解碼為php裡的物件進行操作

/**
    * 當客戶端發來訊息時觸發
    * @param int $client_id 連線id
    * @param mixed $message 具體訊息
    */
   public static function onMessage($client_id, $message)
   {
		//獲取客戶端傳送的json
        $client_obj = json_decode($message);
		//code...
   }

舉個栗子,現在客戶端傳送過來一個要求將一段文字傳送給另一個客戶端的請求

首先客戶端發來的json會是這樣的格式

$data = [
   "type" => "say_txt",   //傳遞的型別
   "from_uid" => 10,     //傳送者的uid
   "to_uid" => 20,         //接收者的uid
   "data" => "我是10,你好啊20"    //想要傳遞的資料
]; 

那我們應該先分析,客戶端傳來的這個資料,他想進行什麼操作,是給某人發訊息,還是詢問某人是否線上等

我們首先應該根據資料中的type選擇對應的操作

/**
    * 當客戶端發來訊息時觸發
    * @param int $client_id 連線id
    * @param mixed $message 具體訊息
    */
   public static function onMessage($client_id, $message)
   {
		//獲取客戶端傳送的json
        $client_obj = json_decode($message);

		//判斷使用者傳送的資訊的型別
		switch ($client_obj->type){
           //傳送給某個人文字
           case "say_txt":
               //code..........
                break;
		}
   }

然後再再對應具體的邏輯進行編寫

public static function onMessage($client_id, $message)
   {
		//獲取客戶端傳送的json
        $client_obj = json_decode($message);
		//code...
		//判斷使用者傳送的資訊的型別
		switch ($client_obj->type){
           //傳送給某個人文字
           case "say_txt":
               //向接收者推送訊息
				$data = [
					"type" => 'say_txt',
					"from_uid" => $client_obj->from_uid,
					"to_uid" => $client_obj->to_uid,
					"data" => $client_obj->data,
				];
				Gateway::sendToUid($client_obj->to_uid,json_encode($data));
                break;
		}
   }

那比如我們現在要寫a詢問b是否線上的請求怎麼寫呢
1.在case裡新增一個is_online的分支
2.在is_online裡去編寫具體的邏輯

public static function onMessage($client_id, $message)
   {
		//獲取客戶端傳送的json
        $client_obj = json_decode($message);
		//code...
		//判斷使用者傳送的資訊的型別
		switch ($client_obj->type){
           //傳送給某個人文字
           case "say_txt":
               //向接收者推送訊息
				$data = [
					"type" => 'say_txt',
					"from_uid" => $client_obj->from_uid,
					"to_uid" => $client_obj->to_uid,
					"data" => $client_obj->data,
				];
				Gateway::sendToUid($client_obj->to_uid,json_encode($data));
                break;
			 //判斷某個使用者是否線上
            case "is_online":
                $status = Gateway::isUidOnline($client_obj->to_uid);
                $data = [
                    "type" => "is_online",
                    "status" => $status,
                ];
                //向傳送者返回接受者是否線上的訊息
                Gateway::sendToUid($client_obj->from_uid,json_encode($data));
                break;
		}
   }

所以以後所有的邏輯都可以按照上面的模板進行編寫

三.客戶端的架構

客戶端的架構與伺服器基本一致
只不過客戶端收到伺服器傳來的資訊時,觸發的是websocked物件的onmessage方法,話不多說,上程式碼

1.獲取資料,並格式化為js物件

//檢測伺服器是否給客戶端傳送訊息
	ws.onmessage = function(e){
		//獲取伺服器傳來的資料
		let server_data = JSON.parse(e.data);
	}

2.根據伺服器傳來資料中型別的不同,建立不同的分支

//檢測伺服器是否給客戶端傳送訊息
	ws.onmessage = function(e){
		//獲取伺服器傳來的資料
		let server_data = JSON.parse(e.data);
		
		switch (server_data.type){
			//收到伺服器發來要求初始化的訊息
			case "init":
			//code...
			break;
		}
	}

3.編寫具體的邏輯程式碼

//檢測伺服器是否給客戶端傳送訊息
	ws.onmessage = function(e){
		//獲取伺服器傳來的資料
		let server_data = JSON.parse(e.data);
		
		switch (server_data.type){
			//收到伺服器發來要求初始化的訊息
			case "init":
				//繫結uid
				init_information();
				//獲取使用者名稱與頭像
				get_head_img();
				//將所有的與接收者的訊息該為以讀
				set_allRead();
				break;
		}
	}

4.當有新功能需要新增時,重複2,3即可

//檢測伺服器是否給客戶端傳送訊息
	ws.onmessage = function(e){
		//獲取伺服器傳來的資料
		let server_data = JSON.parse(e.data);
		
		switch (server_data.type){
			//收到伺服器發來要求初始化的訊息
			case "init":
				//繫結uid
				init_information();
				//獲取使用者名稱與頭像
				get_head_img();
				//將所有的與接收者的訊息該為以讀
				set_allRead();
				break;
			//判讀某個使用者是否線上
            case "is_online":
				is_online(server_data.status);
				break;
		}
	}