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


    研究了一下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++字符串的机制是末尾是,所以在字符串后,00字节就是

    然后是第二个字符串长度为01 00,也就是为1

    61同理,十进制转ascii码,为a,之后的00为c++机制的

    完美解析,发送包无措,之后c++服务器也返回了相应的包,我在按照同理进行解包就可以了!

  • 相关阅读:
    GO语言的进阶之路-Golang字符串处理以及文件操作
    将本地的代码推送到公网的github账号去
    GO语言的进阶之路-go的程序结构以及包简介
    Linux操作系统原理
    Linux安装-kickstart无人值守安装
    LVM逻辑卷管理
    Liunx软Raid实现
    parted分区工具用法
    高级Linux运维工程师必备技能(扫盲篇)
    H3C配置FTP服务器
  • 原文地址:https://www.cnblogs.com/moqiang02/p/4061559.html
Copyright © 2020-2023  润新知