PHP TCP服务端监听端口接收客户端RFID网络读卡器上传的读卡数据

本示例使用设备:WIFI/TCP/UDP/HTTP协议RFID液显网络读卡器可二次开发语音播报POE-淘宝网 (taobao.com)

php 复制代码
<?php
header("content-type:text/html;charset=GBK");

set_time_limit(0);
$port=39169;    //监听端口

if(($socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === FALSE){
    echo '初始化socket失败: ' . socket_strerror(socket_last_error($socket));
    exit;
}

socket_set_nonblock($socket);

// socket_bind(): 将socket资源绑定到指定地址
if(!socket_bind($socket, '0.0.0.0', $port)){
    echo '绑定端口失败: ' . socket_strerror(socket_last_error($socket));
    exit;
}

// socket_listen(): 监听socket的连接请求
if(!socket_listen($socket)){
    echo '监听端口: ' . socket_strerror(socket_last_error($socket));
    exit;
}else{echo "TCP服务已启动,正在侦听端口:".$port."\n";}

while(1){
    if(($client = socket_accept($socket)) !== FALSE){
        while(1){
            //这里不循环的话,只能接收到一次消息
            $content = socket_read($client, 10240);
            $content = trim($content);

            if($content){
                $response = AnalyzeData($content); //解析接收到的数据,并生成回应数据
                socket_write($client, $response);

                $Sendinf='';                    //将发送的信息用16进制数显示,方便调式
                for($i=0;$i<strlen($response);$i++){
                    $byte = ord($response[$i]);
                    $b=substr('00'.dechex($byte ),-2);
                    $Sendinf=$Sendinf.$b.' ';
                }
                echo "发送数据:".$Sendinf."\n\n";
            }
        }
    }
}
socket_close($socket);

//解析接收到的数据,并根据情况生成不同的回应数据
function AnalyzeData($inMsg)
{
    $len = strlen($inMsg);
    $bytes = array();
    $Getinf='';
    for($i=0;$i<$len;$i++)
    {
        $byte = ord($inMsg[$i]);
        $bytes[] =  $byte ;

        $b=substr('00'.dechex($byte ),-2);
        $Getinf=$Getinf.$b.' ';
    }
    echo "接收数据:".$Getinf. PHP_EOL;

    switch($bytes[0]){
        case hexdec('0xF3'):        //接收到设备的心跳数据包,设备心跳间隔可根据协议自行设置
            $Ipaddstr=$bytes[1].".".$bytes[2].".".$bytes[3] .".".$bytes[4] ;
            $Machine=($bytes[5]+$bytes[6]*256) ;
            $frame=($bytes[7]+$bytes[8]*256) ;
            $Heartbeattype=substr('00'.dechex($bytes[9]),-2);
            $heartlen=$bytes[10];
            $switch=substr('00'.dechex($bytes[11]),-2);
            $keyinput=substr('00'.dechex($bytes[12]),-2);
            $Randcode=substr('00'.dechex($bytes[13]),-2).substr('00'.dechex($bytes[14]),-2).substr('00'.dechex($bytes[15]),-2).substr('00'.dechex($bytes[16]),-2);
            $SerialNum="";
            for($i=17;$i<sizeof($bytes);$i++){
                $SerialNum=$SerialNum.substr('00'.dechex($bytes[$i]),-2);
            }
            $Dispinf="数据解析:设备心跳包,设备IP:".$Ipaddstr.",机号:".$Machine.",数据包序号:".$frame.",心跳类型:".$Heartbeattype.",长度:".$heartlen.",继电器状态:".$switch.",按键值:".$keyinput.",随机码:".$Randcode.",硬件序列号:".$SerialNum;
            echo $Dispinf."\n\n";
            break;
        case hexdec('0xC1') or hexdec('0xCF') :     //接收IC读卡器上传的读卡号数据、IC卡离开读卡器的信息
            if($bytes[0]==hexdec('0xC1')){
                $Dispinf="数据解析:IC读卡器读取卡号,";
            }else{$Dispinf="数据解析:IC卡离开读卡器,";}

            $Ipaddstr=$bytes[1].".".$bytes[2].".".$bytes[3] .".".$bytes[4] ;
            $Machine=($bytes[5]+$bytes[6]*256) ;
            $frame=($bytes[7]+$bytes[8]*256) ;
            $Cardlen=$bytes[9];
            $Card16H="";
            for($i=0;$i<$Cardlen;$i++)
            {
                $Card16H=$Card16H.substr('00'.dechex($bytes[10+$i]),-2);
            }
            $CardNo=$bytes[10] & 0xff;
            $CardNo=$CardNo+($bytes[11] & 0xff) *256;
            $CardNo=$CardNo+($bytes[12] & 0xff) *65536;
            $CardNo=$CardNo+($bytes[13] & 0xff) *16777216;
            $CardNo=substr("0000000000".$CardNo,-10);
            $SerialNum ="";
            for($i=10+$Cardlen;$i<$len;$i++){
                $SerialNum=$SerialNum.substr('00'.dechex($bytes[$i]),-2);
            }
            $Dispinf=$Dispinf."设备IP:".$Ipaddstr.",机号:".$Machine.",数据包序号:".$frame.",卡号长度:".$Cardlen.",16进制卡号:".$Card16H.",转十进制卡号:".$CardNo.",硬件序列号:".$SerialNum;
            echo $Dispinf."\n\n";

            //此处加入业务对数据库的查、增、删、减等操作

            $DispStr="卡号:".$CardNo."  ".substr(date('Y-m-d h:i:s', time()),0,16)."            "; //全屏显示信息长度>=34
            return GetResponseData(4,$DispStr); //生成回应数据

            break;
        case hexdec('0xD1') or hexdec('0xDF') :     //接收ID读卡器上传的读卡号数据、ID卡离开读卡器的信息
            if($bytes[0]==hexdec('0xD1')){
                $Dispinf="数据解析:ID读卡器读取卡号,";
            }else{$Dispinf="数据解析:ID卡离开读卡器,";}

            $Ipaddstr=$bytes[1].".".$bytes[2].".".$bytes[3] .".".$bytes[4] ;
            $Machine=($bytes[5]+$bytes[6]*256) ;
            $frame=($bytes[7]+$bytes[8]*256) ;
            $Card16H="";
            for($i=9;$i<14;$i++)
            {
                $Card16H=$Card16H.substr('00'.dechex($bytes[10+$i]),-2);
            }
            $CardNo=$bytes[9] & 0xff;
            $CardNo=$CardNo+($bytes[10] & 0xff) *256;
            $CardNo=$CardNo+($bytes[11] & 0xff) *65536;
            $CardNo=$CardNo+($bytes[12] & 0xff) *16777216;
            $CardNo=substr("0000000000".$CardNo,-10);
            $SerialNum ="";
            for($i=14;$i<$len;$i++){
                $SerialNum=$SerialNum.substr('00'.dechex($bytes[$i]),-2);
            }
            $Dispinf=$Dispinf."设备IP:".$Ipaddstr.",机号:".$Machine.",数据包序号:".$frame.",16进制卡号:".$Card16H.",转十进制卡号:".$CardNo.",硬件序列号:".$SerialNum;
            echo $Dispinf."\n\n";

            //此处加入业务对数据库的查、增、删、减等操作

            $DispStr="卡号:".$CardNo."  ".substr(date('Y-m-d h:i:s', time()),0,16)."            "; //全屏显示信息长度>=34
            return GetResponseData(4,$DispStr); //生成回应数据

            break;
        default:
    }
}

//根据情况生成不同的回应数据
function GetResponseData($respcode,$DispStr)
{
    $sdata = array();
    switch($respcode){
        case 0:     //回只应蜂鸣响声
            $sdata[0] = hexdec('0x96');    //指令码
            $sdata[1] = 0;                          //机号低位,
            $sdata[2] = 0;                          //机号高位,高低位都为0表示任意机号
            $sdata[3] = 1;                          //蜂鸣响声代码,取值范围0-12,代表12种不同的蜂鸣响声
            $sendBuf = '';
            for ($i = 0; $i < 4; $i++) {
                $sendBuf = $sendBuf . chr($sdata[$i]);
            }
            return $sendBuf;
            break;
        case 1:     //回应只开启继电器
            $sdata[0] = hexdec('0x78');    //指令码
            $sdata[1] = 0;                          //机号低位,
            $sdata[2] = 0;                          //机号高位,高低位都为0表示任意机号
            $sdata[3] = hexdec('0xF0');    //继电器代码 F0表示全部继电器、F1表示1号继电器 、F2表示2号继电器、F3表示3号继电器......
            $sdata[4] = hexdec('0x2C');    //继电器开启延时低位16进制
            $sdata[5] = hexdec('0x01');    //继电器开启延时高位16进制,高低位取值FFFF表示继电器一直开启
            $sendBuf = '';
            for ($i = 0; $i < 6; $i++) {
                $sendBuf = $sendBuf . chr($sdata[$i]);
            }
            return $sendBuf;
            break;
        case 2:     //回应只关闭已开启的继电器
            $sdata[0] = hexdec('0x78');    //指令码
            $sdata[1] = 0;                          //机号低位,
            $sdata[2] = 0;                          //机号高位,高低位都为0表示任意机号
            $sdata[3] = hexdec('0xE0');    //继电器代码 E0表示全部继电器、E1表示1号继电器 、E2表示2号继电器、E3表示3号继电器......
            $sdata[4] = hexdec('0x2C');    //继电器关闭延时低位16进制
            $sdata[5] = hexdec('0x01');    //继电器关闭延时高位16进制,高低位取值FFFF表示继电器一直关闭
            $sendBuf = '';
            for ($i = 0; $i < 6; $i++) {
                $sendBuf = $sendBuf . chr($sdata[$i]);
            }
            return $sendBuf;
            break;
        case 3:     //回应蜂鸣响声+文字显示
            $sdata[0]=hexdec('0x5A');    //指令码
            $sdata[1]=0;                          //机号低位
            $sdata[2]=0;                          //机号高位,高低位都为0表示任意机号
            $sdata[3]=2;                          //蜂鸣声代码,取值范围0-12,代表12种不同的蜂鸣响声
            $sdata[4]=20;                         //显示时长,单位秒,取值范围0-255,取值255时表示永久显示
            $sendBuf='';
            for($i=0;$i<5;$i++)
            {
                $sendBuf=$sendBuf.chr($sdata[$i]);
            }
            $sendBuf=$sendBuf.$DispStr;
            return $sendBuf;
            break;
        case 4:     //回应蜂鸣响声+继电器开关+文字显示+播报TTS语音
            $SpeakStr="[v10]";                    //[v10]是语音大小,取值范围0-16,可加在任何地方,其他语音策略请看文档说明
            $SpeakStr=$SpeakStr."刷卡成功,感谢您使用我们的网络读卡器!";//要播报的TTS语音,每条指令最大不能超过126字符
            $Splen = strlen($SpeakStr);           //TTS语音长度
            //
            $sdata[0]=hexdec('0x5C');    //指令码
            $sdata[1]=0;                          //机号低位
            $sdata[2]=0;                          //机号高位,高低位都为0表示任意机号
            $sdata[3]=2;                          //蜂鸣声代码,取值范围0-12,代表12种不同的蜂鸣响声
            $sdata[4]=hexdec('0xF0');    //继电器代码 F0表示全部继电器 F1表示1号继电器 F2表示2号继电器

            $sdata[5]=hexdec('0x2C');    //继电器开启时长低位
            $sdata[6]=hexdec('0x01');    //继电器开启时长高位

            $sdata[7]=hexdec('0x14');    //显示保留时间,单位为秒,为0xFF时表示永久显示
            $sdata[8]=0;                          //在显示屏中的哪个位置开始
            $sdata[9]=hexdec('0x22');    //显示字符串长度 为全屏显示为 34 个字符
            $sdata[10]=$Splen;                    //语音长度

            $suffixStr=chr(hexdec('0x55')).chr(hexdec('0xaa')).chr(hexdec('0x66')).chr(hexdec('0x99'));  //固定的抗干扰后缀

            $sendBuf='';
            for($i=0;$i<11;$i++)
            {
                $sendBuf=$sendBuf.chr($sdata[$i]);
            }
            $sendBuf=$sendBuf.substr($DispStr,0,34).$SpeakStr.$suffixStr;   //最长显示34个字符

            return $sendBuf;
            break;
        default:
    }
}

//获取本机IP地址------------------------------------------------------------------------------------------------------------------------
function get_local_ip()
{
    $preg = "/\A((([0-9]?[0-9])|(1[0-9]{2})|(2[0-4][0-9])|(25[0-5]))\.){3}(([0-9]?[0-9])|(1[0-9]{2})|(2[0-4][0-9])|(25[0-5]))\Z/";
    //获取操作系统为win2000/xp、win7的本机IP真实地址
    $Netdriv=array();
    exec("ipconfig", $out, $stats);
    if (!empty($out)) {
        foreach ($out AS $row) {
            if (strstr($row, "IP") && strstr($row, ":") && !strstr($row, "IPv6")) {
                $tmpIp = explode(":", $row);
                if (preg_match($preg, trim($tmpIp[1]))) {
                    $Netdriv[]=trim($tmpIp[1]);
                    echo trim($tmpIp[1])."\n";
                }
            }
        }
    }
    //获取操作系统为linux类型的本机IP真实地址
    //exec("ifconfig", $out, $stats);
    //if (!empty($out)) {
    //    if (isset($out[1]) && strstr($out[1], 'addr:')) {
    //        $tmpArray = explode(":", $out[1]);
    //        $tmpIp = explode("", $tmpArray[1]);
    //        if (preg_match($preg, trim($tmpIp[0]))) {
    //            return trim($tmpIp[0]);
    //        }
    //    }
    //}
    if (!empty($Netdriv)) {
        return $Netdriv[0];   //如果有多张网块,可以修改数组取值来绑定相应的网卡
    }else{
        return '127.0.0.1';
    }
}

?>
相关推荐
JaguarJack18 小时前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
后端·php·服务端
BingoGo18 小时前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
php
JaguarJack2 天前
告别 Laravel 缓慢的 Blade!Livewire Blaze 来了,为你的 Laravel 性能提速
后端·php·laravel
郑州光合科技余经理2 天前
代码展示:PHP搭建海外版外卖系统源码解析
java·开发语言·前端·后端·系统架构·uni-app·php
QQ5110082852 天前
python+springboot+django/flask的校园资料分享系统
spring boot·python·django·flask·node.js·php
WeiXin_DZbishe2 天前
基于django在线音乐数据采集的设计与实现-计算机毕设 附源码 22647
javascript·spring boot·mysql·django·node.js·php·html5
longxiangam3 天前
Composer 私有仓库搭建
php·composer
上海云盾-高防顾问3 天前
DNS异常怎么办?快速排查+解决指南
开发语言·php
ShoreKiten3 天前
关于解决本地部署sqli-labs无法安装低版本php环境问题
开发语言·php
liliangcsdn3 天前
深入探索TD3算法的推理过程
开发语言·php