Quantcast
Channel: CSDN博客推荐文章
Viewing all articles
Browse latest Browse all 35570

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

$
0
0

研究了一下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++服务器也返回了相应的包,我在按照同理进行解包就可以了!

作者:zouhao619 发表于2013-6-3 21:19:49 原文链接
阅读:1 评论:0 查看评论

Viewing all articles
Browse latest Browse all 35570

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>