WebSocket使用笔记
程序员文章站
2022-05-06 15:30:25
...
一、简介
对于网页中快速的发送接收多条消息,WebSocket非常适合来解决这种需求。此次使用WebSocket来搭建一个聊天网页应用。主要涉及的客户端的实现,服务端使用是一个php来实现的WebSocket服务端,在本篇中暂不做详细介绍。
主要的JavaScript代码有这些
- new WebSocket 创建一个websocket对象
- socket.onopen 建立连接后触发
- socket.onerror 错误时触发
- socket.onmessage 接受到数据时触发
- socket.onclose 连接关闭时触发
- socket.send() 发送数据
二、成果
最终实现的是向服务器发消息,服务器返回相同消息,效果如下图所示。在线展示版点击图片下发链接
在线版本在这里
三、代码
JavaScript
var socket;
var submit = document.getElementById('submit');//首先输入聊天者名字,提交后可开始聊天var button = document.getElementById('send');//发送按钮
button.addEventListener('click', sendMsg);
submit.addEventListener('click', startChat);
functionstartChat(){
document.getElementById('modal').style.visibility = "collapse";
document.getElementById('modalBody').style.visibility = "collapse";
connect();//连接服务器
}
//发送消息functionsendMsg(){var txetArea = document.getElementById('sendText');
var content = txetArea.value;
var client = document.getElementById('name').value;
showMsg(content,0);
txetArea.value = "";
msg = {
name: client,
message: content
}
socket.send(JSON.stringify(msg)); //发送数据
}
//显示消息functionshowMsg(content,type){var mainDiv = document.getElementById('main');
var div = document.createElement('div');
mainDiv.appendChild(div);
var lineDiv = mainDiv.lastChild;
lineDiv.className = 'line';
lineDiv.innerHTML = (function(){if (type == 0){
return"";
}
else {
return"";
}
})();
var contentDiv = lineDiv.lastChild;
contentDiv.innerHTML = content;
mainDiv.scrollTop = mainDiv.scrollHeight - mainDiv.clientHeight;
}
//建立连接functionconnect(){var http_request;
if (window.XMLHttpRequest){
http_request = new XMLHttpRequest();
if (http_request.overrideMimeType){
http_request.overrideMimeType('text/xml');
}
} elseif (window.ActiveXObject) {
try {
http_request = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e){
try {
http_request = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e){}
}
}
http_request.open('GET', "http://localhost/websocket/server.php", true);
http_request.send();
socket = new WebSocket("ws://localhost:9000/websocket/server.php");
socket.onopen = open; //绑定成功打开后触发的函数
socket.onmessage = recMessage; //绑定接受到数据后的处理函数
socket.onerror = error; //绑定处理错误的函数
socket.onclose = close; //绑定连接关闭后的处理函数
}
//连接成功functionopen(){var i = document.getElementsByTagName('i');
i[0].innerHTML = '连接成功!';
button.disabled = '';
}
//出错functionerror(){var i = document.getElementsByTagName('i');
i[0].style.color = "#FF0000";
i[0].innerHTML = '连接失败';
button.disabled = 'disabled';
}
//接受到数据functionrecMessage(e){var data = JSON.parse(e.data);
showMsg(data.message, 1);
}
//连接关闭functionclose(){
button.disabled = 'disabled';
if (confirm('连接已关闭,是否需要再次连接?')){
connect();
}
}
php服务端代码,已封装成类
namespaceMyLab;
classWebSocket{private$host;
private$port;
function__construct($port, $host)
{$this->host = $host;
$this->port = $port;
}
//启动服务functionStartServer(){$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);//创建socket
socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);
socket_bind($socket, 0, $this->port);
socket_listen($socket);//开启监听$sockets = array($socket);
$write = NULL;
$except = NULL;
while (true)
{
$clients = $sockets;
$num = socket_select($clients, $write, $except, 0);
if ($num === false){
echo"socket_select failed!";
break;
}
if (in_array($socket, $clients))
{
$socket_new = socket_accept($socket); //接受连接$sockets[] = $socket_new; //保存连接$header = socket_read($socket_new, 1024);
$status = $this->handshaking($header, $socket_new, $this->host, $this->port);
$response = $this->code(json_encode(array('message'=>'欢迎来到Chat with yourself')));
$status = $this->sendMessage($response, $socket_new);//首次连接上之后回应$found_socket = array_search($socket, $clients);
unset($clients[$found_socket]);
}
foreach ($clientsas$client) //遍历连接,处理接受到的消息
{
while (socket_recv($client, $buf, 1024, 0) >= 1)
{
$received_text = $this->decode($buf);
$decode_text = json_decode($received_text);
$user_name = $decode_text->name;
$user_message = $decode_text->message;
$response_text = $this->code(json_encode(array('type' => 'usermsg', 'name' => $user_name, 'message' => $user_message)));
$this->sendMessage($response_text, $client);
break2;
}
}
}
}
//握手验证functionhandshaking($receved_header,$client_conn, $host, $port)
{$headers = array();
$lines = preg_split("/\r\n/", $receved_header);
foreach($linesas$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));
return$upgrade;
}
//解码functiondecode($str)
{$length = ord($str[1]) & 127;
if ($length == 126)
{
$masks = substr($str, 4, 4);
$data = substr($str, 8);
}
elseif ($length == 127) {
$masks = substr($str, 10, 4);
$data = substr($str, 14);
}
else {
$masks = substr($str, 2, 4);
$data = substr($str, 6);
}
$str = '';
for ($i = 0; $i $data); ++$i)
{
$str .= $data[$i] ^ $masks[$i % 4];
}
return$str;
}
//发送消息functionsendMessage($msg, $cilent)
{try{
return socket_write($cilent, $msg, strlen($msg));
}
catch (\Exception$e){
return$e;
}
}
//编码functioncode($str)
{$b1 = 0x80 | (0x1 & 0x0f);
$length = strlen($str);
if ($length 125)
$header = pack('CC', $b1, $length);
elseif ($length >125 && $length 65536
推荐阅读
-
Python使用pandas处理CSV文件的实例讲解
-
Python ORM框架SQLAlchemy学习笔记之数据添加和事务回滚介绍
-
vue-cli 使用vue-bus来全局控制的实例讲解
-
Python使用新浪微博API发送微博的例子
-
使用pandas模块读取csv文件和excel表格,并用matplotlib画图的方法
-
pycharm 使用心得(一)安装和首次使用
-
vue 使用自定义指令实现表单校验的方法
-
pycharm 使用心得(九)解决No Python interpreter selected的问题
-
python网络编程学习笔记(10):webpy框架
-
在Vue 中使用Typescript的示例代码