项目需要使用websocket推送最新订单,客户服务器非linux不支持swoole,因此使用原生,直接上代码
(1).PHP服务端
<?php ini_set('error_reporting', E_ALL ^ E_NOTICE); ini_set('display_errors', 1); set_time_limit(0); $address = '127.0.0.1'; $port = 6936; //01.创建一个套接字(参数1是支持ipv4的TCP/UDP,参数2是套接字使用的类型,参数3是domain下具体协议) $sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP) or die('Create Socket Failed'); //02.设置socket的参数(参数1是资源句柄,参数2是ip地址,参数3是挂起本脚本的端口) socket_bind($sock, $address, $port) or die('Could not bind to address'); //03.开始监听来自本端口的所有连接 socket_listen($sock); //04.设置为非阻塞 socket_set_nonblock($sock); //05.保存所有的客户端state记录是否握手,shopid记录店铺id /* array( array('client'=>$sock1,'state'=>0,'shopid'=>0), array('client'=>$sock2,'state'=>0,'shopid'=>1), ) */ $client = array(); //06.while挂起进程来处理webscoket while (true) { //检测到新client,加入client组,并记录是否握手 if ($newsock = @socket_accept($sock)) { if (is_resource($newsock)) { //给新检测到的client回应 socket_write($newsock, "", 2) . chr(0); //并且将其加入client队伍中 array_push($client,array('client'=>$newsock,'state'=>0)); } } if (count($client)) { foreach ($client AS $k => $v) { //是否获取到数据 if (@socket_recv($v['client'], $string, 1024, 0) === 0) { unset($client[$k]); socket_close($v['client']); } else { //已经握手可以直接发送消息 if ($v['state'] == 1) { //握手完成的第一次,可以直接拿到client发送来的完整数据 if($string!=''){ $clientmsg=unmask($string); echo $clientmsg;//这就是client发送来的数据 } $data = array('12345', '上山打老虎','客户端的小妹妹你好'); $data = json_encode($data); $data = mask($data); @socket_write($v['client'], $data, strlen($data)); } //未握手先完成握手 else { doHandShake($v['client'], $string); $client[$k]['state']=1; } } } } sleep(1); } //握手方法 function doHandShake($socket, $buffer) { list($resource, $host, $origin, $key) = getHeaders($buffer); $upgrade = "HTTP/1.1 101 Switching Protocol\r\n" . "Upgrade: websocket\r\n" . "Connection: Upgrade\r\n" . "Sec-WebSocket-Accept: " . calcKey($key) . "\r\n\r\n"; //必须以两个回车结尾 socket_write($socket, $upgrade, strlen($upgrade)); } //获取请求头 function getHeaders($buffer) { $r = $h = $o = $key = null; if (preg_match("/GET (.*) HTTP/", $buffer, $match)) { $r = $match[1]; } if (preg_match("/Host: (.*)\r\n/", $buffer, $match)) { $h = $match[1]; } if (preg_match("/Origin: (.*)\r\n/", $buffer, $match)) { $o = $match[1]; } if (preg_match("/Sec-WebSocket-Key: (.*)\r\n/", $buffer, $match)) { $key = $match[1]; } return [$r, $h, $o, $key]; } //验证socket function calcKey($key) { $accept = base64_encode(sha1($key . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true)); return $accept; } //解码数据(解析client发送的数据) function unmask($text) { $length = ord($text[1]) & 127; if ($length == 126) { $masks = substr($text, 4, 4); $data = substr($text, 8); } elseif ($length == 127) { $masks = substr($text, 10, 4); $data = substr($text, 14); } else { $masks = substr($text, 2, 4); $data = substr($text, 6); } $text = ""; for ($i = 0; $i < strlen($data); ++$i) { $text .= $data[$i] ^ $masks[$i % 4]; } return $text; } //编码数据(编码向client发送的数据) function mask($text) { $b1 = 0x80 | (0x1 & 0x0f); $length = strlen($text); if ($length <= 125) $header = pack('CC', $b1, $length); elseif ($length > 125 && $length < 65536) $header = pack('CCn', $b1, 126, $length); elseif ($length >= 65536) $header = pack('CCNN', $b1, 127, $length); return $header . $text; } socket_close($sock); ?>
(2).Javascript客户端
<script type="text/javascript"> if("WebSocket" in window) { var ws = new WebSocket("ws://127.0.0.1:6936"); //socket握手自动触发推送消息 ws.onopen = function() { var data = { id: 287, name: '某终端' } data = JSON.stringify(data); ws.send(data); }; //监听来自服务端的消息 ws.onmessage = function(evt) { console.log(evt.data); }; //客户端或服务端断开自动触发 ws.onclose = function() { console.log('websocket已经断开!'); }; } else { console.log('您的浏览器不支持h5,无法启动websocket'); } </script>
项目中使用服务来执行webservice,由于对方系统api不稳定,经常导致服务崩溃,只能重启,一个月差不多要重启一次。初期的解决办法是捕获异常,然后continue掉。<?php try { $url = 'http...
(1).config.php 配置文件<?php /** * RabbitMQ_Config */ $config = [ 'host' => ...
文章篇幅较长,如果不喜欢看文章的,此处抛出韩顺丰老师的位运算视频,韩老师应该是全网讲php位运算符最详细的一个老师了。链接:https://pan.baidu.com/s/14xj7er8eVSUcJ-jYXyA0GA 提取码:731m 链接:https://pan.baidu.com...
本教程使用的定时任务基于EasyTak,EasyTask官方文档:https://gitee.com/392223903/EasyTask由于tp3.2.x官方开发未考虑命令行支持和绝对路径开发的标准,因此我编写了一个支持的类来运行。1.在tp3.2.3根目录下安装easytaskcomposer&...
//设置客户端断开依然运行 ignore_user_abort(true); //设置脚本不超时 set_time_limit(0); //死循环每隔1秒访问一次网址 while (true) { sleep(1); &nb...
本教程使用的定时任务基于EasyTak,EasyTask官方文档:https://gitee.com/392223903/EasyTask(1).安装tp6composer create-project topthink/think tp(2).安装定时任务compos...