socket位元組流解析(網路抓包解析)
阿新 • • 發佈:2019-02-14
研究了一下PHP和C++socket通訊,用C++作為伺服器端,php作為客戶端進行.
socket通訊是基於協議的,因此,只要雙方協議一致就行.
關於協議的選擇:我看過網上大部分協議都是在應用層的協議,選用這樣的協議很方便,基本上就是字串傳過來,傳過去
本次研究的協議算是當今國際化的一個標準做法.length+flag+body(長度+型別+內容)的方式,
total_length | code | flag | length1 | string1 | length2 | string2 |
總長度 | 操作型別 | 標誌 | 字串1長度 | 字串1 | 字串2長度 | 字串2 |
4位元組 | 2位元組 | 4位元組(暫時無用) | 2位元組 | x位元組 | 2位元組 | x位元組 |
php實現方式,也很容易,通過pack打包成二進位制進行通訊.下面貼一下程式碼
本地測試主要應用為:傳送賬號和密碼給伺服器端
<?php class Byte{ //長度 private $length=0; private $byte=''; //操作碼 private $code; public function setBytePrev($content){ $this->byte=$content.$this->byte; } public function getByte(){ return $this->byte; } public function getLength(){ return $this->length; } public function writeChar($string){ $this->length+=strlen($string); $str=array_map('ord',str_split($string)); foreach($str as $vo){ $this->byte.=pack('c',$vo); } $this->byte.=pack('c','0'); $this->length++; } public function writeInt($str){ $this->length+=4; $this->byte.=pack('L',$str); } public function writeShortInt($interge){ $this->length+=2; $this->byte.=pack('v',$interge); } } class GameSocket{ private $socket; private $port=9991; private $host='192.168.211.231'; private $byte; private $code; const CODE_LENGTH=2; const FLAG_LENGTH=4; public function __set($name,$value){ $this->$name=$value; } public function __construct($host='192.168.211.231',$port=9991){ $this->host=$host; $this->port=$port; $this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); if(!$this->socket){ exit('建立socket失敗'); } $result = socket_connect($this->socket,$this->host,$this->port); if(!$result){ exit('連線不上目標主機'.$this->host); } $this->byte=new Byte(); } public function write($data){ if(is_string($data)||is_int($data)||is_float($data)){ $data[]=$data; } if(is_array($data)){ foreach($data as $vo){ $this->byte->writeShortInt(strlen($vo)); $this->byte->writeChar($vo); } } $this->setPrev(); $this->send(); } /* *設定表頭部分 *表頭=length+code+flag *length是總長度(4位元組) code操作標誌(2位元組) flag暫時無用(4位元組) */ private function getHeader(){ $length=$this->byte->getLength(); $length=intval($length)+self::CODE_LENGTH+self::FLAG_LENGTH; return pack('L',$length); } private function getCode(){ return pack('v',$this->code); } private function getFlag(){ return pack('L',24); } private function setPrev(){ $this->byte->setBytePrev($this->getHeader().$this->getCode().$this->getFlag()); } private function send(){ $result=socket_write($this->socket,$this->byte->getByte()); if(!$result){ exit('傳送資訊失敗'); } } public function __desctruct(){ socket_close($this->socket); } } $data[]='testzouhao'; $data[]='a'; $gameSocket=new GameSocket(); $gameSocket->code=11; $gameSocket->write($data);
通過抓包分析,得到本次的包內容
包頭等等都不用看了,主要看藍色部分.
根據協議分析,前4個位元組為表頭,代表的是長度
因此:
17 00 00 00代表的是表頭長度,17為16進位制,轉換為十進位制為23,代表其餘部分全部加為23位元組.
0b 00代表的是操作碼為11,代表是登入操作
18 00 00 00代表的是flag,暫時無用,不去理會
0a 00 代表的字串1的長度,轉為十進位制為10
74 65 73 74 7a 6f 75 68 61 6f 分別轉為十進位制之後,是ascii碼對應的字元,結果為:testzouhao,
由於C++字串的機制是末尾是\0,所以在字串後,00位元組就是\0
然後是第二個字串長度為01 00,也就是為1
61同理,十進位制轉ascii碼,為a,之後的00為c++機制的\0
完美解析,傳送包無措,之後c++伺服器也返回了相應的包,我在按照同理進行解包就可以了!