Php socket数据编码

Posted jzssuanfa

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Php socket数据编码相关的知识,希望对你有一定的参考价值。

bytes.php  字节编码类

技术分享
/**
 * byte数组与字符串转化类
 * @author 
 * created on 2011-7-15
 */

class bytes {
   
    /**
     * 转换一个string字符串为byte数组
     * @param $str 须要转换的字符串
     * @param $bytes 目标byte数组
     * @author zikie
     */
    
    public static function getbytes($str) {

        $len = strlen($str);
        $bytes = array();
           for($i=0;$i<$len;$i++) {
               if(ord($str[$i]) >= 128){
                   $byte = ord($str[$i]) - 256;
               }else{
                   $byte = ord($str[$i]);
               }
            $bytes[] =  $byte ;
        }
        return $bytes;
    }
   
    /**
     * 将字节数组转化为string类型的数据
     * @param $bytes 字节数组
     * @param $str 目标字符串
     * @return 一个string类型的数据
     */
    
    public static function tostr($bytes) {
        $str = ‘‘;
        foreach($bytes as $ch) {
            $str .= chr($ch);
        }

           return $str;
    }
   
    /**
     * 转换一个int为byte数组
     * @param $byt 目标byte数组
     * @param $val 须要转换的字符串
     * @author zikie
     */
   
    public static function integertobytes($val) {
        $byt = array();
        $byt[0] = ($val & 0xff);
        $byt[1] = ($val >> 8 & 0xff);
        $byt[2] = ($val >> 16 & 0xff);
        $byt[3] = ($val >> 24 & 0xff);
        return $byt;
    }
   
    /**
     * 从字节数组中指定的位置读取一个integer类型的数据
     * @param $bytes 字节数组
     * @param $position 指定的開始位置
     * @return 一个integer类型的数据
     */
    
    public static function bytestointeger($bytes, $position) {
        $val = 0;
        $val = $bytes[$position + 3] & 0xff;
        $val <<= 8;
        $val |= $bytes[$position + 2] & 0xff;
        $val <<= 8;
        $val |= $bytes[$position + 1] & 0xff;
        $val <<= 8;
        $val |= $bytes[$position] & 0xff;
        return $val;
    }

    /**
     * 转换一个shor字符串为byte数组
     * @param $byt 目标byte数组
     * @param $val 须要转换的字符串
     * @author zikie
     */
   
    public static function shorttobytes($val) {
        $byt = array();
        $byt[0] = ($val & 0xff);
        $byt[1] = ($val >> 8 & 0xff);
        return $byt;
    }
   
    /**
     * 从字节数组中指定的位置读取一个short类型的数据。

* @param $bytes 字节数组 * @param $position 指定的開始位置 * @return 一个short类型的数据 */ public static function bytestoshort($bytes, $position) { $val = 0; $val = $bytes[$position + 1] & 0xff; $val = $val << 8; $val |= $bytes[$position] & 0xff; return $val; } }

技术分享

 

socket.class.php  socket赋值类

技术分享
<?php
define("CONNECTED", true);
define("DISCONNECTED", false);

/**
 * Socket class
 * 
 *  
 * @author Seven 
 */
Class Socket
{
    private static $instance;

    private $connection = null;
    
    private $connectionState = DISCONNECTED;
    
    private $defaultHost = "127.0.0.1";
    
    private $defaultPort = 80;
    
    private $defaultTimeout = 10;
    
    public  $debug = false;
    
    function __construct()
    {
        
    }
    /**
     * Singleton pattern. Returns the same instance to all callers
     *
     * @return Socket
     */
    public static function singleton()
    {
        if (self::$instance == null || ! self::$instance instanceof Socket)
        {
            self::$instance = new Socket();
           
        }
        return self::$instance;
    }
    /**
     * Connects to the socket with the given address and port
     * 
     * @return void
     */
    public function connect($serverHost=false, $serverPort=false, $timeOut=false)
    {        
        if($serverHost == false)
        {
            $serverHost = $this->defaultHost;
        }
        
        if($serverPort == false)
        {
            $serverPort = $this->defaultPort;
        }
        $this->defaultHost = $serverHost;
        $this->defaultPort = $serverPort;
        
        if($timeOut == false)
        {
            $timeOut = $this->defaultTimeout;
        }
        $this->connection = socket_create(AF_INET,SOCK_STREAM,SOL_TCP); 
        
        if(socket_connect($this->connection,$serverHost,$serverPort) == false)
        {
            $errorString = socket_strerror(socket_last_error($this->connection));
            $this->_throwError("Connecting to {$serverHost}:{$serverPort} failed.<br>Reason: {$errorString}");
        }else{
            $this->_throwMsg("Socket connected!");
        }
        
        $this->connectionState = CONNECTED;
    }
    
    /**
     * Disconnects from the server
     * 
     * @return True on succes, false if the connection was already closed
     */
    public function disconnect()
    {
        if($this->validateConnection())
        {
            socket_close($this->connection);
            $this->connectionState = DISCONNECTED;
            $this->_throwMsg("Socket disconnected!");
            return true;
        }
        return false;
    }
    /**
     * Sends a command to the server
     * 
     * @return string Server response
     */
    public function sendRequest($command)
    {
        if($this->validateConnection())
        {
            $result = socket_write($this->connection,$command,strlen($command));
            return $result;
        }
        $this->_throwError("Sending command \"{$command}\" failed.<br>Reason: Not connected");
    }
    
    
    
    public function isConn()
    {
        return $this->connectionState;
    }
    
    
    public function getUnreadBytes()
    {
        
        $info = socket_get_status($this->connection);
        return $info[‘unread_bytes‘];

    }

    
    public function getConnName(&$addr, &$port)
    {
        if ($this->validateConnection())
        {
            socket_getsockname($this->connection,$addr,$port);
        }
    }
    
   
    
    /**
     * Gets the server response (not multilined)
     * 
     * @return string Server response
     */
    public function getResponse()
    {
        $read_set = array($this->connection);
    
        while (($events = socket_select($read_set, $write_set = NULL, $exception_set = NULL, 0)) !== false) 
        {
            if ($events > 0)
            {
                foreach ($read_set as $so)
                {
                    if (!is_resource($so))
                    {
                        $this->_throwError("Receiving response from server failed.<br>Reason: Not connected");
                        return false;
                    }elseif ( ( $ret = @socket_read($so,4096,PHP_BINARY_READ) ) == false){
                        $this->_throwError("Receiving response from server failed.<br>Reason: Not bytes to read");
                        return false;
                    }
                    return $ret;
                }
            }
        }
        
        return false;
    }
    public function waitForResponse()
    {
        if($this->validateConnection())
        {
            return socket_read($this->connection, 2048);
        }
        
        $this->_throwError("Receiving response from server failed.<br>Reason: Not connected");
    return false;
    }
    /**
     * Validates the connection state
     * 
     * @return bool
     */
    private function validateConnection()
    {
        return (is_resource($this->connection) && ($this->connectionState != DISCONNECTED));
    }
    /**
     * Throws an error
     * 
     * @return void
     */
    private function _throwError($errorMessage)
    {
        echo "Socket error: " . $errorMessage;
    }
    /**
     * Throws an message
     * 
     * @return void
     */
    private function _throwMsg($msg)
    {
        if ($this->debug)
        {
            echo "Socket message: " . $msg . "\n\n";
        }
    }
    /**
     * If there still was a connection alive, disconnect it
     */
    public function __destruct()
    {
        $this->disconnect();
    }
}

?>
技术分享

PacketBase.class.php  打包类

技术分享
<?

php /** * PacketBase class * * 用以处理与c++服务端交互的sockets 包 * * 注意:不支持宽字符 * * @author Seven <[email protected]> * */ class PacketBase extends ContentHandler { private $head; private $params; private $opcode; /**************************construct***************************/ function __construct() { $num = func_num_args(); $args = func_get_args(); switch($num){ case 0: //do nothing 用来生成对象的 break; case 1: $this->__call(‘__construct1‘, $args); break; case 2: $this->__call(‘__construct2‘, $args); break; default: throw new Exception(); } } //无參数 public function __construct1($OPCODE) { $this->opcode = $OPCODE; $this->params = 0; } //有參数 public function __construct2($OPCODE, $PARAMS) { $this->opcode = $OPCODE; $this->params = $PARAMS; } //析构 function __destruct() { unset($this->head); unset($this->buf); } //打包 public function pack() { $head = $this->MakeHead($this->opcode,$this->params); return $head.$this->buf; } //解包 public function unpack($packet,$noHead = false) { $this->buf = $packet; if (!$noHead){ $recvHead = unpack("S2hd/I2pa",$packet); $SD = $recvHead[hd1];//SD $this->contentlen = $recvHead[hd2];//content len $this->opcode = $recvHead[pa1];//opcode $this->params = $recvHead[pa2];//params $this->pos = 12;//去除包头长度 if ($SD != 21316) { return false; } }else { $this->pos = 0; } return true; } public function GetOP() { if ($this->buf) { return $this->opcode; } return 0; } /************************private***************************/ //构造包头 private function MakeHead($opcode,$param) { return pack("SSII","SD",$this->TellPut(),$opcode,$param); } //用以模拟函数重载 private function __call($name, $arg) { return call_user_func_array(array($this, $name), $arg); } /***********************Uitl***************************/ //将16进制的op转成10进制 static function MakeOpcode($MAJOR_OP, $MINOR_OP) { return ((($MAJOR_OP & 0xffff) << 16) | ($MINOR_OP & 0xffff)); } } /** * 包体类 * 包括了对包体的操作 */ class ContentHandler { public $buf; public $pos; public $contentlen;//use for unpack function __construct() { $this->buf = ""; $this->contentlen = 0; $this->pos = 0; } function __destruct() { unset($this->buf); } public function PutInt($int) { $this->buf .= pack("i",(int)$int); } public function PutUTF($str) { $l = strlen($str); $this->buf .= pack("s",$l); $this->buf .= $str; } public function PutStr($str) { return $this->PutUTF($str); } public function TellPut() { return strlen($this->buf); } /*******************************************/ public function GetInt() { //$cont = substr($out,$l,4); $get = unpack("@".$this->pos."/i",$this->buf); if (is_int($get[1])){ $this->pos += 4; return $get[1]; } return 0; } public function GetShort() { $get = unpack("@".$this->pos."/S",$this->buf); if (is_int($get[1])){ $this->pos += 2; return $get[1]; } return 0; } public function GetUTF() { $getStrLen = $this->GetShort(); if ($getStrLen > 0) { $end = substr($this->buf,$this->pos,$getStrLen); $this->pos += $getStrLen; return $end; } return ‘‘; } /***************************/ public function GetBuf() { return $this->buf; } public function SetBuf($strBuf) { $this->buf = $strBuf; } public function ResetBuf(){ $this->buf = ""; $this->contentlen = 0; $this->pos = 0; } } ?>

技术分享

格式

技术分享
struct header
{
int type;     // 消息类型
int length;     // 消息长度
}

struct MSG_Q2R2DB_PAYRESULT

{

int serialno; 
int openid; 
char payitem[512];
int billno; 
int zoneid;
int providetype;  
int coins; 

}

调用的方法,另外需require两个php文件。一个是字节编码类,另外一个socket封装类。事实上主要看字节编码类就能够了!
技术分享

调用測试

技术分享
public function index() {
        $socketAddr = "127.0.0.1";    
        $socketPort = "10000";    
        try {
            
            $selfPath = dirname ( __FILE__ );
            require ($selfPath . "/../Tool/Bytes.php");
            $bytes = new Bytes ();
            
            $payitem = "sdfasdfasdfsdfsdfsdfsdfsdfsdf";
            $serialno = 1;
            $zoneid = 22;
            $openid = "CFF47C448D4AA2069361567B6F8299C2";
            
            $billno = 1;
            $providetype = 1;
            $coins = 1;
            
            $headType = 10001;
            $headLength = 56 + intval(strlen($payitem ));
            
            $headType = $bytes->integerToBytes ( intval ( $headType ) );
            $headLength = $bytes->integerToBytes ( intval ( $headLength ) );
            $serialno = $bytes->integerToBytes ( intval ( $serialno ) );
            $zoneid = $bytes->integerToBytes ( intval ( $zoneid ) );
            $openid = $bytes->getBytes( $openid  );
            $payitem_len = $bytes->integerToBytes ( intval ( strlen($payitem) ) );
            $payitem =  $bytes->getBytes($payitem);            
            $billno = $bytes->integerToBytes ( intval ( $billno ) );
            $providetype = $bytes->integerToBytes ( intval ( $providetype ) );
            $coins = $bytes->integerToBytes ( intval ( $coins ) );
            
            $return_betys = array_merge ($headType , $headLength , $serialno , $zoneid , $openid,$payitem_len ,$payitem,$billno,$providetype,$coins);
            
            $msg = $bytes->toStr ($return_betys);
            $strLen = strlen($msg);

            $packet = pack("a{$strLen}", $msg);
            $pckLen = strlen($packet);
            
            $socket = Socket::singleton ();
            $socket->connect ( $socketAddr, $socketPort ); //连server            
            $sockResult = $socket->sendRequest ( $packet); // 将包发送给server 

            sleep ( 3 );
            $socket->disconnect (); //关闭链接

        } catch ( Exception $e ) {
            var_dump($e);
            $this->log_error("pay order send to server".$e->getMessage());
        }
    }
技术分享

以上是关于Php socket数据编码的主要内容,如果未能解决你的问题,请参考以下文章

超级有用的9个PHP代码片段

比较有用的php代码片段

Laravel基本使用

markdown 打字稿...编码说明,提示,作弊,指南,代码片段和教程文章

PHP必用代码片段

PHP代码-psysh调试代码片段工具