Websocket通信实战项目(js)(图片互传应用)(下)客户端H5+css+js实现

news2024/11/23 15:42:20

                               
  Rqtz : 个人主页
   共享IT之美,共创机器未来    
  Sharing the Beauty of IT and Creating the Future of Machines Together


目录

 

起始 

客户端GUI

Javascripts连接websocket

使用localStorage保存用户输入的IP

Websocket连接成功

Websocket接收数据

解析发来的图片二进制数据

根据字节头判断文件格式

根据图片二进制数据在前端显示图片

websocket连接关闭

webscoket连接错误

整体代码

websocket发送图片数据

选择文件

读取文件

保存发来的图片

webocket断开连接

整体代码框架

最后


 

起始 

         基于上篇文章,我介绍了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');
  1. socket 定义为一个全局变量,创建一个新的WebSocket对象
  2. 'ws://': 这是WebSocket协议的前缀,表示这是一个WebSocket连接。

  3. ip: 这是一个变量,表示WebSocket服务器的IP地址,他通过一个输入框的value获取。

  4. ':8899': 这是WebSocket服务器监听的端口号。在这个例子中,端口号是8899。你可以根据实际情况更改端口号。

  5. '/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 = "通信运行中";

            });
  1. 通过向socket添加一个open事件,监听websocket的是否连接成功
  2. dataval 是一哦个textarea 用于输出相关信息
  3. fengche 是指连接成功后,小风车会有一个旋转动画
  4. 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";
    }
   
}
  1. Blob对象 定义: Blob对象是JavaScript中的一个内置对象,用于处理二进制数据。它表示一段不可变的原始数据,可以存储大量的二进制数据,如图像、音频、视频等。
  2. event.data        这里的event.data是一个Blob对象,因为服务器端发来的数据是一个图片的二进制数据,所以event.data是一个Blob对象;如果服务器发来的是文本数据,那么event.data是一个字符串。
  3. FileReader读取文件  以下是FileReader的一些常用方法:

    1. readAsArrayBuffer(blob):以ArrayBuffer的形式读取指定的Blob或File对象。
    2. readAsBinaryString(blob):以二进制字符串的形式读取指定的Blob或File对象。
    3. readAsDataURL(blob):以数据URL的形式读取指定的Blob或File对象。
    4. 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;
            }
  1. 使用createObjectURL方法将当前的blob对象,也就是图片的二进制数据转为URL格式,目的是将其设置到img标签的src属性来显示图片
  2. currimagedata是一个image对象 , 定义为var currimagedata = new Image()
  3. currimagedata.onload = function()

    是一个事件处理函数,在图像数据读取完成后触发

  4. 图片读取完成后,通过其widthheight以及blob(rece_picblob)对象的size方法,将图片的详细数据设置到数据框中.
  5. 等比缩放 使用一个变量读取完数据后,pthots是个img标签scale缩放倍数,初始值为2.5,可以根据select标签选择,最后再将缩放后的宽高数据,设置为图片标签的src属性,这样就达到了先获取图片原始数据,在将缩放后数据设置为图片。
  6. 缩放倍数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的小项目,可能有写的不好的地方,如有错误请大佬及时批评指正,小弟感激不尽!

7f1ef757c074450595905c3a5ab92b2f.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1894126.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

51-5 权限维持2 - 影子账号(隐藏用户)

权限维持技术 权限维持技术(Persistence,也称为权限持久化)是一种能够在系统重启、用户更改密码或其他可能导致访问中断的情况下保持对系统访问的技术。例如,它包括创建系统服务、利用计划任务、修改系统启动项或注册表、以及映像劫持等方法。 创建影子账户 影子账户是指隐…

Labview_Workers5.0 学习笔记

1.Local Request 个人理解该类型的请求针对自身的&#xff0c;由EHL或者MHL到该vi的MHL中。 使用快速放置快捷键"Ctrl9"创建方法如下&#xff1a; 创建后的API接口命名均为rql开头&#xff0c;并且在所选main.vi中的MHL创建对应的条件分支。 此时使用该API函数就…

【计算机毕业设计】026基于微信小程序的原创音乐

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

行业模板|DataEase旅游行业大屏模板推荐

DataEase开源数据可视化分析工具于2022年6月发布模板市场&#xff08;https://templates-de.fit2cloud.com&#xff09;&#xff0c;并于2024年1月新增适用于DataEase v2版本的模板分类。模板市场旨在为DataEase用户提供专业、美观、拿来即用的大屏模板&#xff0c;方便用户根据…

SpringBoot 启动流程二

SpringBoot启动流程二 我们首先查看构造方法 SpringApplication 我们发现这个构造方法还是在SpringApplication类里面 这个构造方法还是调用了自身的构造方法 传入了两个参数 第一个参数叫resourceLoader 传入的是一个资源加载器 要从外部读入东西 这个方法通过this关键字…

番外篇 | YOLOv8改进之即插即用全维度动态卷积ODConv + 更换Neck网络为GFPN

前言:Hello大家好,我是小哥谈。本文所做出的改进是在YOLOv8中引入即插即用全维度动态卷积ODConv和更换Neck网络为GFPN,希望大家学习之后能够有所收获~!🌈 目录 🚀1.基础概念 🚀2.网络结构 🚀3.添加步骤 🚀4.改进方法 🍀🍀步骤1:block.py文件修改…

【Android面试八股文】你是怎么保证Android设备的时间与服务器时间同步的?(使用NTP和TrueTime方案)

文章目录 一、网络时间协议(NTP)二、使用网络时间协议(NTP)2.1 使用系统提供的 NTP 服务器2.2 使用TrueTime2.2.1 引入TrueTime库2.2.2 初始化 TrueTime2.2.3 用法2.2.4 使用 TrueTime 获取时间2.2.4 自动更新时间2.2.5 注意事项二. 使用 HTTP 请求获取服务器时间2.1. 发送…

技术探索:利用Python库wxauto实现Windows微信客户端的全面自动化管理

项目地址&#xff1a;github-wxauto 点击即可访问 项目官网&#xff1a;wxauto 点击即可访问 &#x1f602;什么是wxauto? wxauto 是作者在2020年开发的一个基于 UIAutomation 的开源 Python 微信自动化库&#xff0c;最初只是一个简单的脚本&#xff0c;只能获取消息和发送…

同方威视受邀盛装亮相2024长三角快递物流展(杭州)助力行业物畅其流

同方威视技术股份有限公司携安全检测产品和综合解决方案&#xff0c;盛装亮相2024长三角快递物流展&#xff08;杭州&#xff09; 展位号&#xff1a;3C馆A07-1 时间&#xff1a;2024年7月8-10日 地址&#xff1a;杭州国际博览中心&#xff08;浙江省杭州市萧山区奔竞大道35…

【路由交换技术】Cisco Packet Tracer基础入门教程(五)

这一期我们来学习端口聚合&#xff0c;这是针对交换机的技术 前言 不知道大家有没有注意到&#xff0c;我们之前的实验在交换机与交换机之间只用一条线连接&#xff0c;像这样 通过今天的学习&#xff0c;我们要用两条线来连接交换机&#xff0c;就像这样&#xff08;为了能…

球形气膜:现代娱乐场馆的最佳选择—轻空间

随着科技的发展和人们对高品质生活的追求&#xff0c;娱乐场馆的建设迎来了新的变革。球形气膜结构凭借其独特的优势&#xff0c;逐渐成为现代娱乐场馆建设的最佳选择。轻空间将介绍球形气膜的优势&#xff0c;并探讨其在不同应用场景中的广泛应用。 球形气膜的优势 1. 独特的建…

Kotlin和Java的一些不同点

1.Kotlin 的变量是没有默认值的&#xff08;因此要求初始化&#xff09;&#xff0c;Java的成员变量是有默认值的 Java的成员变量&#xff1a; String name; // 默认值是 null int count; // 默认值是 0不过其实 Java 也只是成员变量有默认值&#xff0c;局部变量也是没有默…

以品质为初心,以创新为驱动,光明乳业闪耀第十五届中国奶业大会

2024年7月3日&#xff0c;以“数智赋能引领产业发展增长点&#xff0c;科技创新驱动奶业新质生产力”为主题的中国奶业协会第十五届奶业大会奶业20强&#xff08;D20&#xff09;论坛暨2024中国奶业展览会隆重召开&#xff0c;光明乳业党委书记、董事长黄黎明受邀出席会议&…

Linux 压测工具---ab

安装 yum -y install httpd-tools 本文用于压测k8s集群内pod&#xff0c;k8s集群master可直接测试pod ip 命令&#xff1a; ab -n 10000 -c 100 http://10.42.8.212/ 其中&#xff0c;-n表示请求数&#xff0c;-c表示并发数&#xff0c;ip必须有”/“&#xff0c;表示此目录…

如何清理电脑内存?让电脑运行如飞!

电脑内存&#xff08;RAM&#xff09;的清理对于维持系统的流畅运行至关重要。随着使用时间的增加&#xff0c;系统内存会被各种应用程序和后台进程占用&#xff0c;导致系统响应变慢&#xff0c;甚至出现卡顿现象。通过有效地清理内存&#xff0c;可以提升电脑的性能&#xff…

5.基于SpringBoot的SSMP整合案例-数据层开发

目录 1.新建项目 2.实体类开发&#xff1a; 2.1在pom.xml中增加Lombok坐标&#xff1a; 2.2添加Book实体类 3.数据层开发&#xff1a; 3.1 配置MyBatisPlus与Druid 3.2创建数据层接口 3.3写测试类 3.4点击运行&#xff1a; 4.数据层快速开发&#xff1a; 4.1配置MyB…

【数据结构】02.顺序表

一、顺序表的概念与结构 1.1线性表 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有限序列。线性表是⼀种在实际中广泛使用的数据结构&#xff0c;常见的线性表&#xff1a;顺序表、链表、栈、队列、字符串… 线性表在逻辑上是线性结构&#xff0…

HighConcurrencyCommFramework c++通讯服务器框架 :简介-信号处理

项目是4月份左右做的现在整理到博客上&#xff0c;顺便加深一下印象 介绍 项目描述:该项目是使用 C 实现的高并发服务器脚手架&#xff0c;包含线程池和连接池等技术&#xff0c;支持开发者进行二次开发复用&#xff0c;只需 要添加对应业务逻辑即可完成通信服务器、网络交易…

【Termius】详细说明MacOS中的SSH的客户端利器Termius

希望文章能给到你启发和灵感~ 如果觉得有帮助的话,点赞+关注+收藏支持一下博主哦~ 阅读指南 开篇说明一、基础环境说明1.1 硬件环境1.2 软件环境二、软件的安装2.1 Termius界面介绍2.1.1 Hosts 主机列表2.1.2 SFTP 文件传输2.1.3 Port ForWarding 端口转发2.1.4 Snippets 片…

afrog-漏洞扫描(挖洞)工具【了解安装使用详细】

★★免责声明★★ 文章中涉及的程序(方法)可能带有攻击性&#xff0c;仅供安全研究与学习之用&#xff0c;读者将信息做其他用途&#xff0c;由Ta承担全部法律及连带责任&#xff0c;文章作者不承担任何法律及连带责任。 1、afrog介绍 afrog 是一款性能卓越、快速稳定、PoC可定…