核心类(用到了模型)
<?php/**
* Created by PhpStorm.
* User: Administrator
* Date: 2020/11/11
* Time: 16:37 */namespace appcommoncontroller;use appmodelChat;class SocketService
{ private $address = '0.0.0.0'; private $port = 1999; private $_sockets; public function __construct($address = '', $port='')
{ if(!empty($address)){ $this->address = $address;
} if(!empty($port)) { $this->port = $port;
}
} public function service(){ //获取tcp协议号码。
$tcp = getprotobyname("tcp"); $sock = socket_create(AF_INET, SOCK_STREAM, $tcp);
socket_set_option($sock, SOL_SOCKET, SO_REUSEADDR, 1); if($sock < 0)
{ throw new Exception("failed to create socket: ".socket_strerror($sock)."n");
}
socket_bind($sock, $this->address, $this->port);
socket_listen($sock, $this->port); echo "listen on $this->address $this->port ... n"; $this->_sockets = $sock;
} public function run(){ $this->service(); $clients[] = $this->_sockets; while (true){ $changes = $clients; $write = NULL; $except = NULL;
socket_select($changes, $write, $except, NULL); foreach ($changes as $key => $_sock){ if($this->_sockets == $_sock){ //判断是不是新接入的socket
if(($newClient = socket_accept($_sock)) === false){ die('failed to accept socket: '.socket_strerror($_sock)."n");
} $line = trim(socket_read($newClient, 1024)); $this->handshaking($newClient, $line); //获取client ip
socket_getpeername ($newClient, $ip); $clients[$ip] = $newClient;
} else { try{
socket_recv($_sock, $buffer, 2048, 0); // 接收数据
$msg = $this->message($buffer); // 转码数据
echo "{$key} clinet msg:",$msg,"n"; $this->send($_sock, $msg); $data = json_decode($msg, true); if(!empty($data)){ $db = new Chat(); $db->allowField(true)->save($data);
}
} catch (Exception $e){ unset($clients[$_sock]); } }
}
}
} /**
* 握手处理
* @param $newClient socket
* @return int 接收到的信息 */
public function handshaking($newClient, $line){ $headers = array(); $lines = preg_split("/rn/", $line); 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 Handshakern" .
"Upgrade: websocketrn" .
"Connection: Upgradern" .
"WebSocket-Origin: $this->addressrn" .
"WebSocket-Location: ws://$this->address:$this->port/websocket/websocketrn".
"Sec-WebSocket-Accept:$secAcceptrnrn"; return socket_write($newClient, $upgrade, strlen($upgrade));
} /**
* 解析接收数据
* @param $buffer
* @return null|string */
public function message($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;
} /**
* 发送数据
* @param $newClinet 新接入的socket
* @param $msg 要发送的数据
* @return int|string */
public function send($newClinet, $msg){ $msg = $this->frame($msg);
socket_write($newClinet, $msg, strlen($msg));
} public 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;
} /**
* 关闭socket */
public function close(){ return socket_close($this->_sockets);
}
}$sock = new SocketService();$sock->run();
绑定入口
在application创建common/controller
把核心类放进去
在public创建server.php
<?php/**
* Created by PhpStorm.
* User: Administrator
* Date: 2020/11/11
* Time: 16:13 */// [ 应用入口文件 ]namespace think;// 加载基础文件require __DIR__ . '/../thinkphp/base.php';// 执行应用并响应(绑定)Container::get('app')->bind('common/Socket_service')->run()->send();
运行服务端
在cmd或者treminal中
cd到这个应用的public目录中
php server.php
服务端已启动,正在监听1999端口
客户端
<{include file="public/header" /}><style>
.fl{ float: left; }
.fr{ float: right; }
li{ display: block; background-color: #ccc; line-height: 30px; width: 100%; height: 30px; }
.block{ width: 90%; height: 500px; float: left; margin: 0 auto; }
.msg{ width: 100%; height: 400px; background-color: #fff; margin-bottom: 400px; }
.receive{ width: 51%; }
.send{ width: 51%; }
.red{ color: red; float: right; }</style></head><body><div class="block">
<div class="msg">
<div class="send fl">
<ul>
<li>1111111 <span class="red">2020</span></li>
</ul>
</div>
<div class="receive fr">
<ul>
<li>1111111 <span class="red">2020</span></li>
</ul>
</div>
<div class="bottom">
<textarea name="" id="content" cols="30" rows="10" class="layui-textarea"></textarea>
<button class="layui-btn" id="send">发送</button>
</div>
</div></div></body></html><script>
$(function () { var wsurl = 'ws://127.0.0.1:1999'; var websocket; var i = 0; var uid = 2; if (window.WebSocket) {
websocket = new WebSocket(wsurl); //连接建立 websocket.onopen = function (evevt) {
console.log("Connected to WebSocket server."); // $('.receive').append('<p class="bg-info message"><i class="glyphicon glyphicon-info-sign"></i>Connected to WebSocket server!</p>'); $('.receive').append('<li>Connected to WebSocket server! <span class="red">'+ getTime(new Date().getTime()) +'</span></li>');
} //收到消息 websocket.onmessage = function (event) { var msg = JSON.parse(event.data); //解析收到的json消息数据
i++; if (msg.send_uid == uid) {
$('.send').append('<li> '+ msg.content +' <span class="red">'+ getTime(new Date().getTime()) +'</span></li>');
}else{
$('.receive').append('<li> '+ msg.content +'<span class="red">'+ getTime(new Date().getTime()) +'</span></li>');
}
$('#message').val('');
window.location.hash = '#' + i;
} //发生错误 websocket.onerror = function (event) {
i++;
console.log("Connected to WebSocket server error");
window.location.hash = '#' + i;
} //连接关闭 websocket.onclose = function (event) {
i++;
console.log('websocket Connection Closed. ');
window.location.hash = '#' + i;
} function send() { var msg = {
type: 'send',
send_uid: 1,
receive_uid: 2,
content: '111111',
img: '',
voice: ''
}; 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>
结果
