很就没更新博客了。今天更新一篇文章,今天要讲的是TLV格式和TLV在PHP5中的应用。
讲到TLV格式可能很多人都没有听说过吧。不过不要紧,今天我们就一直来了解它。
TLV是一种可变格式,主要用到在客服端与服务端之间的数据发送。说道其本质是是客服端向服务段数据传输双方规定的一个协议。
TLV中T、L字段的长度往往固定(通常为1~4bytes),V字段长度可变。顾名思义,T字段表示数值类型,L字段表示数值长度、V字段往往用来存放数值。
T:Tag标识,用于标识该数据元,类似于数组中的key
L:Length长度,TLV中Value的长度
V:Value数据本身,其中Value本身也可以包含TLV
接下来我们以PHP形式的方式来讲解TLV,在PHP中TLV其表现形式可以用数组来表示,如下:
<?php
$tag = 0x103
$value = “Test TLV”;
$ret = array($tag,strlen($value),$value);
print_r($ret);
在这段代码中数据ret就是TLV在PHP中的表示。其中strlen($value)为TLV中的Length(T),其中需要注意的是$tag和length必须为int类型。当然这段代码并不完整。以下代码段是对TLV进行了处理的TLV。
<?php
/**
TLV包解析类
*/
class Tlv {
private $buffer;
private $t_len = 4; //T长度
private $l_len = 4; //L长度
private $buf_len =0; //字节流长度
private $buf_array = array();
/**
* 构造函数
*/
function __construct(){}
/**
* 解析数据
*
* @param byte $buffer 二进制流数据
* @param $IsArray
* @return array
*/
function Read($buffer,$IsArray=false){
$this->buffer = $buffer;
$this->buf_len = strlen($this->buffer);
$isMore = false;
$tmp_array = array();
$tmp_key = "";
//清空数组
if(isset($this->buf_array)){
unset($this->buf_array);
$this->buf_array = array();
}
$i=0;
while($i<$this->buf_len){
//获取TGA
$t = $this->getLength($i,$this->t_len);
if($this->toHex($t) == "0xffffffff") break;
$i += $this->t_len;
//获取Length
$l = $this->getLength($i,$this->l_len);
$i += $this->l_len;
//获取Value
$v = substr($this->buffer,$i,$l);
$i += $l;
if($IsArray){
$this->buf_array[$this->toHex($t)] =array($this->toHex($t),$l,$v);
}else{
array_push($this->buf_array,array($this->toHex($t),$l,$v));
}
}
return $this->buf_array;
}
//将数组转换二进制数据
function Write($arrdata){
$i = 0;
$msg = null;
while($i<count($arrdata)){
$msg .= $this->Pack("N*",$arrdata[$i][0]);
$msg .= $this->Pack("N*",$arrdata[$i][1]);
$msg .= $arrdata[$i][2];
$i += 1;
}
return $msg;
}
//获取值
function getValue($key){
return $this->buf_array[$key][2];
}
//转换成十六进制
function toHex($value){
return "0x".dechex($value);
}
//压包
function Pack($format,$data){
return pack($format,$data);
}
//解包
function Unpack($format,$data){
$ret = unpack($format,$data);
return $ret[1];
}
//清楚所有数据
function Clear(){
if(isset($this->buffer)){
unset($this->buffer);
}
$this->buf_len = 0;
}
}
<?php
/**
客户端上行包
*/
class Packet_0x103 extends Tlv {
function GetPack(){
$tag = 0x103
$value = Tlv::Write(“Test TLV”);
$ret = array($tag,strlen($value),$value);
return Tlv::Write($ret);
}
function Clear(){
if(isset($this->Pack_arry)){
unset($this->Pack_arry);
}
}
}
<?php
/**
客户端上行发送数据
*/
require("Tlv.class.php");
require("Packet.0x103.php");
$Packet = new Packet_0x103();
$data = $Packet->GetPack();
$Packet->Clear();
$conn = fsockopen("192.168.87.1",80,$errno,$errstr,1);//发送到服务端的地址和端口号
if(!$conn) die($errstr)."<br/>";//加上连接是否有效判断,就不会一直刷了
fwrite($conn,"POST /www.test.com/htdocs/All.php HTTP/1.1\r\n");//实际上就是将数据POST 到http://localhost:80/index.php
fwrite($conn,"Host:192.168.87.1\r\n");
fwrite($conn,"Connection:close\r\n");//这里加上会快一些。
fwrite($conn,"Content-length:".strlen($data)."\r\n\r\n");
fwrite($conn,$data);
while(!feof($conn))
{
$content .= fgets($conn,128);
}
fclose($conn);
echo $content;
<?php
/**
接收从数据端发送过来的数据包
*/
header('content-type:text/html;charset="utf-8"');
//获取从客户端POST来的字节流
$Stream =file_get_contents("php://input");
$tlv = new TLV();
$data = $tlv->Read($Stream);
echo $data;
?>