Rqtz : 个人主页
共享IT之美,共创机器未来
Sharing the Beauty of IT and Creating the Future of Machines Together
目录
起始
基于上篇文章,我介绍了websocket图传软件服务器端实现,那么本篇文章要介绍的是websocket的客户端实现 ,主要使用javascripts来实现通信部分和后端逻辑,前端h5+css来实现,为什么用javascripts呢?因为主要是为了能在安卓平台使用,由于不会安卓开发,哈哈,能力有限,只能用javascripts在浏览器上用了,虽然兼容不太好,但毕竟是个小练习吧,正好练习以下javacsripts语法.
服务器端实现请看Websocket通信实战项目(图片互传应用)+PyQt界面+python异步编程(async) (上)服务器端python实现-CSDN博客
客户端GUI
动图展示
视频 图片互传-CSDN直播
Javascripts连接websocket
var socket;
socket = new WebSocket('ws://'+ip+':8899/handler');
- socket 定义为一个全局变量,创建一个新的WebSocket对象
'ws://'
: 这是WebSocket协议的前缀,表示这是一个WebSocket连接。
ip
: 这是一个变量,表示WebSocket服务器的IP地址,他通过一个输入框的value获取。
':8899'
: 这是WebSocket服务器监听的端口号。在这个例子中,端口号是8899。你可以根据实际情况更改端口号。
'/handler'
: 这是WebSocket服务器上的特定路径,通常用于处理客户端发送的消息。在这个例子中,路径是/handler
。如上篇文章的handler。
使用localStorage保存用户输入的IP
定义 :
localStorage
是 Web Storage API 的一部分,它允许网页在用户的浏览器上存储键值对数据。这些数据会持久存在,即使用户关闭浏览器或重启电脑,数据也不会丢失。- 方法一 localStorage.setItem(键, 值); 设置键值对
- 方法二 value=localStorage.getItem("键");通过访问键,进而得到其值存储到变量
代码示例
if(localStorage.getItem("ipaddress"))
ipaddr.value=localStorage.getItem("ipaddress");
//使用localstorage设置默认IP地址
const moren = document.getElementById("moren");
moren.addEventListener("click",function(){
if(ipaddr.value=="")
alert("请输入IP地址");
else
{
localStorage.setItem("ipaddress", ipaddr.value);
alert("设置成功");
}
});
Websocket连接成功
socket.addEventListener('open', (event) => {
dataval.value += 'WebSocket连接成功!\n';
fengche.style.animation = 'fengche 2s linear infinite';
commuction.innerHTML = "通信运行中";
});
- 通过向socket添加一个open事件,监听websocket的是否连接成功
- dataval 是一哦个textarea 用于输出相关信息
- fengche 是指连接成功后,小风车会有一个旋转动画
- commuction 修改通信状态。
Websocket接收数据
socket.addEventListener('message', (event) => {
dataval.value+='图片接收成功\n';
});
通过向socket添加一个message事件,监听websocket的发数据事件
解析发来的图片二进制数据
dataval.value+='图片接收成功\n';
//将blob对象赋值给变量
rece_picblob = event.data;
const reader = new FileReader();
//以arraybutter的形式读取blob数据
reader.readAsArrayBuffer(event.data);
reader.onloadend = function() {
//获取blob的arraybuffer对象
const arraybuffer = this.result;
//转换为uint8Array
const uint8Array = new Uint8Array(arraybuffer);
// 检查前两个字节是否符合 JPG 文件的特征
if (uint8Array[0] === 0xFF && uint8Array[1] === 0xD8) {
jpgflag = true;
type.value = "image/jpg";
}
// 检查前两个字节是否符合 PNG 文件的特征
else if (uint8Array[0] === 0x89 && uint8Array[1] === 0x50) {
pngflag = true;
type.value = "image/png";
}
else if (uint8Array[0] === 0x42 && uint8Array[1] === 0x4D) {
bmpflag = true;
type.value = "image/bmp";
}
}
- Blob对象 定义: Blob对象是JavaScript中的一个内置对象,用于处理二进制数据。它表示一段不可变的原始数据,可以存储大量的二进制数据,如图像、音频、视频等。
- event.data 这里的event.data是一个Blob对象,因为服务器端发来的数据是一个图片的二进制数据,所以event.data是一个Blob对象;如果服务器发来的是文本数据,那么event.data是一个字符串。
FileReader读取文件 以下是FileReader的一些常用方法:
- readAsArrayBuffer(blob):以ArrayBuffer的形式读取指定的Blob或File对象。
- readAsBinaryString(blob):以二进制字符串的形式读取指定的Blob或File对象。
- readAsDataURL(blob):以数据URL的形式读取指定的Blob或File对象。
- readAsText(blob, encoding):以文本的形式读取指定的Blob或File对象,可以指定字符编码。
根据字节头判断文件格式
const uint8Array = new Uint8Array(arraybuffer);
将 ArrayBuffer 转换为 Uint8Array
JPG,PNG,BMP文件格式在其二进制两个字节的体现
image/jpg : 0xFF 0xD8
image/png : 0x89 0x50
image/bmp: 0x42 0x4D
根据图片二进制数据在前端显示图片
效果
//读取URL,赋值给image的src属性,显示图片
const url = URL.createObjectURL(event.data);
//将URL存入到其中的src属性
currimagedata.src = url;
//图片读取完成后,计算相关属性
currimagedata.onload = function() {
var width = currimagedata.width;
var height = currimagedata.height;
px.value = width+"x"+height+"px";
ram.value = rece_picblob.size+"字节";
nameval.value = "";
//scale倍缩放
photos.width = currimagedata.width / scale;
photos.height = currimagedata.height / scale;
photos.src = url;
}
- 使用createObjectURL方法将当前的blob对象,也就是图片的二进制数据转为URL格式,目的是将其设置到img标签的src属性来显示图片。
- currimagedata是一个image对象 , 定义为var currimagedata = new Image()
currimagedata.onload = function()
是一个事件处理函数,在图像数据读取完成后触发
- 图片读取完成后,通过其width,height以及blob(rece_picblob)对象的size方法,将图片的详细数据设置到数据框中.
- 等比缩放 使用一个变量读取完数据后,pthots是个img标签,scale缩放倍数,初始值为2.5,可以根据select标签选择,最后再将缩放后的宽高数据,设置为图片标签的src属性,这样就达到了先获取图片原始数据,在将缩放后数据设置为图片。
- 缩放倍数html
<select id="selectment"> <option value="option1">2.5</option> <option value="option2">1.5</option> <option value="option3">0.5</option> </select>
Javascripts
//选择缩放倍数 const select = document.getElementById("selectment") select.addEventListener("change",function(){ if(select.value == "option1"){scale = 2.5;photos.width = currimagedata.width / scale;photos.height = currimagedata.height / scale;} else if(select.value == "option2"){scale = 1.5;photos.width = currimagedata.width / scale;photos.height = currimagedata.height / scale;} else if(select.value == "option3"){scale = 0.5;photos.width = currimagedata.width / scale;photos.height = currimagedata.height / scale;} });
websocket连接关闭
//连接关闭,小风车转起来
socket.addEventListener('close', (event) => {
dataval.value += 'WebSocket连接关闭\n';
fengche.style.animation = 'fengche 2s linear';
commuction.innerHTML = "通信关闭中";
});
webscoket连接错误
socket.addEventListener('error', (event) => {
dataval.value +='WebSocket错误:'+ event.data+"\n";
});
整体代码
WebSocketbtn.addEventListener("click",function(){
console.log(ip)
if(ipaddr.value =="" || ip == "" )
alert("请输入IP地址或绑定ip");
else
{
socket = new WebSocket('ws://'+ip+':8899/handler');
//连接成功,小风车转起来
socket.addEventListener('open', (event) => {
dataval.value += 'WebSocket连接成功!\n';
fengche.style.animation = 'fengche 2s linear infinite';
commuction.innerHTML = "通信运行中";
});
//接收服务器发来的图片数据
socket.addEventListener('message', (event) => {
dataval.value+='图片接收成功\n';
//将blob对象赋值给变量
rece_picblob = event.data;
const reader = new FileReader();
//以arraybutter的形式读取blob数据
reader.readAsArrayBuffer(event.data);
reader.onloadend = function() {
//获取blob的arraybuffer对象
const arraybuffer = this.result;
//转换为uint8Array
const uint8Array = new Uint8Array(arraybuffer);
console.log(uint8Array)
// 检查前两个字节是否符合 JPG 文件的特征
if (uint8Array[0] === 0xFF && uint8Array[1] === 0xD8) {
jpgflag = true;
type.value = "image/jpg";
}
// 检查前两个字节是否符合 PNG 文件的特征
else if (uint8Array[0] === 0x89 && uint8Array[1] === 0x50) {
pngflag = true;
type.value = "image/png";
}
else if (uint8Array[0] === 0x42 && uint8Array[1] === 0x4D) {
bmpflag = true;
type.value = "image/bmp";
}
}
//读取URL,赋值给image的src属性,显示图片
const url = URL.createObjectURL(event.data);
//将URL存入到其中的src属性
currimagedata.src = url;
//图片读取完成后,计算相关属性
currimagedata.onload = function() {
var width = currimagedata.width;
var height = currimagedata.height;
px.value = width+"x"+height+"px";
ram.value = rece_picblob.size+"字节";
nameval.value = "";
//scale倍缩放
photos.width = currimagedata.width / scale;
photos.height = currimagedata.height / scale;
photos.src = url;
}
});
//连接关闭,小风车转起来
socket.addEventListener('close', (event) => {
dataval.value += 'WebSocket连接关闭\n';
fengche.style.animation = 'fengche 2s linear';
commuction.innerHTML = "通信关闭中";
});
//连接错误
socket.addEventListener('error', (event) => {
dataval.value +='WebSocket错误:'+ event.data+"\n";
});
}
});
websocket发送图片数据
选择文件
//选择文件,单击div连接到file类型input
selfilebtn.addEventListener("click",function(){
document.getElementById("fileinput").click();
});
通过给div设置点击事件,并且连接到input文件选择框,这个div指的是发送图片的那个圆角矩形。
读取文件
//读取文件
fileInput.addEventListener('change',function(event){
const files = event.target.files;
var file = files[0];
if(file.size>7000000)
alert("图片文件不能超过7MB")
else
{
//将文件信息显示在输入框
ram.value = file.size+"字节";
nameval.value = file.name;
type.value = file.type;
//创建读文件对象
const reader = new FileReader();
const reader2 = new FileReader();
//读取文件内容,二进制格式
reader.readAsArrayBuffer(file);
//读取文件内容,URL格式
reader2.readAsDataURL(file);
//二进制格式读取完成后触发
reader.onload = function(e) {
//获取文件内容
const filedata = e.target.result;
// console.log(filedata)
//发送消息
sendMessage(filedata);
};
//URL格式读取完成后触发
reader2.onload = function(e) {
const picdata = e.target.result;
//创建一个图像对象
//将URL存入到其中的src属性
currimagedata.src = picdata;
//图片读取完成后
currimagedata.onload = function() {
var width = currimagedata.width;
var height = currimagedata.height;
px.value = width+"x"+height+"px";
//scale倍缩放
photos.width = currimagedata.width / scale;
photos.height = currimagedata.height / scale;
photos.src = picdata;
}
}
}
- 监听input文件输入框的change事件
var file = files[0];
由于文件是单选的,所以就之选取了选择的第一个文件。
获取文件属性
file.size 文件大小 (字节)
file.name 文件名称
file.type 文件类型
file.width 图片宽度
file.height 图片高度
reader.onload = function(e) { //获取文件内容 const filedata = e.target.result; // console.log(filedata) //发送消息 sendMessage(filedata); };
等待读取完成后,将二进制数据发送
sendmessage函数实现
//websocket发送消息函数 function sendMessage(message) { socket.send(message); dataval.value+="图片发送成功!\n"; };
其实就是使用websocket对象socket使用send方法发送。
保存发来的图片
//保存图片
sendpic.addEventListener("click",function(){
if(rece_picblob.size == 0)
alert("当前没有受到服务器发来的任何数据")
else
{
if(pngflag)
{
saveAs(rece_picblob,"output.png");
pngflag = false;
}
else if(jpgflag)
{
saveAs(rece_picblob,"output.jpg");
jpgflag = false;
}
else if(bmpflag)
{
saveAs(rece_picblob,"output.bmp");
bmpflag = false;
}
dataval.value+='图片保存成功\n';
}
});
根据不同的图片格式保存相应的图片。
但是在电脑端测试的时候,保存图片就会刷新页面,手机就不会,可是我并没有写刷新页面的代码,这个bug就很奇怪。
其中saveAs()方法,使用的是FileSaver.js,在html中引入
<script src="https://cdn.bootcdn.net/ajax/libs/FileSaver.js/2.0.5/FileSaver.js"></script>
使用saveAs()方法
- 参数1:是一个Blob对象,这里是图片的二进制数据
- 参数2:是保存的文件名,这里是output.png/jpg/bmp
webocket断开连接
disWebSocketbtn.addEventListener('click',function(){
socket.close();
});
整体代码框架
最后
由于这个项目是小弟初次接触websocket的小项目,可能有写的不好的地方,如有错误请大佬及时批评指正,小弟感激不尽!