php socket主动推送消息,php实现socket推送技术

这篇文章主要介绍了关于php实现socket推送技术 ,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下

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

demo

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

})

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

代码解析:

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

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

以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!

相关推荐:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值