当前位置:首页 > PHP > 正文内容

php scoket,php webscoket,php webscoket 服务器

高老师7年前 (2017-12-03)PHP1730

项目需要使用websocket推送最新订单,客户服务器非linux不支持swoole,因此使用原生,直接上代码

(1).PHP服务端

<?php
ini_set('error_reporting', E_ALL ^ E_NOTICE);
ini_set('display_errors', 1);
set_time_limit(0);

$address = '127.0.0.1';
$port = 6936;

//01.创建一个套接字(参数1是支持ipv4的TCP/UDP,参数2是套接字使用的类型,参数3是domain下具体协议)
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP) or die('Create Socket Failed');

//02.设置socket的参数(参数1是资源句柄,参数2是ip地址,参数3是挂起本脚本的端口)
socket_bind($sock, $address, $port) or die('Could not bind to address');

//03.开始监听来自本端口的所有连接
socket_listen($sock);

//04.设置为非阻塞
socket_set_nonblock($sock);

//05.保存所有的客户端state记录是否握手,shopid记录店铺id
/*
array(
	array('client'=>$sock1,'state'=>0,'shopid'=>0),
	array('client'=>$sock2,'state'=>0,'shopid'=>1),
)
*/

$client = array();

//06.while挂起进程来处理webscoket
while (true) {

	//检测到新client,加入client组,并记录是否握手
	if ($newsock = @socket_accept($sock)) {
		if (is_resource($newsock)) {
			//给新检测到的client回应
			socket_write($newsock, "", 2) . chr(0);
			//并且将其加入client队伍中
			array_push($client,array('client'=>$newsock,'state'=>0));
		}
	}

	if (count($client)) {
		foreach ($client AS $k => $v) {
			//是否获取到数据
			if (@socket_recv($v['client'], $string, 1024, 0) === 0) {
				unset($client[$k]);
				socket_close($v['client']);
			} else {
				//已经握手可以直接发送消息
				if ($v['state'] == 1) {

					//握手完成的第一次,可以直接拿到client发送来的完整数据
					if($string!=''){
						$clientmsg=unmask($string);
						echo $clientmsg;//这就是client发送来的数据
					}

					$data = array('12345', '上山打老虎','客户端的小妹妹你好');
					$data = json_encode($data);
					$data = mask($data);
					@socket_write($v['client'], $data, strlen($data));
				}
				//未握手先完成握手
				else {
					doHandShake($v['client'], $string);
					$client[$k]['state']=1;
				}
			}
		}
	}

	sleep(1);
}

//握手方法
function doHandShake($socket, $buffer) {
	list($resource, $host, $origin, $key) = getHeaders($buffer);
	$upgrade = "HTTP/1.1 101 Switching Protocol\r\n" . "Upgrade: websocket\r\n" . "Connection: Upgrade\r\n" . "Sec-WebSocket-Accept: " . calcKey($key) . "\r\n\r\n";
	//必须以两个回车结尾
	socket_write($socket, $upgrade, strlen($upgrade));
}

//获取请求头
function getHeaders($buffer) {
	$r = $h = $o = $key = null;
	if (preg_match("/GET (.*) HTTP/", $buffer, $match)) { $r = $match[1];
	}
	if (preg_match("/Host: (.*)\r\n/", $buffer, $match)) { $h = $match[1];
	}
	if (preg_match("/Origin: (.*)\r\n/", $buffer, $match)) { $o = $match[1];
	}
	if (preg_match("/Sec-WebSocket-Key: (.*)\r\n/", $buffer, $match)) { $key = $match[1];
	}
	return [$r, $h, $o, $key];
}

//验证socket
function calcKey($key) {
	$accept = base64_encode(sha1($key . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true));
	return $accept;
}

//解码数据(解析client发送的数据)
function unmask($text) {
	$length = ord($text[1]) & 127;
	if ($length == 126) {
		$masks = substr($text, 4, 4);
		$data = substr($text, 8);
	} elseif ($length == 127) {
		$masks = substr($text, 10, 4);
		$data = substr($text, 14);
	} else {
		$masks = substr($text, 2, 4);
		$data = substr($text, 6);
	}
	$text = "";
	for ($i = 0; $i < strlen($data); ++$i) {
		$text .= $data[$i] ^ $masks[$i % 4];
	}
	return $text;
}

//编码数据(编码向client发送的数据)
function mask($text) {
	$b1 = 0x80 | (0x1 & 0x0f);
	$length = strlen($text);

	if ($length <= 125)
		$header = pack('CC', $b1, $length);
	elseif ($length > 125 && $length < 65536)
		$header = pack('CCn', $b1, 126, $length);
	elseif ($length >= 65536)
		$header = pack('CCNN', $b1, 127, $length);
	return $header . $text;
}

socket_close($sock);
?>

(2).Javascript客户端

<script type="text/javascript">
if("WebSocket" in window) {
	var ws = new WebSocket("ws://127.0.0.1:6936");
	
	//socket握手自动触发推送消息
	ws.onopen = function() {
		var data = {
			id: 287,
			name: '某终端'
		}
		data = JSON.stringify(data);
		ws.send(data);
	};
	
	//监听来自服务端的消息
	ws.onmessage = function(evt) {
		console.log(evt.data);

	};
	
	//客户端或服务端断开自动触发
	ws.onclose = function() {
		console.log('websocket已经断开!');
	};
} else {
	console.log('您的浏览器不支持h5,无法启动websocket');
}
</script>

扫描二维码推送至手机访问。

版权声明:本文由高久峰个人博客发布,如需转载请注明出处。

本文链接:https://blog.5b1.cn/post/47.html

分享给朋友:

“php scoket,php webscoket,php webscoket 服务器” 的相关文章

PHP跨域问题最佳解决方案

PHP跨域问题最佳解决方案

1、允许单个域名访问指定某域名(http://client.runoob.com)跨域访问,则只需在http://server.runoob.com/server.php文件头部添加如下代码:header('Access-Control-Allow-Origin:http://client....

PHP浮点数乘以整数还是浮点型

PHP浮点数乘以整数还是浮点型

<?PHP     $a=0.5*100;     if(is_int($a)){   echo'int'; } else{ echo'not int';   }    ...

PHP中Session文件过多的解决方法

PHP中Session文件过多的解决方法

PHP的session文件夹默认保存在同一个文件,随着访客的增多,访问的速度会非常慢,例如部分管理系统后台每天登陆1000次,1个月就创建了30000个session文件,一年后是多少?假设这个系统的用户是上万人呢?方法1:每个网站使用自己的session文件夹,代码如下:<?php $pat...

php调用 java webservice接口

php调用 java webservice接口

php调用Webservice基本语法如下:$url ='xxxxxxx.cn'  //链接服务器端 $client = new SoapClient($url);通过以上语法已经连接到webservice,也可将wsdl在本地使用,...

php引用变量的完全理解

php引用变量的完全理解

在PHP中,大部分变量类型,如字符串,整型,浮点,数组等都是值类型的,而类和对象是引用类型.和其他语言有点差距.(1).在值类型中我们直接使用&符号表示指向对应变量的内存地址,当前变量和被指向的变量只要有1个的值被修改都会直接影响另外一个变量的值发生变化。(ps:还是非常节省内存的,可以使用...

 php mysql 行锁,php mysql 行级锁,php mysql 行锁定

php mysql 行锁,php mysql 行级锁,php mysql 行锁定

应用场景:PHP模拟购买,商品数量大于0才能购买常见代码:<?php //连接数据库 $con=mysqli_connect("localhost","ihuohuo","927464cy","ihuohuo");...