您的位置:首页 > 编程语言 > PHP开发

php基于websocket搭建简易聊天室(socket)

2017-09-13 13:29 513 查看

前言

http连接分为短连接和长连接。短连接一般可以用ajax实现,长连接就是websocket。短连接实现起来比较简单,但是太过于消耗资源。websocket高效不过兼容存在点问题。websocket是html5的资源

前端

//连接socket

var ws = new Websocket(‘ws://127.0.0.1:8080’);

//成功连接socket的时候

ws.onopen = function(){}

//成功获取服务端输出的信息

ws.onmessage = function(e){}

//连接错误的时候

ws.onerror = function(){}

//向服务端发送数据

ws.send();

后台,服务端

websocket 通信图解 这是一个简易的客户端和服务端的通信图解,php主要就做的就是接受加密key 并返回 其中完成套接字的创建和握手操作



服务端处理websocket的图解



服务端代码

服务端做的流程大致是:

1,挂起一个socket套接字进程等待连接

2,有socket连接之后遍历套接字数组

3,没有握手的进行握手操作,如果已经握手则接收数据解析并写入缓冲区进行输出

套接字

1,将套接字放入数组

public function __contruct($address,$port){

//建立套接字

$this->soc = $this->createSocket($address,$port);

$this->socs = array($this->soc);

}

2,建立套接字

socket_create解释:http://www.php.net/manual/zh/function.socket-create.php

public function createSocket($address,$port){

//创建

$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

//设置套接字选项

socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);

//绑定IP地址以及端口

socket_bind($socket,$address,$port);

//监听套接字

socket_listen($socket);

return $socket;

}

挂起进程,遍历套接字数组

public function run(){

//挂起进程

while(true){

$arr = $this->socs;

$write=$except=NULL;

//接受套接字数字,监听状态

socket_select($arr,$write,$except, NULL);

//遍历套接字数组

foreach($arr as $k=>$v ){

//如果是新建立的套接字返回一个有效的 套接字资源

if($this->soc == $v ){

$client=socket_accept($this->soc);

if($client < 0){

echo “socket_accept() failed”;

}else{

// array_push($this->socs,$client);

// unset($this[]);

//将有效的套接字资源放到套接字数组

$this->socs[]=$client;

}

}else{

//从已连接的socket接收数据 返回的是从socket中接收的字节数

$byte=socket_recv($v, $buff,20480, 0);

//如果接受的字节数 0

if($byte < 7){

continue;

}

//判断有没有握手没有握手则进行握手,如果握手了 则进行处理

if(!$this->hand[(int)$client]){

//进行握手操作

$this->hands($client,$buff,$v);

}else{

//处理数据

$mess=$this->decodeData($buff);

//发送数据

$this->send($mess,$v);

}

}

}

}

}

进行握手

握手流程是接收websocket内容从Sec-WebSocket-Key:中获取key并通过加密算法写入缓冲区客户端会进行验证(自动验证不需要我们处理)

public function hands($client,$buff,$v)

{

//提取websocket传的key并进行加密 (这是固定的握手机制获取Sec-WebSocket-Key:里面的key)

$buf = substr($buff,strpos($buff,’Sec-WebSocket-Key:’)+18);

//去除换行空格字符

$key = trim(substr($buf,0,strpos($buf,”\r\n”)));

//固定的加密算法

$new_key = base64_encode(sha1($key.”258EAFA5-E914-47DA-95CA-C5AB0DC85B11”,true));

$new_message = “HTTP/1.1 101 Switching Protocols\r\n”;

\ $new_message .= “Upgrade: websocket\r\n”;

\$new_message .= “Sec-WebSocket-Version: 13\r\n”;

\$new_message .= “Connection: Upgrade\r\n”;

\$new_message .= “Sec-WebSocket-Accept: ” . \$new_key . “\r\n\r\n”;

//将套接字写入缓冲区

socket_write($v,$new_message,strlen($new_message));

//socket_write(socket,$upgrade.chr(0),strlen($upgrade.chr(0)));

//标记此套接字握手成功

$this->hand[(int)$client]=true;

}

解析客户端的数据

//解析数据

public function decodeData($buff)

{

//$buff 解析数据帧

$mask = array();

$data = ”;

$msg = unpack(‘H*’,$buff); //用unpack函数从二进制将数据解码

$head = substr($msg[1],0,2);

if (hexdec($head{1}) === 8) {

$data = false;

}else if (hexdec($head{1}) === 1){

$mask[] = hexdec(substr($msg[1],4,2));

$mask[] = hexdec(substr($msg[1],6,2));

$mask[] = hexdec(substr($msg[1],8,2));

$mask[] = hexdec(substr($msg[1],10,2));

//遇到的问题 刚连接的时候就发送数据 显示 state connecting

$s = 12;

$e = strlen($msg[1])-2;

$n = 0;

for (\$i=\$s; \$i<= \$e; \$i+= 2) {

\$data .= chr(\$mask[\$n%4]^hexdec(substr(\$msg[1],\$i,2)));

\$n++;

}

//发送数据到客户端

//如果长度大于125 将数据分块

\$block=str_split(\$data,125);

\$mess=array(

‘mess’=>\$block[0],

);

return \$mess;

}

将套接字写入缓冲区,发送数据

/发送数据

public function send($mess,$v)

{

//遍历套接字数组 成功握手的 进行数据群发

foreach ($this->socs as $keys => $values) {

//用系统分配的套接字资源id作为用户昵称

$mess[‘name’]=”Tourist’s socket:{$v}”;

$str=json_encode($mess);

$writes =”\x81”.chr(strlen($str)).$str;

// ob_flush();

// flush();

// sleep(3);

if($this->hand[(int)$values])

socket_write($values,$writes,strlen($writes));

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: