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';
    }
}

?>
相关推荐
两个人的幸福9 天前
Windows 桌面应用自研 PHP 队列(下):完整代码与六大工程化优化
php
BingoGo11 天前
PHP 泛型之殇 泛型 RFC 提案被拒绝
后端·php
JaguarJack11 天前
PHP 泛型之殇 泛型 RFC 提案被拒绝
后端·php
用户30745969820712 天前
PHP 扩展——从入门到理解
php
鹏仔先生12 天前
拷贝漫画APP下载页PHP程序,后台带免费AI写作
php
云水一下13 天前
从零开始学 PHP 系列(一):PHP 的前世今生与开发环境搭建
开发语言·php
xingpanvip13 天前
星盘接口开发文档:本命盘接口指南
android·开发语言·css·php·lua
酉鬼女又兒13 天前
零基础入门计算机网络运输层:端到端通信核心作用、端口号分类规则、复用分用工作机制及UDP与TCP协议全方位对比详解
网络·网络协议·tcp/ip·计算机网络·考研·udp·php
dog25013 天前
不要再继续优化 TCP
网络协议·tcp/ip·php
Channing Lewis13 天前
PHP 解析 Excel 的那些坑:一次“行号错位”引发的数据丢失
开发语言·php·excel