php实现 Web sockets

本文介绍了HTML5中的WebSocket技术,这是一种实现实时双向通信的技术。文章提供了基于PHP的WebSocket服务器实现示例,展示了如何建立和维护WebSocket连接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

自十月底,html5 宣布定稿之后,新一轮的关于html的讨论便开始了,现在这里,我也为大家介绍一种html5标准中提到的新技术 websocket,以及他的 php 实现范例。

WebSocket是 HTML5 开始提供的一种 浏览器 与 服务器 间进行 全双工 通讯的网络技术。WebSocket通信协议于2011年被 IETF 定为标准 RFC 6455 ,WebSocket API被 W3C 定为标准。

在WebSocket API中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。

—————-  form wiki

传统的web程序,都遵循这样的执行方式,浏览器发送一个请求,然后服务器端接收这个请求,处理完成浏览器的请求之后,再将处理完成的结果返回给浏览器,然后浏览器处理返回的html,将其呈现给用户。如下图所示:

即使后来出现了ajax这样的新的技术,它实际也是使用javascript的api来向服务器发送请求,然后等待相应的数据。也就是说,在浏览器和服务器的交互中,我们每想得到一个得到新的数据(更新页面,获得服务器端的最新状态)就必须要发起一个http请求,建立一条TCP/IP链接,当这次请求的数据被浏览器接收到之后,就断开这条TCP/IP连接。

新的websocket技术,在浏览器端发起一条请求之后,服务器端与浏览器端的请求进行握手应答之后,就建立起一条长久的,双工的长连接,基于这条连接,我们不必做一些轮询就能随时获得服务器端的状态,服务器也不必等待浏览器端的请求才能向用户推送数据,可以在这条连接上随时向以建立websocket连接的用户 push 数据。

这里 是 websocket 协议的 RFC 文档。

我这里的实现是基于 php sockets的实现, php socket api

<?php
  class WsServer{
	  public  $socket;
	  public  $socketArray;
	  public  $activatedSocketArray;
	  public function __construct($address,$port){
	  	$this->socket =  $this->init($address,$port);
	  	if($this->socket == null)
	  		exit(1);
	  	
	  }
	  private function init($address,$port){
		 $wssocket  = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
		 socket_set_option($wssocket, SOL_SOCKET, SO_REUSEADDR, 1);
		 socket_bind($wssocket,$address,$port);
		 if(socket_listen($wssocket)){
	  		$this->p("Socket init success");
	  		return $wssocket;
		 }else{
		 	$this->p("Socket init failure");
		 	exit();
		 }
		 
	  }
	 
	  public function run(){
		$this->socketArray[] = $this->socket;
		$write  = NULL;
		$except = NULL;
	  	while (true){
		$this->activatedSocketArray = $this->socketArray;
	  	socket_select($this->activatedSocketArray, $write, $except, null);
	  	
		foreach($this->activatedSocketArray as $s){
	  	 if($s == $this->socket){
	  	   $client = socket_accept($this->socket);
	  	   socket_recv($client, $buffer, 2048, 0);
	  	 
	  	   // response a handshake response
	  	   if(socket_write($client, $this->handshakeResponse($buffer))!== false){
	  		 $this->p('add a socket into the queue');
	  		 array_push($this->socketArray, $client);
	  		}else{
	  	   	   $this->p('error on handshake');
	  	   	   $this->errorLog(socket_last_error());
	  	   }
	  	}else{
	  		socket_recv($s, $buffer, 2048, 0);
	  		$str  = $this->decode($buffer);
	  		$str = $this->frame($str);
	  		socket_write($s,$str,strlen($str));
	  	  }
	  	}
	  	
	  	}
	  }
	  /*
	   *   build the data frame sent to client by server socket.  
	   * 
	   * **/
	  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;
	  }
	  /*
	   * decode the client socket input 
	   * 
	   * **/
	  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;
	  }
	/*
	 * params @requestHeaders : read from request socket
	 * return an array of request 
	 * 
	 * */
	function parseHeaders($requsetHeaders){
		$resule =array();
		if (preg_match("/GET (.*) HTTP/"			  ,$requsetHeaders,$match)) { $resule['reuqest'] = $match[1]; }
		if (preg_match("/Host: (.*)\r\n/"			 ,$requsetHeaders,$match)) { $result['host'] = $match[1]; }
		if (preg_match("/Origin: (.*)\r\n/"		   ,$requsetHeaders,$match)) { $result['origin'] = $match[1]; }
		if (preg_match("/Sec-WebSocket-Key: (.*)\r\n/",$requsetHeaders,$match)) { $result['key'] = $match[1]; }
		return $result;
		
	}
	/*
	 * protocol version : 13
	 * generting the key of handshaking
	 * return encrypted key
	 * */
	function getKey($requestKey){
		return base64_encode(sha1($requestKey . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true));
		
	}
	/**params @parseRequest : request written in socket
	 * return handshakResponse witten in response socket
	 * */
	function  handshakeResponse($request){
		$parsedRequest  = $this->parseHeaders($request);
		$encryptedKey = $this->getKey($parsedRequest['key']);
		$response  = "HTTP/1.1 101 Switching Protocol\r\n" .
					"Upgrade: websocket\r\n" .
					"Connection: Upgrade\r\n" .
					"Sec-WebSocket-Accept: " .$encryptedKey. "\r\n\r\n";
		return $response;
					
	}
	/*
	 * report last_error in socket 
	 * 
	 * */
	function errorLog($ms){
		echo 'Error:\n'.$ms;
	}
	/*
	 * print the log
	 * 
	 * */
	private  function p($e){
		echo $e."\n";
	}
   function test(){
   	  $read[] = $this->socket;
   	  $write = null;
   	  $except = null;
   	  socket_select($read, $write, $except,null);
   	  var_dump($read);
   }
  }
  $w = new WsServer('localhost',4000);
  $w->run();
?>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值