php 聊天室 原理,html5 WebSocket 与 PHP socket 聊天室原理

首先要运行server.php服务端,然后通过浏览器运行chat.html

chat.html

聊天室

发送

(function() {

var socket = new WebSocket('ws://127.0.0.1:8008');

var send = document.getElementById('send');

var data = document.getElementById('data');

var message = document.getElementById('message');

var wrapper = document.getElementById('wrapper');

var height = (wrapper.offsetHeight) -270;

message.style.height = height+'px';

socket.onopen = function(event) {

message.innerHTML = '

连接成功!

';

}

socket.onmessage = function(event) {

var dl = document.createElement('dl');

var jsonData = JSON.parse(event.data);

dl.innerHTML = "

+jsonData.avatar+ "+jsonData.content+"";

message.appendChild(dl);

message.scrollTop = message.scrollHeight;

}

socket.onerror = function() {

message.innerHTML = '

连接失败!

';

}

send.addEventListener('click', function() {

var content = data.value;

if(content.length <= 0) {

alert('消息不能为空!');

return false;

}

var avatar = Math.random();

var message = {

"avatar" : 'images/avatar.jpg',

"content" : content

}

var json = JSON.stringify(message);

socket.send(json);

data.value = ''; data.focus();

});

})();

server.php

class WebSocket {

private $socket;

private $accept;

private $isHand = array();

public function __construct($host, $port, $max) {

$this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

socket_set_option($this->socket, SOL_SOCKET, SO_REUSEADDR, TRUE);

socket_bind($this->socket, $host, $port);

socket_listen($this->socket, $max);

}

public function start() {

while(true) {

$cycle = $this->accept;

$cycle[] = $this->socket;

socket_select($cycle, $write, $except, null);

foreach($cycle as $sock) {

if($sock === $this->socket) {

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

$this->accept[] = $client;

$key = array_keys($this->accept);

$key = end($key);

$this->isHand[$key] = false;

} else {

$length = socket_recv($sock, $buffer, 204800, 0);

$key = array_search($sock, $this->accept);

if($length < 7) {

$this->close($sock);

continue;

}

if(!$this->isHand[$key]) {

$this->dohandshake($sock, $buffer, $key);

} else {

// 先解码,再编码

$data = $this->decode($buffer);

$data = $this->encode($data);

// 判断断开连接(断开连接时数据长度小于10)

if(strlen($data) > 10) {

foreach($this->accept as $client) {

socket_write($client, $data, strlen($data));

}

}

}

}

}

}

}

/**

* 首次与客户端握手

*/

public function dohandshake($sock, $data, $key) {

if (preg_match("/Sec-WebSocket-Key: (.*)\r\n/", $data, $match)) {

$response = base64_encode(sha1($match[1] . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true));

$upgrade = "HTTP/1.1 101 Switching Protocol\r\n" .

"Upgrade: websocket\r\n" .

"Connection: Upgrade\r\n" .

"Sec-WebSocket-Accept: " . $response . "\r\n\r\n";

socket_write($sock, $upgrade, strlen($upgrade));

$this->isHand[$key] = true;

}

}

/**

* 关闭一个客户端连接

*/

public function close($sock) {

$key = array_search($sock, $this->accept);

socket_close($sock);

unset($this->accept[$key]);

unset($this->handshake[$key]);

}

/**

* 解码过程

*/

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

}

/**

* 编码过程

*/

public function encode($buffer) {

$length = strlen($buffer);

if($length <= 125) {

return "\x81".chr($length).$buffer;

} else if($length <= 65535) {

return "\x81".chr(126).pack("n", $length).$buffer;

} else {

return "\x81".char(127).pack("xxxxN", $length).$buffer;

}

}

}

$webSocket = new WebSocket('127.0.0.1', 8008, 100);

$webSocket->start();

?>

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值