php和c++socket通讯(基于字节流,二进制)

来源:互联网 发布:英雄联盟js打野符文 编辑:程序博客网 时间:2024/05/01 09:59

php和c++socket通讯(基于字节流,二进制)

3702人阅读 评论(7)收藏 举报
phpc++socketqtpack

研究了一下PHP和C++socket通讯,用C++作为服务器端,php作为客户端进行.

socket通讯是基于协议的,因此,只要双方协议一致就行.

关于协议的选择:我看过网上大部分协议都是在应用层的协议,选用这样的协议很方便,基本上就是字符串传过来,传过去

本次研究的协议算是当今国际化的一个标准做法.length+flag+body(长度+类型+内容)的方式,

total_lengthcodeflaglength1string1length2string2总长度操作类型标志字符串1长度字符串1字符串2长度字符串24字节2字节4字节(暂时无用)2字节x字节2字节x字节

php实现方式,也很容易,通过pack打包成二进制进行通讯.下面贴一下代码

本地测试主要应用为:发送账号和密码给服务器端

[php] view plaincopyprint?
  1. <?php  
  2. class Byte{  
  3.     //长度  
  4.     private $length=0;  
  5.       
  6.     private $byte='';  
  7.     //操作码  
  8.     private $code;  
  9.     public function setBytePrev($content){  
  10.         $this->byte=$content.$this->byte;  
  11.     }  
  12.     public function getByte(){  
  13.         return $this->byte;  
  14.     }  
  15.     public function getLength(){  
  16.         return $this->length;  
  17.     }  
  18.     public function writeChar($string){  
  19.         $this->length+=strlen($string);  
  20.         $str=array_map('ord',str_split($string));  
  21.         foreach($str as $vo){  
  22.             $this->byte.=pack('c',$vo);  
  23.         }  
  24.         $this->byte.=pack('c','0');  
  25.         $this->length++;  
  26.     }  
  27.     public function writeInt($str){  
  28.         $this->length+=4;  
  29.         $this->byte.=pack('L',$str);  
  30.     }  
  31.     public function writeShortInt($interge){  
  32.         $this->length+=2;  
  33.         $this->byte.=pack('v',$interge);  
  34.     }  
  35. }  
  36. class GameSocket{  
  37.     private $socket;  
  38.     private $port=9991;  
  39.     private $host='192.168.211.231';  
  40.     private $byte;  
  41.     private $code;  
  42.     const CODE_LENGTH=2;  
  43.     const FLAG_LENGTH=4;  
  44.     public function __set($name,$value){  
  45.         $this->$name=$value;  
  46.     }  
  47.     public function __construct($host='192.168.211.231',$port=9991){  
  48.         $this->host=$host;  
  49.         $this->port=$port;  
  50.         $this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);  
  51.         if(!$this->socket){  
  52.             exit('创建socket失败');  
  53.         }  
  54.         $result = socket_connect($this->socket,$this->host,$this->port);  
  55.         if(!$result){  
  56.             exit('连接不上目标主机'.$this->host);  
  57.         }  
  58.         $this->byte=new Byte();  
  59.     }  
  60.     public function write($data){  
  61.         if(is_string($data)||is_int($data)||is_float($data)){  
  62.             $data[]=$data;  
  63.         }  
  64.         if(is_array($data)){  
  65.             foreach($data as $vo){  
  66.                 $this->byte->writeShortInt(strlen($vo));  
  67.                 $this->byte->writeChar($vo);  
  68.             }  
  69.         }  
  70.         $this->setPrev();  
  71.         $this->send();  
  72.     }  
  73.     /* 
  74.      *设置表头部分 
  75.      *表头=length+code+flag 
  76.      *length是总长度(4字节)  code操作标志(2字节)  flag暂时无用(4字节) 
  77.      */  
  78.     private function getHeader(){  
  79.         $length=$this->byte->getLength();  
  80.         $length=intval($length)+self::CODE_LENGTH+self::FLAG_LENGTH;  
  81.         return pack('L',$length);  
  82.     }  
  83.     private function getCode(){  
  84.         return pack('v',$this->code);  
  85.     }  
  86.     private function getFlag(){  
  87.         return pack('L',24);  
  88.     }  
  89.       
  90.     private function setPrev(){  
  91.         $this->byte->setBytePrev($this->getHeader().$this->getCode().$this->getFlag());  
  92.     }  
  93.   
  94.     private function send(){  
  95.         $result=socket_write($this->socket,$this->byte->getByte());  
  96.         if(!$result){  
  97.             exit('发送信息失败');  
  98.         }  
  99.     }  
  100.     public function __desctruct(){  
  101.         socket_close($this->socket);  
  102.     }  
  103. }  
  104.   
  105. $data[]='testzouhao';  
  106. $data[]='a';  
  107. $gameSocket=new GameSocket();  
  108. $gameSocket->code=11;  
  109. $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++服务器也返回了相应的包,我在按照同理进行解包就可以了!

0 0