文档章节

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

啊和
 啊和
发布于 2013/07/23 10:06
字数 867
阅读 982
收藏 2
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++服务器也返回了相应的包,我在按照同理进行解包就可以了!


本文转载自:http://www.sctarena.com/Article/Article.asp?nid=4703

共有 人打赏支持
啊和
粉丝 10
博文 42
码字总数 1249
作品 0
石景山
程序员
私信 提问
hadoop深入研究:(十)——序列化与Writable接口

转载请写明来源地址:http://blog.csdn.net/lastsweetop/article/details/9193907 所有源码在github上,https://github.com/lastsweetop/styhadoop 简介 序列化和反序列化就是结构化对象和字...

lastsweetop
2013/07/05
0
0
类加载时机与过程 asdfsadfasdfsa 09-19 268

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34173549/article/details/79612719 通过之前的介绍可知,类加载过程共有5个步骤,分别是:加载、验证、准...

追风筝的猪
2018/03/20
0
0
理解Java中字符流与字节流的区别

什么是流 字节流 public abstract int read() throws IOException; public int read(byte b[]) throws IOException { } public int read(byte b[], int off, int len) throws IOException {......

清尘V
2016/04/21
105
0
php socket方面的问题

@狮子的魂 你好,想跟你请教个问题:主要是二进制字节流,tcp传输一次可能有多个包或者半个包,那我在php这边怎么解包呢?保证收到有效的数据包 丢弃无效的数据包呢?希望大神有时间能回答一...

大地之灯
2016/07/27
193
1
什么时候使用字节流、什么时候使用字符流,二者的区别

在程序中所有的数据都是以流的方式进行传输或保存的,程序需要数据的时候要使用输入流读取数据,而当程序需要将一些数据保存起来的时候,就要使用输出流完成。 InputStream 和OutputStream,...

watermelon11
02/24
0
0

没有更多内容

加载失败,请刷新页面

加载更多

树形结构的数据库表Schema设计

程序设计过程中,我们常常用树形结构来表征某些数据的关联关系,如企业上下级部门、栏目结构、商品分类等等,通常而言,这些树状结构需要借助于数据库完成持久化。然而目前的各种基于关系的数...

太菜鸟
20分钟前
0
0
Pod在多可用区worker节点上的高可用部署

一、 需求分析 当前kubernetes集群中的worker节点可以支持添加多可用区中的ECS,这种部署方式的目的是可以让一个应用的多个pod(至少两个)能够分布在不同的可用区,起码不能分布在同一个可用...

迷你芊宝宝
29分钟前
0
0
使用maven命令上传jar包到仓库

mvn deploy:deploy-file -DgroupId=com.jz.tss.service -DartifactId=tss-service -Dversion=1.9.02-SNAPSHOT -Dfile=E:/Workspace/tss-service/build/oracle/TSS-Service/WEB-INF/lib/TSS-S......

GodIsCj
31分钟前
2
0
mysql 向下无限递归(不使用函数,单纯sql)

表结构和数据 CREATE TABLE table1(id int, name varchar(10), parent_id int); INSERT table1 VALUES (1, 'Home', 0), (2, 'About', 1), (3, 'Contact', 1), (4, 'Legal', 2), ......

一雨成东
31分钟前
0
0
面试官问:ZooKeeper 一致性协议 ZAB 原理

一致性协议有很多种,比如 Paxos,Raft,2PC,3PC等等,今天我们讲一种协议,ZAB 协议,该协议应该是所有一致性协议中生产环境中应用最多的了。为什么呢?因为他是为 Zookeeper 设计的分布式...

Java爬坑之路
34分钟前
17
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部