亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

數據傳輸的協議

發布時間:2020-06-28 19:10:36 來源:網絡 閱讀:5221 作者:超級極客 欄目:編程語言

1數據協議

1TCP,websocket,http這些是屬于底層的傳輸協議。保障服務器和客戶端可以收發數據。


2假設接收到了數據之后,有什么用呢,比如服務器需要知道客戶端發來的數據是干嘛的,

所以就需要用到數據協議。 也就是客戶端和服務器商量好一種數據協議.

根據這種自定義的協議收發數據, 服務器就能聽懂 客戶端的協議了。


3比如說登陸協議,用戶名密碼啊這些.  這就是上層的協議。


4游戲數據協議每一個數據包都不能過大, 比如64k,如果超出可以在發送的

時候,把這些數據進行分包. 這樣做可以防止惡意***,


 


6分包協議:

第一種模式:包頭+包體模式   

第二種模式:\r\n為結束符號的模式;



命令組成的協議: 比如一個登陸協議

發送:

命令主類型號:用戶登陸的命令,用戶注冊的命令

命令子類型號   用戶名    密碼


返回:

命令類型號,命令子類型號,返回碼, 為多少就返回用戶的數據 






2二進制數據協議

1 二進制協議原理:

    直接將內存里的對象保存為二進制數據,然后通過封包(size+(二進制數據))

的方式發送出去,  解包的時候,讀取size,然后讀取二進制數據,再根據二進制的

結構體描述文件來解開這個包,獲取每個數據成員的數據.


2設計原理:

//協議的結構體
struct person{
    int main_type.
    int sub_type,
    char* name,
    int uid,
    int age,
    int sex,
    ...
}

//首先將這個結構體里面的每個數據成員對應的值寫入到內存,然后一個封包好的地址
//序列化二進制 打包
unsigned char* pack_person(結構體)

然后進行封包 [包頭 size ]+[包體]

//反序列號 解包
struct person* unpack_person(unsigned char* data,int len);

3二進制協議的設計優點:

     體積小,傳輸的性能好,高效



4二進制協議的缺點:

    有一些語言的支持不好,比如javascript,腳本語言去解析內存,

本身需要c/c++的支持,然后到處腳本的接口,所以這種模式非常不適合h6游戲.

不適合服務器和客戶端使用不同的語言.





3json數據協議

1 json數據協議,為了改變二進制的不足,改變二進制的封包與解包需要

以來于每個協議的對象,使用跨語言的數據交換格式json與xml相比,體積會比

xml小,可讀性比二進制好,跨語言的封包和解包,每個語言只需要實現json的解碼編碼即可


2json數據格式的封包格式,不采用size+body的方式,因為腳本語言不適合直接操作字節,

所以采用\r\n的模式, 收到/r/n后認為就是一個數據包,所以在編碼好的json字符串里

不能有\r\n, 但是字符串里面有\r\n的話呢

這樣的話就是要把這些數據轉換成base64編碼






4二進制數據傳輸服務器的設計

首先設計協議的結構,客戶端和服務器公用同一個封包和拆包的代碼。

這個包是這樣設計的,前面兩個字節放長度,然后緊接著4個字節放協議類型,后面再放數據包。

//使用#define 或者 enum來定義一個協議
enum{
	USER_LOGIN = 0, //用戶登錄
};

//設計登陸的         數據包1
struct user_login{
    char* name; //賬號
    char* passwd;//密碼
    int channel; 一個標志
};


//返回給客戶端登陸結果 數據包2  
struct user_login_response {
    int status;//登陸狀態  1就是登陸成功
    char* name; //名字
    int level;  //等級
};

不同的包要不同的處理API  
數據包1  就是對登陸的請求進行  封包
int command_login_pack(int cmd_type,struct user_login_req*
                            req, unsigned char* dst){
     //unsigned 防止最高位擴展
     //無符號比有符號能保存2倍于有符號類型的正整數
    //cmd_type就是 協議類型  然后就是這個結構體,out是一個輸出的指針  
    //執行輸出的內存的指針
    
    
    unsigned cahr* walk = dst;
    int len= 0;
    
    
  //前面4個字節cmd_type 因為你可能有很多這樣的命令
    *((int*)walk) = cmd_type;//將這個變量以地址形式顯示,然后取他的值
    walk += 4;   //內存向前4個字節
    
    //用戶名和密碼 
    sprintf(walk, "%s", req->uname)
     //跳過這個字符串的長度 + 1 是因為有0的結尾符
    walk += strlen(walk) + 1; 
    
    sprintf(walk, "%s", req->upasswd);
    walk += strlen(walk) + 1;
    
    *((int*)walk) = req->channel;
    
    	walk += 4;
	len = walk - dst;//長度
	return len;

}


//登陸請求的解包設計
void command_login_unpack(unsigned char* data,
				int len, struct user_login_req* out){
				
	   //data就是服務器收到的二進制數據
          char* walk = (char*)data;
          out->uname = _strdup(walk);
	  walk += strlen(walk) + 1;  //+1就是結尾符
	  
	  out->upasswd = _strdup(walk); //字符串拷貝函數 需要free釋放內存
	  walk += strlen(walk) + 1;
	
	  out->channel = *(int*)walk;
}



//返回結果封包和解包

int login_response_pack(int cmd_type,struct user_login_response*
			respons, unsigned char* out)
{
	//unsigned 防止最高位擴展
	//無符號比有符號能保存2倍于有符號類型的正整數

	unsigned char* walk = out;
	*(int*)walk = cmd_type;
	walk += 4;


	*(int*)walk = respons->status;
	walk += 4; 


	sprintf(walk,"%s", respons->name);
	walk += (strlen(walk) + 1);


	*(int*)walk = respons->level;
	walk += 4;

	return (walk - out);
}


void login_response_unpack(unsigned char* data, int len,struct 
		user_login_response* out)
{
	unsigned char* walk = data;
	out->status = *(int*)walk;
	walk += 4;

	out->name = _strdup(walk);
	walk += (strlen(walk) + 1);

	out->level = *(int*)walk;
	walk += 4;

}





然后 客戶端和服務器 需要公用這個 協議文件

首先客戶端會創建一個請求

//從這里開始發送登錄請求 //////////////////////////////客戶端發送請求
struct user_login req;  // 用戶登陸的結構體
req.uname = "小明";    //賬號
req.upasswd = "1123456";   //密碼
req.channel = 10;       //一個標記

char send_buf[4096]; 
//封包  跳過前面兩個字節 用來存長度
int len = command_login_pack(USER_LOGIN, &req ,send_buf+2);
//返回的len就是長度直接把這個長度個 這個 緩沖區
*((unsigned int *)send_buf) = (len + 2);
send(s, send_buf, len + 2, 0);  //發送給客戶端




// 從這里收取服務器的處理結果了  ////////////////////////////////服務器收到處理請求
        
        int size = (*(unsigned short*)io_data->pkg); //獲取前面兩個字節的長度
        //內存這里要+2個字節 才是協議
         data += 2;   
        
	//前面4個字節總是包的命令  也就是協議
	switch (*(int*)data){
		case USER_LOGIN:{    //判斷是不是登陸協議
		//解包  
			

		        //之后先調用回調函數
		        SERVER.cmd_func[USER_LOGIN](s,data+4,len-4);  +4個字節 就是協議的長度
			
				
		}break;
			
	}

/////////////////////////////////登陸處理回調函數
	//  解包
	struct user_login_req req;
	command_login_unpack(data, len, &req);


        //然后就能拿到完整的數據了
        printf("%s:%s==%d登錄請求\n", req.uname,req.upasswd,req.channel);
        
        
        
        
        
        
        
        /////////////////////////////到這里  應該就是要查詢數據庫了
        
        //返回ok        隨便返回一數據
        struct user_login_response res;
	res.level = 100;
	res.name = "張三";
	res.status = 1;  //登錄OK
        
        
        	//封包
	unsigned char send_buf[256];
	len = login_response_pack(USER_LOGIN, &res,send_buf);
        
        
        
        
        
        在發送前我們要在這個字符串前面加兩個字節的表示長度

    //len就是你要的長度
    char* send_buf = malloc(len + 2); //先申請一個內存
    memcpy(send_buf + 2, data,len);   //把數據跳過前面兩個字節進行拷貝
    //把長度賦值給前面兩個字節 首先len+2 把len的值以地址顯示,然后取值
    *(unsigned short*)send_buf = (len + 2);
    發送給客戶端
        
        
        
        
      
      
      ////////////////////////////////////////////////////客戶端 收到響應
      	len = recv(s, send_buf,4096,0);

	struct user_login_response respons;
	//解包
	if ((*(int*)(send_buf + 2)) == USER_LOGIN){
		login_response_unpack(send_buf + 2 + 4, len - 2 - 4, &respons);
		printf("請求結果:%d==%s\n", respons.status, respons.status ? "成功" : "失敗");
		printf("用戶等級:%d=用戶姓名:%s\n", respons.level, respons.name);

	}

數據傳輸的協議






向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

井陉县| 洛南县| 壤塘县| 大埔区| 宣武区| 定边县| 济阳县| 明水县| 连平县| 赤壁市| 石泉县| 天镇县| 资兴市| 碌曲县| 乐平市| 安乡县| 安西县| 新平| 霞浦县| 增城市| 加查县| 怀柔区| 溧水县| 东辽县| 塘沽区| 三都| 北海市| 张家界市| 内江市| 衡山县| 铅山县| 五华县| 容城县| 喜德县| 界首市| 庆城县| 晋江市| 宜兰市| 丰城市| 白玉县| 明水县|