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 相关文章推荐
复杂检索数据并分页显示的处理方法
Oct 09 PHP
如何提高MYSQL数据库的查询统计速度 select 索引应用
Apr 11 PHP
php获取网页中图片、DIV内容的简单方法
Jun 19 PHP
PHP防止表单重复提交的几种常用方法汇总
Aug 19 PHP
php实现获取文件mime类型的方法
Feb 11 PHP
PHP实现HTTP断点续传的方法
Jun 17 PHP
thinkphp3.2.3 分页代码分享
Jul 28 PHP
PHP入门教程之操作符与控制结构流程详解
Sep 09 PHP
PHP屏蔽关键字实现方法
Nov 17 PHP
给大家分享几个常用的PHP函数
Jan 15 PHP
php获取文章内容第一张图片的方法示例
Jul 03 PHP
php插件Xajax使用方法详解
Aug 31 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 header Content-Type类型小结
2011/07/03 PHP
一个经典的PHP文件上传类分享
2014/11/18 PHP
php中二维数组排序问题方法详解
2015/08/28 PHP
修改PHP脚本使WordPress拦截垃圾评论的方法示例
2015/12/10 PHP
PHP读取大文件的几种方法介绍
2016/10/27 PHP
php post json参数的传递和接收处理方法
2018/05/31 PHP
js的with语句使用方法
2007/09/21 Javascript
javascript 获取select下拉列表值的代码
2009/09/07 Javascript
jQuery学习笔记之 Ajax操作篇(一) - 数据加载
2014/06/23 Javascript
详解JavaScript中的客户端消息框架设计原理
2015/06/24 Javascript
javascript实现随机读取数组的方法
2015/08/03 Javascript
jQuery实现简单的文件上传进度条效果
2020/03/26 Javascript
AngularJS中如何使用$http对MongoLab数据表进行增删改查
2016/01/23 Javascript
网站发布后Bootstrap框架引用woff字体无法正常显示的解决方法
2016/11/24 Javascript
详解nodejs 文本操作模块-fs模块(五)
2016/12/23 NodeJs
web前端vue实现插值文本和输出原始html
2018/01/19 Javascript
Angular5中调用第三方库及jQuery的添加的方法
2018/06/07 jQuery
angular 实现下拉列表组件的示例代码
2019/03/09 Javascript
微信小程序事件流原理解析
2019/11/27 Javascript
python RabbitMQ 使用详细介绍(小结)
2018/11/08 Python
对python中的six.moves模块的下载函数urlretrieve详解
2018/12/19 Python
Python3模拟登录操作实例分析
2019/03/12 Python
OpenCV里的imshow()和Matplotlib.pyplot的imshow()的实现
2019/11/25 Python
flask的orm框架SQLAlchemy查询实现解析
2019/12/12 Python
sklearn中的交叉验证的实现(Cross-Validation)
2021/02/22 Python
python FTP编程基础入门
2021/02/27 Python
无需JS和jQuery代码实现CSS3鼠标浮动放大图片
2016/11/21 HTML / CSS
GAP欧盟网上商店:GAP EU
2016/09/13 全球购物
工商管理专业实习大学生自我鉴定
2013/09/19 职场文书
大学生标准推荐信范文
2013/11/25 职场文书
网络工程师职业规划
2014/02/10 职场文书
《诺贝尔》教学反思
2014/02/17 职场文书
创建市级文明单位实施方案
2014/03/01 职场文书
小学生保护环境倡议书
2014/05/15 职场文书
工会主席事迹材料
2014/06/03 职场文书
2016年感恩父亲节活动总结
2016/04/01 职场文书