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

                               
  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;//转换为uint8Arrayconst 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;//转换为uint8Arrayconst 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.mzph.cn/pingmian/40667.shtml

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

相关文章

MySQL InnoDB Cluster 高可用集群部署

MySQL InnoDB Cluster 简介 官方文档&#xff1a;https://dev.mysql.com/doc/refman/8.4/en/mysql-innodb-cluster-introduction.html 本章介绍 MySQL InnoDB Cluster&#xff0c;它结合了 MySQL 技术&#xff0c;使您能够部署和管理完整的 MySQL 集成高可用性解决方案。 说…

科普文:Linux服务器性能调优之CPU调度策略和可调参数

概叙 进程 进程是操作系统虚拟出来的概念&#xff0c;用来组织计算机中的任务。计算机的核心是CPU&#xff0c;它承担了所有的计算任务&#xff1b;而操作系统是计算机的管理者&#xff0c;它负责任务的调度、资源的分配和管理&#xff0c;统领整个计算机硬件&#xff1b;应用…

网络编程:UDP编程笔记

1.字节序的概念和转换 小端格式: 低位字节数据存储在低地址 大端格式: 高位字节数据存储在低地址 在主机上时为小端存储,在网络上时为大端,所以接收到数据时,要转为小端口 如下图: #include <arpa/inet.h> 发送者调用的函数: uint32_t htonl(uint32_t hostlong); //转…

【信息学奥赛】CSP-J/S初赛06 算法基础及时间/空间复杂度等问题

本专栏&#x1f449;CSP-J/S初赛内容主要讲解信息学奥赛的初赛内容&#xff0c;包含计算机基础、初赛常考的C程序和算法以及数据结构&#xff0c;并收集了近年真题以作参考。 如果你想参加信息学奥赛&#xff0c;但之前没有太多C基础&#xff0c;请点击&#x1f449;专栏&#…

AI与学术的交响:ChatGPT辅助下的实验设计新篇章

学境思源&#xff0c;一键生成论文初稿&#xff1a; AcademicIdeas - 学境思源AI论文写作 在学术研究中&#xff0c;实验设计是确保研究质量和结果可信度的关键环节。这篇文章我们将为大家介绍如何利用ChatGPT辅助完成学术论文的实验设计&#xff0c;通过提供灵感、优化实验步…

VUE Pinia状态持久化

效果 实现方法 插件&#xff1a;pinia-plugin-persistedstate 链接地址 具体操作 安装 npm i pinia-plugin-persistedstate 添加到 pinia 实例上 import { createPinia } from pinia import piniaPluginPersistedstate from pinia-plugin-persistedstateconst pinia cre…

K8s 集群(kubeadm) CA 证书过期解决方案

Author&#xff1a;Arsen Date&#xff1a;2024/07/04 目录 一、现象描述二、解决方案三、集群验证 一、现象描述 之前有篇文章《K8s Token 过期解决方案&#xff08;Kubeadm&#xff09;》提到了默认生成的 Token 有效期只有 24 小时&#xff0c;过期后 Token 将不可用&#…

B端系统设计风格简洁与高效的完美融合

B端系统设计风格简洁与高效的完美融合

CIDEr(Consensus-based Image Description Evaluation)的计算

CIDEr&#xff08;Consensus-based Image Description Evaluation&#xff09; 论文原文 CIDEr: Consensus-based Image Description Evaluation CIDEr&#xff08;Consensus-based Image Description Evaluation&#xff09;是一种用于自动评估图像描述&#xff08;image ca…

基于java语言+ Vue+ElementUI+ MySQL8.0.36数字化产科管理平台源码,妇幼信息化整体解决方案

基于java语言 VueElementUI MySQL8.0.36数字化产科管理平台源码&#xff0c;妇幼信息化整体解决方案 数字化产科管理平台是为医院产科量身定制的信息管理系统。它管理了孕妇从怀孕开始到生产结束42天一系列医院保健服务信息。该系统由门诊系统、住院系统、数据统计模块三部分组…

web零碎知识

&nbsp 在html文件中 连续的空格会被认为是一个空格 所以我们需要使用&nbsp来代表空格 &#x3000 把这个当成tab键来使用 我们可以引入js文件&#xff0c;就可以减少html文件的长度。 首先创建一个js文件夹&#xff0c;然后在js文件夹中创建一个&#xff0c;后缀…

数据库表导出到excel:前置知识4 业务和效果

清单配置页面(就是配置那些用户可以下载那些表内容,清单下载实际就是指数据库表下载,清单就是对应的表) 比如:导出一个atom_base_info表数据(数据多) atom_base_info的数据结构 下面这个配置审核状态一类不问&#xff0c;直接到清单下载页面 发起自己想下载的清单(先异步把数…

FreeRTOS之队列上锁和解锁(详解)

这篇文章将记录我学习实时操作系统FreeRTOS的队列上锁和解锁的知识&#xff0c;在此分享给大家&#xff0c;希望我的分享能给你带来不一样的收获&#xff01; 目录 一、简介 二、队列上锁函数prvLockQueue&#xff08;&#xff09; 1、函数初探 2、应用示例 三、队列解锁函…

js之模糊搜索

多的不说 少的不唠 直接上代码

警翼警用记录仪视频格式化后恢复方法

警翼是国内较大的一家警用记录仪厂商&#xff0c;此品牌我们恢复过很多&#xff0c;此次遇到的是一个典型的误格式化的情况&#xff0c;我们来看看误格式化后如何恢复。 故障存储: 32G卡/fat32 故障现象: 客户提供的信息是在交接设备后没有及时备份而做出了初始化设备的操…

养老院管理系统-计算机毕业设计源码00010

养老院管理系统的设计与实现 摘要 本文介绍了一种基于Spring Boot框架的养老院管理系统的设计与实现。该系统旨在帮助养老院管理者更有效地管理机构内的各项事务&#xff0c;并提供更好的服务于老年人。系统的设计考虑了养老院管理的特殊需求&#xff0c;包括系统用户、老人信息…

高二的他已通过NOI保送北大了,让我们一起了解他的信息学奥赛学习经历吧!!!

相信关注本号的各位&#xff0c;对于信息学奥赛已经不陌生了&#xff0c;部分同学也已经开始踏入信息学的旅程&#xff0c;但前路茫茫&#xff0c;让我们一起看看已经取得成就的同学的经历吧。 今天要介绍的这位同学&#xff0c;是来自深圳中学的高二某班的欧阳达晟同学&#x…

简洁纯文字类的Typecho主题wenso

主题介绍 文章说说类博客网站源码&#xff0c;页面清新简洁。适合文章说说美文博客网站建站使用&#xff0c;响应式手机版本。 本来是dedecms的模板&#xff0c;也比较简单&#xff0c;适合用来搭建一个文学类的&#xff0c;纯文字的网站&#xff0c;简单的改成了typecho&…

JVM 堆内存结构 年轻代 老年代

堆内存 内存划分 对于大多数应用&#xff0c;Java 堆是 Java 虚拟机管理的内存中最大的一块&#xff0c;被所有线程共享。此内存区域的唯一目的就是存放对象实例&#xff0c;几乎所有的对象实例以及数据都在这里分配内存。 为了进行高效的垃圾回收&#xff0c;虚拟机把堆内存…