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 相关文章推荐
DEDE采集大师官方留后门的删除办法
Jan 08 PHP
php缩小png图片不损失透明色的解决方法
Dec 25 PHP
PHP统计nginx访问日志中的搜索引擎抓取404链接页面路径
Jun 30 PHP
php天翼开放平台短信发送接口实现方法
Dec 22 PHP
基于PHP实现的事件机制实例分析
Jun 18 PHP
CentOS下搭建PHP环境与WordPress博客程序的全流程总结
May 07 PHP
PHP购物车类Cart.class.php定义与用法示例
Jul 20 PHP
PHPStrom 新建FTP项目以及在线操作教程
Oct 16 PHP
php提交表单时保留多个空格及换行的文本样式的方法
Jun 20 PHP
php使用flock阻塞写入文件和非阻塞写入文件的实例讲解
Jul 10 PHP
使用composer 安装 laravel框架的方法图文详解
Aug 02 PHP
Laravel基础_关于view共享数据的示例讲解
Oct 14 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
3
2006/10/09 PHP
php iconv() : Detected an illegal character in input string
2010/12/05 PHP
PHP中通过trigger_error触发PHP错误示例
2015/06/23 PHP
php利用递归实现删除文件目录的方法
2016/09/23 PHP
vmware linux系统安装最新的php7图解
2019/04/14 PHP
PHP实现基于状态的责任链审批模式详解
2019/05/31 PHP
jquery BS,dialog控件自适应大小
2009/07/06 Javascript
jQuery学习笔记 操作jQuery对象 CSS处理
2012/09/19 Javascript
Jquery操作js数组及对象示例代码
2014/05/11 Javascript
JS+DIV+CSS实现仿表单下拉列表效果
2015/08/18 Javascript
最佳的JavaScript错误处理实践
2016/07/16 Javascript
BootStrap的table表头固定tbody滚动的实例代码
2016/08/24 Javascript
js判断PC端与移动端跳转
2020/12/24 Javascript
实例详解Node.js 函数
2018/06/10 Javascript
vue slots 组件的组合/分发实例
2018/09/06 Javascript
详解VUE调用本地json的使用方法
2019/05/15 Javascript
JS数组扁平化(flat)方法总结详解
2019/06/24 Javascript
vue 监听 Treeselect 选择项的改变操作
2020/08/31 Javascript
pydev使用wxpython找不到路径的解决方法
2013/02/10 Python
python xml解析实例详解
2016/11/14 Python
Python中.py文件打包成exe可执行文件详解
2017/03/22 Python
python3的输入方式及多组输入方法
2018/10/17 Python
Python PIL读取的图像发生自动旋转的实现方法
2019/07/05 Python
解决python多行注释引发缩进错误的问题
2019/08/23 Python
python读取excel数据绘制简单曲线图的完整步骤记录
2020/10/30 Python
美国创意礼品网站:UncommonGoods
2017/02/03 全球购物
监理资料员岗位职责
2014/01/03 职场文书
优秀毕业生找工作自荐信
2014/06/23 职场文书
建筑学专业自荐书
2014/07/09 职场文书
大学军训自我鉴定大全
2014/09/18 职场文书
领导班子对照检查剖析材料
2014/10/13 职场文书
2015质检员个人年终工作总结
2015/10/23 职场文书
超级实用的公文标题大全!
2019/07/19 职场文书
2019年销售部季度工作计划3篇
2019/10/09 职场文书
B站评分公认最好看的动漫,你的名字评分9.9,第六备受喜欢
2022/03/18 日漫
多人盗宝《绿林侠盗》第三赛季4.5上线 跨平台实装
2022/04/03 其他游戏