文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php教程>php实现socket推送技术的讲解

php实现socket推送技术的讲解

时间:2020-12-29  来源:互联网

本站为大家分享一篇php实现socket推送技术的示例,具有很好的参考价值,希望对大家的学习有所帮助。

u=840823493,672068675&fm=15&gp=0.jpg

在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,开始贴代码~

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

服务端代码:

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):

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

代码解析:

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

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

以上就是文章的全部的内容了,希望对你有所帮助。

相关阅读更多 +
最近更新
排行榜 更多 +
元梦之星最新版手游

元梦之星最新版手游

棋牌卡牌 下载
我自为道安卓版

我自为道安卓版

角色扮演 下载
一剑斩仙

一剑斩仙

角色扮演 下载