php做的卖水果网站有哪些拓者设计吧官网app
- 作者: 多梦笔记
- 时间: 2026年02月17日 16:56
当前位置: 首页 > news >正文
php做的卖水果网站有哪些,拓者设计吧官网app,社区网站建设费用,php 网站 下载1、什么是WebSocket?
websocket的目标是通过一个长连接实现与服务器全双工#xff0c;双向的通信。是一种在单个TCP连接上进行全双工通信的协议#xff0c;使得客户端和服务器之间的数据交换变得更加简单#xff0c;允许服务端主动向客户端推送数据。在 js中创建websocket…1、什么是WebSocket?
websocket的目标是通过一个长连接实现与服务器全双工双向的通信。是一种在单个TCP连接上进行全双工通信的协议使得客户端和服务器之间的数据交换变得更加简单允许服务端主动向客户端推送数据。在 js中创建websocket时一个http请求会发送到服务器初始化连接服务器响应后连接使用http的upgrade头部从http协议切换到websocket协议这意味着websocket不能通过标准的http服务器完成而必须使用支持websocket协议的专有服务器。因为websocket使用了自定义协议所以url方案稍有变化不能再使用http://或https://而要使用我是ws://和wss://。前者是不安全的连接后者是安全的。
优点缺点基于TCP协议 WebSocket建立在TCP之上这使得服务器端的实现相对容易。安全性WebSocket 使用的是持久性连接连接建立后会长时间保持打开状态。会增加服务器资源的消耗WebSocket 协议的双向通信机制它可能会面临安全隐患例如 XSS 和 CSRF 攻击等。与HTTP兼容性良好 WebSocket与HTTP协议兼容使用HTTP协议进行握手阶段因此默认端口与HTTP相同80和443且不易被屏蔽。这意味着它可以通过各种HTTP代理服务器增加了通信的灵活性。浏览器兼容性旧版浏览器中可能会出现兼容性问题。轻量级数据格式和高效通信 在连接创建后持久保存连接状态并且交换数据时用于协议控制的数据包头部相对较小数据包大小的限制 WebSocket 协议发送的数据包不能超过 2GB。支持文本和二进制数据WebSocket不仅可以发送文本数据还可以发送二进制数据相对 HTTP可以更轻松地处理二进制内容。服务器需求 WebSocket 协议需要服务器支持这意味着需要更高效的服务器硬件和软件。无同源限制与传统的AJAX请求不同WebSocket没有同源限制客户端可以与任意服务器通信不需要处理跨域
2、怎么理解WebSocket可以用在什么场景?
首先我们思考一个问题当前端需要展示实时数据或实现实时聊天功能我们怎么设计数据请求方案 按照传统的解决方法就是利用轮询和长轮询的方案现在我们来对比一下这三种方案的异同
轮询长轮询websocket方案思路客户端定时向服务器发送Ajax请求服务器接到请求后马上返回响应信息并关闭连接客户端向服务器发送Ajax请求服务器接到请求后hold住连接直到有新消息才返回响应信息并关闭连接客户端处理完响应信息后再向服务器发送新的请求客户端向服务器发起websocket请求建立全双工通信连接一旦服务器有数据更新服务器可以主动给客户端发送数据无需客户端询问优缺点对比后端程序编写比较容易但是请求中有大半是无用浪费带宽和服务器资源在无消息的情况下不会频繁的请求但是服务器hold连接会消耗资源轻量级数据格式和高效通信支持文本和二进制数据无同源限制但是旧版浏览器中可能会出现兼容性问题 WebSocket 协议发送的数据包不能超过 2GB
3、WebSocket对象详解
3-1、websocket() 构造函器会返回一个 WebSocket 对象。 var aWebSocket new WebSocket(url [, protocols]);
参数名称是否必填释义url是要连接的 URL这应该是 WebSocket 服务器将响应的 URL。protocol否一个人类可读的字符串它解释了连接关闭的原因。这个 UTF-8 编码的字符串不能超过 123 个字节。
3-2、api WebSocket.close() 关闭 WebSocket 连接或连接尝试如果有的话。如果连接已经关闭则此方法不执行任何操作;
参数名称是否必填释义code否一个数字状态码它解释了连接关闭的原因。如果没有传这个参数默认使用 1005。reason否一个协议字符串或者一个包含协议字符串的数组。这些字符串用于指定子协议这样单个服务器可以实现多个 WebSocket 子协议例如你可能希望一台服务器能够根据指定的协议protocol处理不同类型的交互。如果不指定协议字符串则假定为空字符串。
WebSocket.send() 将需要通过 WebSocket 链接传输至服务器的数据排入队列并根据所需要传输的 data bytes 的大小来增加 bufferedAmount的值。若数据无法传输例如数据需要缓存而缓冲区已满时套接字会自行关闭。
参数名称是否必填释义data是用于传输至服务器的数据。
3-3、属性 WebSocket.binaryType返回 websocket 连接所传输二进制数据的类型。
WebSocket.bufferedAmount一个只读属性用于返回已经被send()方法放入队列中但还没有被发送到网络中的数据的字节数。一旦队列中的所有数据被发送至网络则该属性值将被重置为 0。但是若在发送过程中连接被关闭则属性值不会重置为 0。如果你不断地调用send()则该属性值会持续增长。
WebSocket.extensions是只读属性返回服务器已选择的扩展值。目前链接可以协定的扩展值只有空字符串或者一个扩展列表。
WebSocket.protocol 是个只读属性用于返回服务器端选中的子协议的名字这是一个在创建 WebSocket 对象时在参数 protocols 中指定的字符串当没有已建立的链接时为空串。
WebSocket.readyState返回当前 WebSocket 的链接状态只读。
值释义0正在链接中1已经链接并且可以通讯2连接正在关闭3连接已关闭或者没有链接成功
WebSocket.url是一个只读属性返回值为当构造函数创建WebSocket实例对象时 URL 的绝对路径。
3-4、事件
WebSocket.onclose属性返回一个事件监听器这个事件监听器将在 WebSocket 连接的readyState 变为 3时被调用它接收一个名字为“close”的 CloseEvent 事件。
WebSocket.onerror当websocket的连接由于一些错误事件的发生 (例如无法发送一些数据) 而被关闭时一个error事件将被引发。
WebSocket.onmessagemessage 事件会在 WebSocket 接收到新消息时被触发。
WebSocket.onopen属性定义一个事件处理程序当WebSocket 的连接状态readyState 变为1时调用;这意味着当前连接已经准备好发送和接受数据。
4、怎么保持WebSocket长时间连接不断线
首先我们来探讨一下为什么websocket断线的原因有哪些由于websocket连接是基于一个tcp连接上的长时间全双工双向通信所以断线的原因有下几种可能个人猜测 1、网络连接网络连接不稳定或出现故障可能会导致WebSocket断线 2、服务器WebSocket服务器出现故障或过载可能会导致WebSocket断线 3、防火墙问题防火墙可能会阻止WebSocketClient与服务器之间的通信导致断线。 4、超时问题WebSocket在一段时间内没有收到服务器发送的数据则可能会断开连接。 5、客户端异常中断。
如何解决断线问题 1、心跳检测机制通过定期发送心跳消息可以确保客户端和服务器之间的连接处于活跃状态。如果一段时间内未收到来自客户端的心跳消息服务器可以认为客户端已经断线并采取相应的措施例如关闭连接或重新建立连接。 2、连接状态管理在客户端代码中维护连接的状态信息以便及时检测连接的断开和重新连接的状态变化。这样可以使应用程序更容易地处理连接断开和重新连接时的逻辑。 3、异常处理 及时捕获和处理在连接过程中可能出现的异常情况例如网络超时、连接被拒绝等以提高系统的稳定性和可靠性。
心跳检测机制 之所以称之为心跳检测是因为它像心跳一样每隔固定时间发一次以此来告诉服务器这个客户端还活着。实际上这种机制是为了维持长连接而设计的。通常情况下心跳包的内容并没有特别的规定通常是一个很小的数据包甚至可能只包含包头的空包。
心跳检测步骤 1、客户端会定期发送一个探测包心跳包给服务器以确保连接的活跃性。 2、在发送探测包的同时客户端会启动一个超时定时器以便在规定的时间内等待服务器的响应。 3、当服务器接收到客户端发送的探测包时会立即回应一个确认包以表明服务器正常接收到了探测包。 4、如果客户端收到服务器的应答包则说明服务器正常客户端在收到服务器的确认包后会立即删除之前启动的超时定时器表明服务器正常运行。 5、如果客户端的超时定时器超时仍未收到应答包则说明服务器挂了如果客户端的超时定时器到期时仍未收到服务器的确认包则客户端会认为服务器已经挂了进而采取相应的措施例如重新连接或者进行错误处理。
5、封装一个通用的推送、订阅主题的webSocket的类
// 先定义一个基础webSocket类
class WebsocketClient {// 连接的URL_host ;// websocket对象ws null;// 传入的websocket的方法函数事件回调函数_insOwner null;constructor(host: string, ins) {this._host host;this._insOwner ins;this.initWebsocket();}// 初始化创建websocket对象initWebsocket() {if (this.ws ! null) {this.ws.close();}try {this.ws new WebSocket(this._host);} catch (error) {console.error(create websocket error: , error.toString());if (this._insOwner typeof this._insOwner.onDisconnect function) {// websocket连接失败处理函数this._insOwner.onDisconnect();}return;}this.ws.onopen () {//开始连接if (this._insOwner typeof this._insOwner.onConnect function) {this._insOwner.onConnect();}};this.ws.onerror (error) {console.error(websocket error: , error);};this.ws.onclose (e) {console.error(websocket onclose: , e);if (this._insOwner typeof this._insOwner.onDisconnect function) {this._insOwner.onDisconnect(e);}};this.ws.onmessage (message) {if (this._insOwner typeof this._insOwner.onMessage function) {this._insOwner.onMessage(message.data);}};}// 发送消息sendMessage(message) {console.log(this.ws, this.ws.readyState, message);// WebSocket 是否处于打开状态 readyState 1//CONNECTING值为0表示正在连接。//OPEN值为1表示连接成功可以通信了。//CLOSING值为2表示连接正在关闭。//CLOSED值为3表示连接已经关闭或者打开连接失败。if (this.ws this.ws.readyState 1) {this.ws.send(message);return true;}return false;}// 关闭连接dispose() {this._host ;this._insOwner null;if (this.ws ! null) {this.ws.close();this.ws null;}}
}在此基础类之上定义一个可发布订阅消息主题的类 什么叫消息主题在真实开发中我们接收websocket信息时后端会在一个ws连接里推送不同页面的信息这个时候我们就要判断当前推送的信息是不是当前页面要用的信息如果是就调用接收信息的回调不是就忽略。示例如下
可发布订阅消息主题的类代码如下interface UpcWebsocketEvent {type: UpcWebsocketEventType;data: UpcWebsocketEventInfo;
}interface UpcWebsocketEventInfo {isReconnect: boolean; // 是否是重连reconnectable: boolean; // 是否自动重连reconnectDivide: number; // 重连间隔 SreconnectMaxTimes?: number; // 最大重连次数reconnectTimes?: number; // 当前重连次数
}export enum UpcWebsocketEventType {Connected,Disconnect,Reconnect,
}export class UpcWebsocketClient {_client: any null; // 存储WebSocket客户端实例_url ;_urlGenerator null; // url 生成器isConnect false; //连接状态reConnectNum 0; //重连次数reConnectMaxNum 3; // 最大重连次数// 登录相关_logined false;_loginTimer null;_loginResolve null;// 心跳相关_heartTimer null;_heartBeatResolve null;_heartBeatResolveTimer null;// 重连句柄_autoReloginTimer null;_autoReloginDivide 10; // 每隔 10 S 发起一次重连// 实例事件, 需全局订阅_instanceEventCallback: ((event: UpcWebsocketEvent) void) | null null;// 主题订阅_subIndex 0;_subMap new Mapstring, Mapnumber, (data: any) void(); // Maptopic, MapsubIndex, listnerconstructor(urlGenerator) {if (typeof urlGenerator ! function) {throw new Error(urlGenerator is not function);}this._urlGenerator urlGenerator;}onInstanceEvent(fn: (event: UpcWebsocketEvent) void) {if (typeof fn function) {this._instanceEventCallback fn;}}emitInstanceEvent(type: UpcWebsocketEventType, data: UpcWebsocketEventInfo) {if (typeof this._instanceEventCallback function) {this._instanceEventCallback({ type, data });}}
// 根据基础类创建websocket对象async createWebsocket() {// this._client存储创建出来的websocket对象索引if (this._client ! null) {this._client.dispose();this._client null;}// 拿到websocket连接url,一般都是要携带token的所以拿url的方法要抽离出类之外通过构造函数传入const result await this._urlGenerator();if (result.code ! 0) {return { code: result.code, msg: 获取推送服务认证口令失败 };}this._url result.data; // \({this._host}/ws?token\){this._token};return new Promise((resolve: (connected: boolean) void) {this._loginResolve resolve;this._client new WebsocketClient(this._url, this);});}// 开始连接如果连接失败将尝试自动重连开启连接async start() {const connected await this.createWebsocket();// 判断ws对象是否创建成功否就重连创建是就开启心跳检测机制if (!connected) {this.autoRelogin();} else {this.keepHeartBeat(); // 开始心跳}}// 暂停连接清理相关资源pause() {// 清理 socketthis._client this._client.dispose();this._client null;// 如果有心跳取消心跳this._heartTimer clearTimeout(this._heartTimer);this._heartTimer null;// 如果心跳正在进行, 取消回调this._heartBeatResolveTimer clearTimeout(this._heartBeatResolveTimer);this._heartBeatResolveTimer null;this._heartBeatResolve null;this._loginResolve null;// 如果在重连, 去掉重连this._autoReloginTimer clearTimeout(this._autoReloginTimer);this._autoReloginTimer null;// 清理主题订阅this._subIndex 0;this._subMap.clear();this.isConnect false; //连接状态this.reConnectNum 0;return;}// 重连,每隔一定时间尝试重新连接async autoRelogin() {this._autoReloginTimer setTimeout(async () {this._autoReloginTimer null;const ret await this.createWebsocket();if (!ret) {return this.autoRelogin();} else {this.keepHeartBeat(); // 开始心跳}this.isConnect true;// 重连成功this.emitInstanceEvent(UpcWebsocketEventType.Reconnect, {msg: ,relogin_divide: this._autoReloginDivide,});}, this._autoReloginDivide * 1000);}// 建立连接连接建立成功之后要做的事情基础类的onopen事件回调函数onConnect() {console.log(webSocket已连接);this.isConnect true;this.reConnectNum 0;typeof this._loginResolve function this._loginResolve(true);this._loginResolve null;this.recoverSubscribe(); // 恢复订阅}// WebSocket连接断开时调用清理资源基础类的onclose事件回调函数onDisconnect(e?) {console.log(webSocket已经关闭 ${e} );// 清理 socketthis._client this._client.dispose();this._client null;// 如果有心跳取消心跳this._heartTimer clearTimeout(this._heartTimer);this._heartTimer null;// 如果心跳正在进行, 取消回调this._heartBeatResolveTimer clearTimeout(this._heartBeatResolveTimer);this._heartBeatResolveTimer null;this._heartBeatResolve null;// 触发掉线通知掉线this.emitInstanceEvent(UpcWebsocketEventType.Disconnect, {msg: ,relogin_divide: this._autoReloginDivide,});//被动断开重新连接if (e e?.code) {this.autoRelogin();console.log(websocket连接不上请重新登录或联系开发人员!);}}// 接收到的 WebSocket消息解析消息并调用相应的处理函数基础类的onmessage事件回调函数onMessage(message: string) {const msg JSON.parse(message);// console.log(onMessage, msg);if (!msg.channel) {console.error(onMessage error );return;}if (!(typeof msg.text string JSON.parse(msg.text).action_ans subscriber successed!)) {this.handlePublish(msg);}}// 使用nginx代理webSocket链接客户端和服务器握手成功后如果在60s时间内没有数据交互连接就会自动断开// 心跳检测定期 30s 发送心跳请求并处理心跳响应keepHeartBeat() {this._heartTimer setTimeout(async () {this._heartTimer null;const ret await this.sendHeartBeat();// if (ret?.code 1) {// return this.onDisconnect();// }return this.keepHeartBeat();}, 30 * 1000); // }// 发送心跳请求返回一个Promise用于处理心跳响应sendHeartBeat() {return new Promise((resolve) {this._heartBeatResolve resolve;this._heartBeatResolveTimer setTimeout(() {this._heartBeatResolveTimer null;if (this._heartBeatResolve ! null) {this._heartBeatResolve({ code: 100, ret_msg: sendHeartBeat timeout, data: null });this._heartBeatResolve null;}}, 10 * 1000);const reqData {action: req,channel: ping,};this._client this._client.sendMessage(JSON.stringify(reqData));});}// handlePublish(msg) {const topic msg.channel;const handleMap this._subMap.get(topic);if (handleMap ! null) {handleMap.forEach((fn) {try {fn(JSON.parse(msg.text));} catch (e) {console.log(e);}});}}// 恢复所有主题的订阅recoverSubscribe() {this._subMap.forEach((handleMap, topic) {if (handleMap ! null handleMap.size 0) {const reqData {action: sub,channel: topic,data: {},};this._client this._client.sendMessage(JSON.stringify(reqData));}});}/*** 订阅指定主题并注册事件监听器。* param topic 订阅的主题字符串。* param listener 当订阅主题触发时执行的回调函数。* returns 返回一个句柄用于取消订阅。/subscribe(topic: string, listener: () void) {if (typeof listener ! function) return;let handleMap this._subMap.get(topic);if (handleMap null) {handleMap new Map();this._subMap.set(topic, handleMap);}const handle this._subIndex;handleMap.set(handle, listener);if (handleMap.size 1) {// 初始添加订阅, 需要向后台发送消息const reqData {action: sub,channel: topic,data: {},};this._client this._client.sendMessage(JSON.stringify(reqData));}return handle;}/** 取消订阅指定主题或删除指定句柄对应的监听器。* param topic 要取消订阅的主题字符串。* param handle 可选取消特定句柄对应的监听器若未提供则取消该主题下的所有监听器。/unsubscribe(topic, handle?) {const handleMap this._subMap.get(topic); // 获取对应主题的订阅if (handleMap null || handleMap.size 0) {// 未订阅无需退订return;}if (typeof handle undefined) {// 全部退订handleMap.clear();} else {handleMap.delete(handle);}if (handleMap.size 0) {// 向后台取消订阅const reqData {action: unsub,channel: topic,data: {},};this._client this._client.sendMessage(JSON.stringify(reqData));}}/** 清理资源并释放所有内部状态。*/dispose() {// 清理 socketthis._client this._client.dispose();this._client null;// 如果有心跳取消心跳this._heartTimer clearTimeout(this._heartTimer);this._heartTimer null;// 如果心跳正在进行, 取消回调this._heartBeatResolveTimer clearTimeout(this._heartBeatResolveTimer);this._heartBeatResolveTimer null;this._heartBeatResolve null;// 如果在重连, 去掉重连this._autoReloginTimer clearTimeout(this._autoReloginTimer);this._autoReloginTimer null;// 清理系统订阅this._instanceEventCallback null;// 清理主题订阅this._subIndex 0;this._subMap.clear();}
}
相关文章
-
php做的卖水果网站有哪些wordpress vip解析插件
php做的卖水果网站有哪些wordpress vip解析插件
- 站长
- 2026年02月17日
-
php制作网站开发大型网站制作教程
php制作网站开发大型网站制作教程
- 站长
- 2026年02月17日
-
php整站开发 企业网站教程潜江网站设计
php整站开发 企业网站教程潜江网站设计
- 站长
- 2026年02月17日
-
php做的网站优缺点特色企业网站
php做的网站优缺点特色企业网站
- 站长
- 2026年02月17日
-
php做的网站怎么打开温州最好的seo
php做的网站怎么打开温州最好的seo
- 站长
- 2026年02月17日
-
php做的知名网站郑州做网站云极
php做的知名网站郑州做网站云极
- 站长
- 2026年02月17日
