php和c++socket通讯(基于字节流,二进制)
2024-08-26 08:52:57
研究了一下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++服务器也返回了相应的包,我在按照同理进行解包就可以了!
最新文章
- Java多线程
- 计算机程序的思维逻辑 (51) - 剖析EnumSet
- Odoo 8.0 new API 之Environment
- yum:在Red Hat和Fedora中使用
- 【bzoj3211】花神游历各国
- 【Java源码分析】LinkedList类
- Neutron分析(7)—— neutron-l3-agent HA solutions
- TestNG中同一个类中执行多个test()方法如何配置testng.xml
- 【加密】C#.NET 各种加密解密
- hdu1505(dp求最大子矩阵)
- 多平台Client TCP通讯组件
- JavaScript实现
- [Swift]LeetCode780. 到达终点 | Reaching Points
- 从头配置,开发 cocos2dx 3.14.1
- 爬起点小说 day02
- 区块链3.0 ada Cardano卡尔达诺如何获得一致好评?
- [Unity动画]05.Entry &; Exit &; Any State
- 【密码学】轻松理解“加盐”的原理与java实现
- http免费升级https 攻略(超简单)
- asp.net六种方法刷新页面