php实现socket推送技术的示例


Posted in PHP onDecember 20, 2017

在socket出现之前已经有ajax定时请求、长轮询等方案,但都不能满足需求,socket就应用而生了。

socket基本函数socket

总结下常用的socket函数

服务端: socket_create 创建socket设置基本参数

socket_bind 绑定ip和端口号

socket_listen 监听

socket_accept 客户端的连接

socket_read 读取客户端的数据

socket_write 给单独客户端发送数据

socket_close 关闭连接

客户端:socket_create 创建socket设置基本参数

socket_connect 连接socket

socket_write 给服务端发送数据

socket_read 读取服务端数据

socket_close 关闭连接

H5websocket不多说了,上链接

OK,开始贴代码~

----------------------------------------------------------分割线

服务端代码:

<?php
class WS {
 var $master;
 var $sockets = array();
 var $debug = false;//true为调试模式,输出log日志
 var $handshake = array();
 function __construct($address, $port){
 $this->master=socket_create(AF_INET, SOCK_STREAM, SOL_TCP) or die("socket_create() failed");
 socket_set_option($this->master, SOL_SOCKET, SO_REUSEADDR, 1) or die("socket_option() failed");
 socket_bind($this->master, $address, $port)  or die("socket_bind() failed");
 socket_listen($this->master,20)  or die("socket_listen() failed");
 
 $this->sockets[] = $this->master;
 $this->say("Server Started : ".date('Y-m-d H:i:s'));
 $this->say("Listening on : ".$address." port ".$port);
 $this->say("Master socket : ".$this->master."\n");
 
 while(true){
 $socketArr = $this->sockets;
 $write = NULL;
 $except = NULL;
 socket_select($socketArr, $write, $except, NULL); //自动选择来消息的socket 如果是握手 自动选择主机
 foreach ($socketArr as $socket){
 if ($socket == $this->master){ //主机
  $client = socket_accept($this->master);
  if ($client < 0){
  $this->log("socket_accept() failed");
  continue;
  } else{
  $this->connect($client);
  }
 } else {
  $bytes = @socket_recv($socket,$buffer,2048,0);
  if ($bytes == 0){
  $this->disConnect($socket);
  }
  else{
  $key = array_search($socket, $this->sockets);
  if (empty($this->handshake) || !isset($this->handshake[$key]) || !$this->handshake[$key]){
  $this->doHandShake($socket, $buffer, $key);
  }
  else{
  $buffer = $this->decode($buffer);
  echo $buffer.PHP_EOL;
  $key = array_search($socket, $this->sockets);
  $arr = $this->sockets;
  array_shift($arr);
  foreach ($arr as $s){
  $this->send($s, $buffer);
  }
  }
  }
 }
 }
 }
 }
 
 function send($client, $msg){
 $msg = $this->frame($msg);
 socket_write($client, $msg, strlen($msg));
 }
 function connect($socket){
 array_push($this->sockets, $socket);
 $this->say("\n" . $socket . " CONNECTED!");
 $this->say(date("Y-n-d H:i:s"));
 }
 function disConnect($socket){
 $index = array_search($socket, $this->sockets);
 socket_close($socket);
 $this->say($socket . " DISCONNECTED!");
 if ($index >= 0){
 echo 'unset index is:'.PHP_EOL;
 unset($this->sockets[$index]);
 }
 }
 function doHandShake($socket, $buffer, $handKey){
 $this->log("\nRequesting handshake...");
 $this->log($buffer);
 list($resource, $host, $origin, $key) = $this->getHeaders($buffer);
 $this->log("Handshaking...");
 $upgrade = "HTTP/1.1 101 Switching Protocol\r\n" .
  "Upgrade: websocket\r\n" .
  "Connection: Upgrade\r\n" .
  "Sec-WebSocket-Accept: " . $this->calcKey($key) . "\r\n\r\n"; //必须以两个回车结尾
 $this->log($upgrade);
 $sent = socket_write($socket, $upgrade, strlen($upgrade));
 $this->handshake[$handKey]=true;
 $this->log("Done handshaking...");
 return true;
 }
 function getHeaders($req){
 $r = $h = $o = $key = null;
 if (preg_match("/GET (.*) HTTP/" ,$req,$match)) { $r = $match[1]; }
 if (preg_match("/Host: (.*)\r\n/" ,$req,$match)) { $h = $match[1]; }
 if (preg_match("/Origin: (.*)\r\n/" ,$req,$match)) { $o = $match[1]; }
 if (preg_match("/Sec-WebSocket-Key: (.*)\r\n/",$req,$match)) { $key = $match[1]; }
 return array($r, $h, $o, $key);
 }
 function calcKey($key){
 //基于websocket version 13
 $accept = base64_encode(sha1($key . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true));
 return $accept;
 }
 function decode($buffer) {
 $len = $masks = $data = $decoded = null;
 $len = ord($buffer[1]) & 127;
 if ($len === 126) {
 $masks = substr($buffer, 4, 4);
 $data = substr($buffer, 8);
 } 
 else if ($len === 127) {
 $masks = substr($buffer, 10, 4);
 $data = substr($buffer, 14);
 } 
 else {
 $masks = substr($buffer, 2, 4);
 $data = substr($buffer, 6);
 }
 for ($index = 0; $index < strlen($data); $index++) {
 $decoded .= $data[$index] ^ $masks[$index % 4];
 }
 return $decoded;
 }
 function frame($s){
 $a = str_split($s, 125);
 if (count($a) == 1){
 return "\x81" . chr(strlen($a[0])) . $a[0];
 }
 $ns = "";
 foreach ($a as $o){
 $ns .= "\x81" . chr(strlen($o)) . $o;
 }
 return $ns;
 }
 
 function say($msg = ""){
 echo $msg . "\n";
 }
 function log($msg = ""){
 if ($this->debug){
 echo $msg . "\n";
 } 
 }
}
 
new WS('localhost', 4000);

客户端代码(H5):

<html>
 <head>
 <title>demo</title>
 <script src="https://cdn.bootcss.com/jquery/1.9.1/jquery.min.js"></script>
 </head>
 <body>
 <input type="text" id="content">
 <input type="button" value="send" id="send">
 <script type="text/javascript">
  var ws = new WebSocket("ws://localhost:4000");
  ws.onopen = function(){
  console.log("握手成功");
  }
  ws.onmessage = function(e){
  console.log("message:" + e.data);
  }
  ws.onerror = function(){
  console.log("error");
  }
  $("#send").click(function(){
  content = $("#content").val();
  console.log(content);
  ws.send(content);
  })
 </script>
 </body>
</html>

然后执行php demo.php 开启socket(从运维那偷学一招,linux下执行nohup php demo.php &可以在后台执行),浏览器打开多个index.html,就能建立通讯了。

代码解析:

1.属性$sockets数组保存每个accept连接(不知道这么描述对不对);

2.属性$handshake数组保存连接是否在连接状态;

以上这篇php实现socket推送技术的示例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
PHP新手上路(十四)
Oct 09 PHP
PHP goto语句简介和使用实例
Mar 11 PHP
php多功能图片处理类分享(php图片缩放类)
Mar 14 PHP
PHP中的use关键字概述
Jul 23 PHP
PHP递归复制、移动目录的自定义函数分享
Nov 18 PHP
php实现基于微信公众平台开发SDK(demo)扩展的方法
Dec 22 PHP
Zend Framework教程之Bootstrap类用法概述
Mar 14 PHP
php base64 编码与解码实例代码
Mar 21 PHP
PHP+AjaxForm异步带进度条上传文件实例代码
Aug 14 PHP
CI框架教程之优化验证码机制详解【验证码辅助函数】
Apr 16 PHP
Yii框架的路由配置方法分析
Sep 09 PHP
PHP单元测试配置与使用方法详解
Dec 27 PHP
PHP实现模拟http请求的方法分析
Dec 20 #PHP
php封装db类连接sqlite3数据库的方法实例
Dec 19 #PHP
PHP性能分析工具xhprof的安装使用与注意事项
Dec 19 #PHP
PHP实现的最大正向匹配算法示例
Dec 19 #PHP
PHP实现的字符串匹配算法示例【sunday算法】
Dec 19 #PHP
PHP实现的折半查找算法示例
Dec 19 #PHP
PHP实现的二分查找算法实例分析
Dec 19 #PHP
You might like
php zend 相对路径问题
2009/01/12 PHP
php运行出现Call to undefined function curl_init()的解决方法
2010/11/02 PHP
php入门学习知识点五 关于php数组的几个基本操作
2011/07/14 PHP
PHP按行读取、处理较大CSV文件的代码实例
2014/04/09 PHP
Ubuntu中搭建Nginx、PHP环境最简单的方法
2015/03/05 PHP
Prototype Selector对象学习
2009/07/23 Javascript
javascript中关于break,continue的特殊用法与介绍
2012/05/24 Javascript
JS随即打乱数组实现代码
2012/12/03 Javascript
js 调用本地exe的例子(支持IE内核的浏览器)
2012/12/26 Javascript
Node.js模拟浏览器文件上传示例
2014/03/26 Javascript
jQuery动画效果animate和scrollTop结合使用实例
2014/04/02 Javascript
JavaScript每天定时更换皮肤样式的方法
2015/07/01 Javascript
基于jQuery实现文本框只能输入数字(小数、整数)
2016/01/14 Javascript
AngularJS实现动态编译添加到dom中的方法
2016/11/04 Javascript
js实现自动图片轮播代码
2017/03/22 Javascript
ztree简介_动力节点Java学院整理
2017/07/19 Javascript
vue根据条件不同显示不同按钮的操作
2020/08/04 Javascript
Python计算三角函数之asin()方法的使用
2015/05/15 Python
Python中实例化class的执行顺序示例详解
2018/10/14 Python
python使用rsa非对称加密过程解析
2019/12/28 Python
Python3查找列表中重复元素的个数的3种方法详解
2020/02/13 Python
实现Python3数组旋转的3种算法实例
2020/09/16 Python
HTML5表格_动力节点Java学院整理
2017/07/11 HTML / CSS
html5启动原生APP总结
2020/07/03 HTML / CSS
欧洲最大的笔和书写专家:The Pen Shop
2017/03/19 全球购物
TIME时代杂志台湾总代理:台时亚洲
2018/10/22 全球购物
Wiggle新西兰:自行车、跑步、游泳
2020/05/06 全球购物
西安当代医院管理研究院笔试题
2015/12/11 面试题
中医专业应届生求职信
2013/11/17 职场文书
自荐书格式
2013/12/01 职场文书
运动会演讲稿100字
2014/08/25 职场文书
2015年元旦文艺晚会总结(学院)
2014/11/28 职场文书
法律意见书范文
2015/06/04 职场文书
《童年》读后感(三篇)
2019/08/27 职场文书
python读取mnist数据集方法案例详解
2021/09/04 Python
Python3.8官网文档之类的基础语法阅读
2021/09/04 Python