首先感谢打开这篇文章,但是运行时候有一点点错误,所以我把自己整理后的内容发布上来
下载代码github下载1,csdn下载2
之所以选择websocket,而不是使用ajax理由如下:
1、ajax轮询 ,ajax轮询 的原理非常简单,让浏览器隔个几秒就发送一次请求,询问服务器是否有新信息。
2、long poll 其实原理跟 ajax轮询 差不多,都是采用轮询的方式,不过采取的是阻塞模型(一直打电话,没收到就不挂电话),也就是说,客户端发起连接后,如果没消息,就一直不返回Response给客户端。直到有消 息才返回或超时,返回完之后,客户端再次建立连接,周而复始,基于事件的触发,一个事件接一个事件。
Ajax轮询与long poll都属于不断发送http请求,然后等待服务器处理,可以看到http协议一个特点,被动性,服务端不能主动联系客户端,只有客户端发起。
缺点:Ajax轮询需要服务器有很快的处理速度与快速响应。long poll需要很高的并发,体现在同时容纳请求的能力。
3、webSocket是HTML5一种新的协议,实现了浏览器与服务器之间的全双工通信,能很好的节省服务器资源与带宽,并在服务器端与浏览器端实现实时通行,他建立在TCP之上, 同http一样,通过tcp来传输数据。
只需要一次HTTP握手,所以说整个通讯过程是建立在一次连接/状态中,服务器端会知道连接的信息,知道客户端关闭请求,同时由服务器主动推送,当有信息需要发送时,直接发送。客户端的连接通过session对象存储,能够实现实时推送。
所以选择webSocket进行实现。
1、运行脚本
保存为 run.bat
cd D:\Program Files\PHP
php D:\www\websocket\Server_socket.php
其中第一行代表PHP文件的安装目录
第二行是接下来介绍的文件存放目录
2、Server_socket.php 服务器端的处理文件
使用php socket
<?php
/**
* 聊天室服务器 websocket 专用
*/
class Server_socket
{
private $socket;
private $accept = [];
private $hands = [];
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);
print_r($this->socket);
}
public function start()
{
$i = 0;
while (true) {
$cycle = $this->accept;
$cycle[] = $this->socket;
socket_select($cycle, $write, $except, null);
foreach ($cycle as $sock) {
if ($sock == $this->socket) {
$this->accept[] = socket_accept($sock);
$arr = array_keys($this->accept);
$key = end($arr);
$this->hands[$key] = false;
}else{
$length = socket_recv($sock, $buffer, 204800, null);
$key = array_search($sock, $this->accept);
if (!$this->hands[$key]) {
$this->dohandshake($sock,$buffer,$key);
}else if($length < 1){
$this->close($sock);
}else{
//接收从客户端发送的内容 解码
$data = $this->decode($buffer);
print_r("\nThis is the data received from client,".$data);
//服务器端的内容 编码
$data = "This is the data sent by server".$i.", so smart";
$data = $this->encode($data);
print_r($data);
//将信息传递给从机
foreach ($this->accept as $client) {
socket_write($client,$data ,strlen($data));
}
$i++;
}
}
}
sleep(1);
}
}/* end of start*/
/**
* 首次与客户端握手
*/
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->hands[$key] = true;
}
}/*dohandshake*/
/**
* 关闭一个客户端连接
*/
public function close($sock) {
$key = array_search($sock, $this->accept);
socket_close($sock);
unset($this->accept[$key]);
unset($this->hands[$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;
}
}
}/* end of class Server_socket*/
$server_socket = new Server_socket('127.0.0.1',9000,20);
$server_socket->start(); sleep(2);
?>
主要的函数是start()函数,当中写了注释内容,可以根据自己的需要进行修改
3、客户端JavaScript websocket
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>websocket</title>
</head>
<body>
<div>
<button id='send'> 发送</button>
</div>
</body>
<script>
// var socket = new WebSocket('ws://127.0.0.1:9000');
var url = "ws://127.0.0.1:9000";
//兼容 FireFox
if ("WebSocket" in window) {
socket = new WebSocket(url);
} else if ("MozWebSocket" in window) {
socket = new MozWebSocket(url);
}
socket.onopen = function(event) {
console.log("connected");
socket.send("client say hello\n");
alert('连接');
};
socket.onmessage = function(event) {//当客户端收到服务端发来的消息时,会触发onmessage事件,参数event.data中包含server传输过来的数据
var content = event.data;//获取消息
console.log(content);
if (content.length > 0) {
alert("server said"+content);
}
};
socket.onclose = function(evt)
{
console.log("WebSocketClosed!");
};
socket.onerror = function(evt)
{
console.log("WebSocketError!");
};
var send = document.getElementById('send');
send.addEventListener('click', function() {
var content = 'client sent\n';
console.log(content);
socket.send(content);
alert('发送');
});
</script>
</html>
这里客户端页面加载后就与服务器端进行连接,如果成功之后,就会执行onopen,如果服务器发送内容,执行onmessage,其中event是服务器发送的对象。查看更多
4、运行步骤
1)下载源代码至本地
2)修改run.bat文件存放路径
3)双击运行脚本
4)打开浏览器,我是放在Apache的www文件夹下面的,输入http://127.0.0.1/websocket/wobsocket.html
5)如果报错
表示Server_socket.php 没有执行,也可能是火狐浏览器的websocket没有打开。
打开火狐浏览器的websocket方法
1)地址栏输入about:config
2)回车,搜索框输入websocket,将与websocket有关的内容全部打开,重启浏览器。
6)执行效果
左边的cmd是执行run.bat的脚本
右边的控制台是客户端执行的有关打印
可以看出,客户端发送的信息被服务端接收,并且服务端发送的内容客户端也可以被接收。
之所以要做这个是有关实现团队前端主机创建成员,从机加入后,推送消息给主机,是哪一个成员加入,以及主机点击开始操作之后,主机和从机同时进入操作页面。
另外,还可能后期还会有操作期间的会话,其实这个已经可以简单实现,不过问题是需要区分团队,每一个团队有一个聊天室。以及发送消息区分每一个用户。可能后期会参考打开,以及打开
参考链接:
[连载] Socket 深度探索 4 PHP (一)http://blog.csdn.net/shagoo/article/details/6396089
php中socket的使用 http://www.cnblogs.com/phpzxh/archive/2010/12/09/1901437.html
PHP-Socket服务端客户端发送接收通信实例详解 http://fighter.blog.51cto.com/1318618/1533957/
写了websocket个聊天室,然后终于弄懂了php的socket
http://www.tuicool.com/articles/iEV3Aje
简单又好用的聊天室技术——WebSocket https://segmentfault.com/a/1190000005041671
php socket 和 html5 websocket 通讯 http://blog.csdn.net/little_rabbit_baby/article/details/53184595
聊天室http://www.cnblogs.com/Wayou/p/hichat_built_with_nodejs_socket.html
WebSocket的JavaScript例子http://www.xyhtml5.com/websocket-javascript-example.html
webSocket、Ajax轮询、长轮询(long poll)http://blog.csdn.net/lb7758zx/article/details/51513353