<!DOCTYPE html>
<html>
<head>
<title>简易聊天Demo</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1, maximum-scale=1, user-scalable=no">
<link href="https://cdn.bootcss.com/bootstrap/3.3.2/css/bootstrap.min.css" rel="stylesheet">
<style type="text/css">
<!--
html, body {
min-height: 100%;
}
body {
margin: 0;
padding: 0;
width: 100%;
font-family: "Microsoft Yahei", sans-serif, Arial;
}
.container {
text-align: center;
}
.title {
font-size: 16px;
color: rgba(0, 0, 0, 0.3);
position: fixed;
line-height: 30px;
height: 30px;
left: 0px;
right: 0px;
background-color: white;
}
.content {
background-color: #f1f1f1;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
margin-top: 30px;
}
.content .show-area {
text-align: left;
padding-top: 8px;
padding-bottom: 168px;
}
.content .show-area .message {
width: 70%;
padding: 5px;
word-wrap: break-word;
word-break: normal;
}
.content .write-area {
position: fixed;
bottom: 0px;
right: 0px;
left: 0px;
background-color: #f1f1f1;
z-index: 10;
width: 100%;
height: 160px;
border-top: 1px solid #d8d8d8;
}
.content .write-area .send {
position: relative;
top: -28px;
height: 28px;
border-top-left-radius: 55px;
border-top-right-radius: 55px;
}
.content .write-area #name {
position: relative;
top: -20px;
line-height: 28px;
font-size: 13px;
}
-->
</style>
</head>
<body>
<div class="container">
<div class="title">简易聊天demo</div>
<div class="content">
<div class="show-area"></div>
<div class="write-area">
<div>
<button class="btn btn-default send">发送</button>
</div>
<div><input name="name" id="name" type="text" placeholder="input your name"></div>
<div>
<textarea name="message" id="message" cols="38" rows="4" placeholder="input your message..."></textarea>
</div>
</div>
</div>
</div>
<!-- <#--弹窗-->
<!-- <div class="modal fade" id="myModal" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title" id="myModalLabel">
提醒
</h4>
</div>
<div class="modal-body" id="modealContent">
你有新的订单
</div>
<div class="modal-footer">
<button onclick="stopAudio()" type="button"
class="btn btn-info" data-dismiss="modal">关闭
</button>
<button onclick="location.reload()" type="button" class="btn btn-primary">查看订单</button>
</div>
</div>
</div>
</div>
<#--播放下单音乐-->
<!--<audio id="notice" loop="loop">
<source src="/diancan/mp3/laidanle.wav" type="audio/mpeg"/>
</audio>
<#--播放催单音乐-->
<!--<audio id="notice2" loop="loop">
<source src="/diancan/mp3/cuidan.wav" type="audio/mpeg"/>
</audio> -->
<script src="http://libs.baidu.com/jquery/1.9.1/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
<script>
$(function () {
var wsurl = 'ws://www.xxxx.com:9999/server.php';
var websocket;
var i = 0;
if (window.WebSocket) {
websocket = new WebSocket(wsurl);
//连接建立
websocket.onopen = function (evevt) {
console.log("Connected to WebSocket server.");
$('.show-area').append('<p class="bg-info message"><i class="glyphicon glyphicon-info-sign"></i>Connected to WebSocket server!</p>');
websocket.send("1231");
}
//收到消息
websocket.onmessage = function (event) {
var msg = JSON.parse(event.data); //解析收到的json消息数据
var type = msg.type; // 消息类型
var umsg = msg.message; //消息文本
var uname = msg.name; //发送人
i++;
if (type == 'usermsg') {
$('.show-area').append('<p class="bg-success message"><i class="glyphicon glyphicon-user"></i><a name="' + i + '"></a><span class="label label-primary">' + uname + ' : </span>' + umsg + '</p>');
}
if (type == 'system') {
$('.show-area').append('<p class="bg-warning message"><a name="' + i + '"></a><i class="glyphicon glyphicon-info-sign"></i>' + umsg + '</p>');
}
$('#message').val('');
window.location.hash = '#' + i;
}
//发生错误
websocket.onerror = function (event) {
i++;
console.log("Connected to WebSocket server error");
$('.show-area').append('<p class="bg-danger message"><a name="' + i + '"></a><i class="glyphicon glyphicon-info-sign"></i>Connect to WebSocket server error.</p>');
window.location.hash = '#' + i;
}
//连接关闭
websocket.onclose = function (event) {
i++;
console.log('websocket Connection Closed. ');
$('.show-area').append('<p class="bg-warning message"><a name="' + i + '"></a><i class="glyphicon glyphicon-info-sign"></i>websocket Connection Closed.</p>');
window.location.hash = '#' + i;
}
/* function send() {
var name = $('#name').val();
var message = $('#message').val();
if (!name) {
alert('请输入用户名!');
return false;
}
if (!message) {
alert('发送消息不能为空!');
return false;
}
var msg = {
message: message,
name: name
};
try {
websocket.send(JSON.stringify(msg));
} catch (ex) {
console.log(ex);
}
} */
//按下enter键发送消息
/* $(window).keydown(function (event) {
if (event.keyCode == 13) {
console.log('user enter');
send();
}
});
//点发送按钮发送消息
$('.send').bind('click', function () {
send();
});
*/
}
else {
alert('该浏览器不支持web socket');
}
});
</script>
<!-- <script type="text/javascript">
//停止播放音乐
function stopAudio() {
document.getElementById('notice').pause()
document.getElementById('notice2').pause()
}
var websocket = null;
//判断当前浏览器是否支持WebSocket
if ('WebSocket' in window) {
websocket = new WebSocket("ws://127.0.0.1:12345/server.php");
} else {
alert('Not support websocket')
}
//连接发生错误的回调方法
websocket.onerror = function () {
alert('websocket通信发生错误!');
};
//连接成功建立的回调方法
websocket.onopen = function (event) {
console.log('建立连接');
}
//接收到消息的回调方法
websocket.onmessage = function (event) {
let msg = event.data
console.log('收到消息:' + msg)
//弹窗提醒, 播放音乐
$('#myModal').modal('show');
if (msg == 0) {
document.getElementById('notice').play();//下单音频
} else {
$('#modealContent').html(msg + "的顾客催单了,请赶快上餐")
document.getElementById('notice2').play();//催单音频
}
}
//连接关闭的回调方法
websocket.onclose = function () {
console.log("websocket链接关闭")
}
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function () {
websocket.close();
}
</script> -->
</body>
</html>
2.创建接口文件
<?php
pc_base::load_sys_class('model', '', 0);
//echo "进入打印接口";
//进行数据库操作
class download extends model
{
function __construct()
{
parent::__construct();
$this->db_config = pc_base::load_config('database');
$this->db_setting = 'default';
$this->table_name = 'v9_download';
}
}
//接口里面需要创建对象
$download_db = new download();
$data_down = $download_db->select("","id,url","1","id desc");
foreach((array)$data_down as $key=> $item){
if($item['id']>425) {
echo $key . "--单表查询--" . $item['url'] . $item['id'] . "<br>";
}
}
?>
3.创建服务websocket服务
<?php
/*//1.初始化curl,返回资源
$curl = curl_init();
//2.设置curl请求的服务器文件地址
//CURLOPT_RETURNTRANSFER将curl_exec()获取的信息以文件流的形式返回,而不是直接输出。
curl_setopt($curl,CURLOPT_RETURNTRANSFER,true);//设置将结果返回而不是直接输出
//针对https协议的请求,需要验证客户端的安全证书,通常都会跳过安全证书的验证
//跳过百度的https验证证书
curl_setopt($curl,CURLOPT_SSL_VERIFYHOST,false);
curl_setopt($curl,CURLOPT_SSL_VERIFYPEER,false);
curl_setopt($curl,CURLOPT_URL,"https://www.baidu.com/index.php");//CURLOPT_URL需要获取的URL地址,也可以在curl_init()函数中设置。
//CURLOPT_HEADER是否返回header头信息
curl_setopt($curl,CURLOPT_HEADER,0);//不返回header头信息
//3.发出请求,接受返回的数据
$result = curl_exec($curl);
echo '<pre>';
var_dump($result);
//4.关闭资源
curl_close($curl);*/
//利用curl调用外部接口,查看数据库数据是否有更新,如果有更新,则打印出来
// 1.初始化curl,返回资源
$ch = curl_init();
//2. 不管是get、post,跳过证书的验证
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
//3.设置请求的服务器地址
curl_setopt($ch, CURLOPT_URL, "http://www.tuibeitu.1xz.cn/api.php?op=print_api");
//4.设置将结果返回而不是直接输出
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
curl_close($ch);
var_dump($result);
echo "进来了";
$host = '0.0.0.0';
$port = '9999';
$null = NULL;
//创建tcp socket
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);//重用端口1表示接受所有的数据包
socket_bind($socket, 0, $port);//把socket绑定在一个IP地址和端口上
//监听端口
socket_listen($socket);
//连接的client socket 列表
$clients = array($socket);
//设置一个死循环,用来监听连接 ,状态//死循环,直到socket断开
while (true) {
$changed = $clients;
/*
//这个函数是同时接受多个连接的关键,我的理解它是为了阻塞程序继续往下执行。
socket_select ($sockets, $write = NULL, $except = NULL, NULL);
$sockets可以理解为一个数组,这个数组中存放的是文件描述符。当它有变化(就是有新消息到或者有客户端连接/断开)时,socket_select函数才会返回,继续往下执行。
$write是监听是否有客户端写数据,传入NULL是不关心是否有写变化。
$except是$sockets里面要被排除的元素,传入NULL是”监听”全部。
最后一个参数是超时时间
如果为0:则立即结束
如果为n>1: 则最多在n秒后结束,如遇某一个连接有新动态,则提前返回
如果为null:如遇某一个连接有新动态,则返回
*/
socket_select($changed, $null, $null, 0, 10);
//如果有新的连接
if (in_array($socket, $changed)) {
//接受并加入新的socket连接
$socket_new = socket_accept($socket);//接受一个socket连接
$clients[] = $socket_new;//将新连接进来的socket存进连接池
//通过socket获取数据执行handshake
$header = socket_read($socket_new, 1024);
perform_handshaking($header, $socket_new, $host, $port);
//获取client ip 编码json数据,并发送通知
socket_getpeername($socket_new, $ip);
$response = mask(json_encode(array('type' => 'system', 'message' => $ip . ' connected')));
send_message($response);
$found_socket = array_search($socket, $changed);
unset($changed[$found_socket]);
}
//轮询 每个client socket 连接
foreach ($changed as $changed_socket) {
//如果有client数据发送过来
/* while (socket_recv($changed_socket, $buf, 1024, 0) >= 1) {
//解码发送过来的数据
$received_text = unmask($buf);
$tst_msg = json_decode($received_text);
$user_name = $tst_msg->name;
$user_message = $tst_msg->message;
//把消息发送回所有连接的 client 上去
//$response_text = mask(json_encode(array('type' => 'usermsg', 'name' => "$user_name", 'message' => $user_message)));
$response_text = mask(json_encode(array('type' => 'usermsg', 'name' => "服务器端", 'message' => "我是从服务器过来啦")));
send_message($response_text);
break 2;
} */
while (1==1) {
// 1.初始化curl,返回资源
$ch = curl_init();
//2. 不管是get、post,跳过证书的验证
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
//3.设置请求的服务器地址
curl_setopt($ch, CURLOPT_URL, "http://www.tuibeitu.1xz.cn/api.php?op=print_api");
//4.设置将结果返回而不是直接输出
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
curl_close($ch);
var_dump($result);
echo "进来了";
//把消息发送回所有连接的 client 上去
$response_text = mask(json_encode(array('type' => 'usermsg', 'name' => "服务器端", 'message' => $result)));
send_message($response_text);
}
//如果有client数据发送过来
/*for($x=1;$x<=50;$x++) {
//解码发送过来的数据
$received_text = unmask($buf);
$tst_msg = json_decode($received_text);
$user_name = $tst_msg->name;
$user_message = $tst_msg->message;
//把消息发送回所有连接的 client 上去
//$response_text = mask(json_encode(array('type' => 'usermsg', 'name' => "$user_name", 'message' => $user_message)));
$response_text = mask(json_encode(array('type' => 'usermsg', 'name' => "服务器端", 'message' => "我是从服务器过来啦")));
send_message($response_text);
//break 2;
} */
//检查offline的client
$buf = @socket_read($changed_socket, 1024, PHP_NORMAL_READ);
if ($buf === false) {
$found_socket = array_search($changed_socket, $clients);
socket_getpeername($changed_socket, $ip);
unset($clients[$found_socket]);
$response = mask(json_encode(array('type' => 'system', 'message' => $ip . ' disconnected')));
send_message($response);
}
}
}
// 关闭监听的socket
socket_close($sock);
//发送消息的方法
function send_message($msg)
{
global $clients;
foreach ($clients as $changed_socket) {
@socket_write($changed_socket, $msg, strlen($msg));
}
return true;
}
//解码数据
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;
}
//编码数据
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;
}
//握手的逻辑
function perform_handshaking($receved_header, $client_conn, $host, $port)
{
$headers = array();
$lines = preg_split("/\r\n/", $receved_header);
foreach ($lines as $line) {
$line = chop($line);
if (preg_match('/\A(\S+): (.*)\z/', $line, $matches)) {
$headers[$matches[1]] = $matches[2];
}
}
$secKey = $headers['Sec-WebSocket-Key'];
$secAccept = base64_encode(pack('H*', sha1($secKey . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));
$upgrade = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" .
"Upgrade: websocket\r\n" .
"Connection: Upgrade\r\n" .
"WebSocket-Origin: $host\r\n" .
"WebSocket-Location: ws://$host:$port/demo/shout.php\r\n" .
"Sec-WebSocket-Accept:$secAccept\r\n\r\n";
socket_write($client_conn, $upgrade, strlen($upgrade));
}PhpStudy开发工具