Websocket备忘录

目录

1.序言

2.后端集成

2.1.pom.xml和集成配置

2.2.行为接口封装

2.3.Spring的自定义消息策略模式

2.3.1.定义接口,描点注解和消息枚举类

2.3.2.策略接口实现类

2.4.2.策略工厂类

2.4.Spring的事件通知机制

2.4.1.自定义事件源

2.4.2.事件监听器

2.4.3.事件发布器

2.4.4.测试

3.前端集成

3.1.页面集成

3.2.vite的反向代理配置

4.总之感觉还是很简单的


1.序言

       WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工(full-duplex)通讯的协议。没有了 Request 和 Response 的概念,两者地位完全平等,连接一旦建立,就建立了真持久性连接,双方可以通过WebSocket随时向对方发送数据。

目的:

服务器端的资源经常在更新,客户端需要尽量及时地知道这些更新从而展示给用户。

常用的解决方案:

前端定时轮询:效率低,非常浪费资源(网络带宽和计算资源)。有一定延迟、服务器压力较大,并且大部分是无效请求。

SSE:一种基于HTTP的,以流的形式由服务端持续向客户端发送数据的技术,是一种半双工通讯方式。听说有用过,有机会再整理

DWR:不熟悉的可以参考我的另一篇文章,专门针对DWR框架的讲解

Websocket:想了解原理或者属性,方法等,可以参考我的下载,有专门的PPT讲解

本篇文章主要是实战开发,后端语言是java,前端是vue3+vite

2.后端集成

2.1.pom.xml和集成配置

springboot2.5.3版本

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

增加配置文件WebsocketConfig.java

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;@EnableWebSocket
@Configuration
public class WebsocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}
}

2.2.行为接口封装

IWebsocket接口定义,包含了websocket的4大基础方法,业务逻辑客户端的增查删改操作,打标记等行为。

import com.xxx.notification.websocket.dto.CacheClient;import javax.websocket.EndpointConfig;
import javax.websocket.Session;
import java.util.List;
import java.util.concurrent.CopyOnWriteArraySet;public interface IWebsocket {interface ILinkPoint {//连接时回调void onOpen(Session session);//收到消息时回调void onMessage(String message);//连接关闭时回调void onClose();//发生错误时回调void onError(Session session, Throwable throwable);}interface IClient {//获取会话Session getSession();//获取标记String getTag();//发送文本void sendText(String text);//发送对象void send(Object object);}interface IManager<T extends CacheClient> {//向指定客户端发送文本void sendText(String text, List<T> clients);//向所有客户端发送文本void sendTextYoAll(String text);//添加客户端void addClient(T client);//获取所有客户端CopyOnWriteArraySet<T> all();//移除客户端void removeClients(List<T> clients);//根据标记获取客户端T getClientByTag(String tag);//根据标记获取多个客户端T[] getClientsByTags(List<String> tags);}

接口实现类ClientService :包含了基础操作

import com.xxx.exception.I18nServerEndException;
import com.xxx.notification.websocket.IWebsocket;
import com.xxx.notification.websocket.dto.CacheClient;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;@Slf4j
@Component
@ServerEndpoint("/api/v1/ws/{username}")
public class ClientService implements IWebsocket.ILinkPoint, IWebsocket.IClient {private static ManagerService managerService = ManagerService.getInstance();private String tag;private Session session;@OnOpen@Overridepublic void onOpen(Session session) {Map<String, List<String>> requestParameterMap = session.getRequestParameterMap();String username = requestParameterMap.get("username").get(0);String types = requestParameterMap.get("types").get(0);List<String> typeList = Arrays.asList(types.split(","));CacheClient cacheClient = CacheClient.getInstance(username, typeList, this);managerService.addClient(cacheClient);this.session = session;this.tag = username;}@OnMessage@Overridepublic void onMessage(String message) {}@OnClose@Overridepublic void onClose() {Set<CacheClient> allCacheClients = managerService.all();List<CacheClient> list = allCacheClients.stream().filter(client -> StringUtils.equals(client.getUsername(), tag)).collect(Collectors.toList());if(list != null && list.size() != 0){managerService.removeClients(list);}}@OnError@Overridepublic void onError(Session session, Throwable throwable) {try {session.close();onClose();} catch (IOException e) {e.printStackTrace();log.error("websocket报错:", e);throw new I18nServerEndException("common.tips_12");}}@Overridepublic Session getSession() {return this.session;}@Overridepublic String getTag() {return this.tag;}@Overridepublic synchronized void sendText(String text) {try {session.getBasicRemote().sendText(text);} catch (IOException e) {e.printStackTrace();log.error("推送消息失败", e);}}@Overridepublic synchronized void send(Object object) {try {session.getBasicRemote().sendObject(object);} catch (IOException | EncodeException e) {log.error("推送消息失败", e);}}
}

接口实现类ClientService :包含了上层的行为操作

import com.xxx.notification.websocket.IWebsocket;
import com.xxx.notification.websocket.dto.CacheClient;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.stream.Collectors;public class ManagerService implements IWebsocket.IManager<CacheClient> {private static CopyOnWriteArraySet<CacheClient> linkSet = new CopyOnWriteArraySet<>();//单例private static ManagerService instance = new ManagerService();private ManagerService() {}public static ManagerService getInstance() {return instance;}@Overridepublic void sendText(String text, List<CacheClient> clients) {for (CacheClient cacheClient : clients) {cacheClient.getClientService().sendText(text);}}@Overridepublic void sendTextYoAll(String text) {for (CacheClient cacheClient : linkSet) {cacheClient.getClientService().sendText(text);}}@Overridepublic void addClient(CacheClient client) {linkSet.add(client);}@Overridepublic CopyOnWriteArraySet<CacheClient> all() {return linkSet;}@Overridepublic void removeClients(List<CacheClient> clients) {for (CacheClient cacheClient : clients) {linkSet.remove(cacheClient);}}@Overridepublic CacheClient getClientByTag(String tag) {for (CacheClient clientService : linkSet) {if (clientService.getClientService().getTag().equals(tag)) {return clientService;}}return null;}@Overridepublic CacheClient[] getClientsByTags(List<String> tags) {if (null == tags || tags.size() == 0) {return null;}Set<String> tagSet = tags.stream().collect(Collectors.toSet());List<CacheClient> clientList = linkSet.stream().filter(c -> tagSet.contains(c.getClientService().getTag())).collect(Collectors.toList());CacheClient[] clients = new CacheClient[clientList.size()];clientList.toArray(clients);return clients;}
}

涉及到的泛型对象CacheClient

import com.xxx.notification.websocket.service.ClientService;
import com.xxx.system.dao.UserDao;
import com.xxx.system.model.User;
import com.xxx.util.SpringContextUtil;
import lombok.Data;
import java.util.List;
import java.util.stream.Collectors;@Data
public class CacheClient {private List<Integer> types;private ClientService clientService;private String username;private String domain;public static CacheClient getInstance(String username, List<String> types, ClientService clientService){UserDao userDao = (UserDao)SpringContextUtil.getBean("userDao");User user = userDao.getByUsername(username);String domain = user.getDomain();CacheClient cacheClient = new CacheClient();cacheClient.setUsername(username);cacheClient.setTypes(types.stream().map(Integer::parseInt).collect(Collectors.toList()));cacheClient.setClientService(clientService);cacheClient.setDomain(domain);return cacheClient;}@Overridepublic boolean equals(Object o) {if (this == o) {return true;}if (o == null || getClass() != o.getClass()) {return false;}CacheClient that = (CacheClient) o;return username != null ? username.equals(that.username) : that.username == null;}@Overridepublic int hashCode() {int result = types != null ? types.hashCode() : 0;result = 31 * result + (username != null ? username.hashCode() : 0);result = 31 * result + (domain != null ? domain.hashCode() : 0);return result;}
}

2.3.Spring的自定义消息策略模式

2.3.1.定义接口,描点注解和消息枚举类

import com.alibaba.fastjson.JSON;
import com.xxx.notification.constants.NotificationType;
import com.xxx.notification.websocket.dto.CacheClient;
import com.xxx.notification.websocket.service.ManagerService;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;/*** 消息服务*/
public interface INotificationService<P> {ManagerService managerService = ManagerService.getInstance();default void sendMessage(NotificationType notificationType, Object message, Set<CacheClient> allCacheClients){Integer type = notificationType.getType();List<CacheClient> list = allCacheClients.stream().filter(client -> client.getTypes().contains(type)).collect(Collectors.toList());if(list != null && list.size() != 0){managerService.sendText(JSON.toJSONString(message), list);}}/*** 发起推送* @param p* @return*/public void pushNotification(P p);
}import java.lang.annotation.*;/*** 策略描点注解*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface StrategyAnchor {NotificationType[] type();
}/*** 通知类型枚举*/
public enum NotificationType {DEVICE_ALARM(1, "deviceAlarm"),SYSTEM_ALARM(2, "systemAlarm");private Integer type;private String name;NotificationType(Integer type, String name) {this.type = type;this.name = name;}public Integer getType() {return type;}public void setType(Integer type) {this.type = type;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}

2.3.2.策略接口实现类

只写了一种实现类

import com.xxx.dto.ObjectResponse;
import com.xxx.notification.constants.NotificationType;
import com.xxx.notification.constants.StrategyAnchor;
import com.xxx.notification.dto.NotificationDto;
import com.xxx.notification.event.AlarmEvent;
import com.xxx.notification.service.INotificationService;
import com.xxx.notification.websocket.dto.CacheClient;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import java.util.Set;
import java.util.stream.Collectors;@Service
@StrategyAnchor(type = NotificationType.DEVICE_ALARM)
public class DeviceAlarmNotificationService implements INotificationService<AlarmEvent> {@Overridepublic void pushNotification(AlarmEvent alarmEvent) {NotificationType notificationType = alarmEvent.getNotificationType();String domain = alarmEvent.getDomain();if(StringUtils.isBlank(domain)) return;Set<CacheClient> allCacheClient = managerService.all();Set<CacheClient> cacheClients = allCacheClient.stream().filter(client -> {String clientDomain = client.getDomain();if(StringUtils.isBlank(clientDomain)) return false;return StringUtils.startsWith(domain, stripEndStr(clientDomain));}).collect(Collectors.toSet());//发送websocketNotificationDto notificationDto = NotificationDto.getInstance(notificationType, alarmEvent);sendMessage(notificationType, ObjectResponse.generateNormalResponse(notificationDto), cacheClients);}private String stripEndStr(String data){String temp = StringUtils.stripEnd(data, "0");temp = StringUtils.isBlank(temp) ? "0" : temp;return temp;}
}

2.4.2.策略工厂类

import com.xxx.notification.constants.NotificationType;
import com.xxx.notification.constants.StrategyAnchor;
import com.xxx.notification.service.INotificationService;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;import java.util.Arrays;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;@Component
public class NotificationFactory implements ApplicationContextAware {private static Map<Integer, INotificationService> beans = new ConcurrentHashMap<>();public static INotificationService getNotificationService(NotificationType notificationType) {return beans.get(notificationType.getType());}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {Map<String, INotificationService> map = applicationContext.getBeansOfType(INotificationService.class);map.forEach((beanName, bean) -> {StrategyAnchor anchor = applicationContext.findAnnotationOnBean(beanName, StrategyAnchor.class);Optional.ofNullable(anchor).ifPresent(an -> Arrays.stream(anchor.type()).forEach(type -> beans.put(type.getType(), bean)));});}
}

2.4.Spring的事件通知机制

结合消息策略模式和解耦合+线程池模式(@Async+@EnableAsync),异步推送消息

2.4.1.自定义事件源

import com.xxx.notification.constants.NotificationType;
import org.springframework.context.ApplicationEvent;public class AlarmEvent extends ApplicationEvent {private NotificationType notificationType;private String domain;public AlarmEvent(Object source) {super(source);}public NotificationType getNotificationType() {return notificationType;}public void setNotificationType(NotificationType notificationType) {this.notificationType = notificationType;}public String getDomain() {return domain;}public void setDomain(String domain) {this.domain = domain;}
}

2.4.2.事件监听器

import com.xxx.notification.NotificationFactory;
import com.xxx.notification.constants.NotificationType;
import com.xxx.notification.service.INotificationService;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Component;@Component
@EnableAsync
public class AlarmEventListener {@Async@EventListenerpublic void handleAlarmEvent(AlarmEvent event) {NotificationType notificationType = event.getNotificationType();if(notificationType == null || notificationType.getType() == null) return;INotificationService notificationService = NotificationFactory.getNotificationService(notificationType);if(notificationService == null) return;notificationService.pushNotification(event);}
}

2.4.3.事件发布器

import com.xxx.alarm.model.Alarm;
import com.xxx.notification.constants.NotificationType;
import org.springframework.context.ApplicationEventPublisher;public class AlarmEventPublisher {/*** 设备告警发送事件* @param alarm* @param eventPublisher*/public static void publishDeviceAlarmEvent(Alarm alarm, ApplicationEventPublisher eventPublisher){AlarmEvent alarmEvent = new AlarmEvent(alarm);alarmEvent.setNotificationType(NotificationType.DEVICE_ALARM);alarmEvent.setDomain(alarm.getDomain());eventPublisher.publishEvent(alarmEvent);}/*** 系统告警发送事件* @param obj* @param eventPublisher*/public static void publishSystemAlarmEvent(Object obj, ApplicationEventPublisher eventPublisher){AlarmEvent alarmEvent = new AlarmEvent(obj);alarmEvent.setNotificationType(NotificationType.SYSTEM_ALARM);eventPublisher.publishEvent(alarmEvent);}
}

2.4.4.测试

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;@Autowired
private ApplicationEventPublisher eventPublisher;
@Autowired
private AlarmService alarmService;@GetMapping("/test")
public voidtestEvent(String id){Alarm alarm = alarmService.findOne(......);//实时消息推送AlarmEventPublisher.publishDeviceAlarmEvent(alarm, eventPublisher);
}

3.前端集成

vue3+vite的方式

3.1.页面集成

<template><h1>Web Socket</h1>
</template><script lang="ts">import { ref,onUnmounted } from "vue";export default {setup() {const ws = ref();const initWs = () => {console.log('${location.host}',location.host);ws.value = new WebSocket(`ws://${location.host}/wsUrl/{登录的用户名}?types=1,2`)//  //连接发生错误的回调方法ws.value.onerror = function () {console.log("ws连接发生错误");};//连接成功建立的回调方法ws.value.onopen = function () {console.log("ws连接成功");}//接收到消息的回调方法ws.value.onmessage = function (event:any) {console.log('的',event.data);}}initWs();onUnmounted(() => {closeWebSocket();});const closeWebSocket = () => {ws.value.close();};return {};},
};
</script>

3.2.vite的反向代理配置

在vite.config.ts文件中

server: {host: '0.0.0.0',// host: "localhost",port: 3001,// // 是否自动在浏览器打开// open: true,// // 是否开启 https// https: false,// // 服务端渲染// ssr: false,proxy: {'/wsUrl':{target: 'ws://后端IP地址:9090/xxx/api/v1/ws/',changeOrigin: true,ws: true,rewrite: (path) => path.replace('/wsUrl', '')},'/api': {target: 'http://localhost:3333/',changeOrigin: true,ws: true,rewrite: (pathStr) => pathStr.replace('/api', '')},},},

其中rewrite属性:把访问路径中的wsUrl设置成空串,另外wsUrl可替换成任意字符,只作为前端标识符的作用。

例如:

前端访问地址是ws://127.0.0.1:3001/wsUrl/xyz,经过反向代理给后端的地址是

ws://后端IP地址:9090/xxx/api/v1/ws/xyz

如果没有加rewrite属性

前端访问地址是ws://127.0.0.1:3001/wsUrl/,经过反向代理给后端的地址是

ws://后端IP地址:9090/xxx/api/v1/ws/wsUrl,就不符合实际要求了

4.总之感觉还是很简单的

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

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

相关文章

基于IMX6ULL的AP3216C的QT动态数据曲线图显示

前言&#xff1a;本文为手把手教学 LinuxQT 的典型基础项目 AP3216C 的数据折线图显示&#xff0c;项目使用正点原子的 IMX6ULL 阿尔法( Cortex-A7 系列)开发板。项目需要实现 AP3216C 在 Linux 系统下的驱动&#xff0c;使用 QT 设计 AP3216C 的数据显示页面作为项目的应用层。…

websocket发布到iis之后无法创建连接访问

在做websocket测试时在本地的服务可以正常访问&#xff0c;在调试成功之后发布到了iis中&#xff0c;发现无法连接&#xff0c;这时可能有以下几个原因。 WebSocket无法连接到IIS&#xff1a; IIS版本不支持WebSocket&#xff1a;IIS 8.0及更高版本才支持WebSocket&#xff0…

从小白到大神之路之学习运维第61天--------Ansible自动化运维工具(playbook配置文件深入了解)

第三阶段基础 时 间&#xff1a;2023年7月14日 参加人&#xff1a;全班人员 内 容&#xff1a; playbook配置文件 目录 playbook配置文件 一、playbook配置文件概念 修改hosts文件 建立playbook配置文件 yml脚本写法注释&#xff1a; 二、Playbook的核心元素 三、…

如何破解中小企业数字化转型难点?建议来了!

打开任何一个搜索引擎&#xff0c;只要输入“中小企业数字化转型”&#xff0c;关于痛点、难处的文章就会铺面而来&#xff0c;难在哪里&#xff0c;其实很好解答&#xff0c;关键在于&#xff0c;如何解决这一个个难处。 PS&#xff1a;给大家整理了一份完整版的《中小企业如…

汽车供应链专场对接会 | 8月25日大会同期活动

爱普搜汽车供应链对接会&#xff0c;是根据采购商的项目需求&#xff0c;有针对性地组织全国各地采购商与供应商&#xff0c;进行面对面交流与沟通&#xff0c;促成实质性交易。参会群体为汽车行业制造型企业、主机厂、Tier1/2。 供应商在参加对接会前已做足功课&#xff0c;现…

C语言-ubuntu下的命令

目录 linux命令 【1】打开关闭终端 【2】终端 【3】ls命令 【4】cd 切换路径 【5】新建 【6】删除 【7】复制 【8】移动 【9】常用快捷键 【10】vi编辑器 【11】简单编程步骤 任务&#xff1a; linux命令 【1】打开关闭终端 打开终端&#xff1a; 1. 直接点击 …

File格式转换MultipartFile格式的例子

首先&#xff1a;需要先引入依赖包 <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.3.9</version> </dependency> 1.Multipartfile转File类型 //创建一…

一零六四、世界杯数据可视化分析(阿里云天池赛)

目录 赛制官方链接 活动背景 活动时间&#xff1a;即日起-12月31日17点 数据说明 世界杯成绩信息表&#xff1a;WorldCupsSummary 世界杯比赛比分汇总表&#xff1a;WorldCupMatches.csv 世界杯球员信息表&#xff1a;WorldCupPlayers.csv 代码实现 赛制官方链接 世界杯…

视频融合平台EasyCVR登录后通道数据及菜单栏页面显示异常的排查与解决

EasyCVR可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有GB28181、RTSP/Onvif、RTMP等&#xff0c;以及厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等&#xff0c;能对外分发RTSP、RTMP、FLV、HLS、WebRTC等格式的视频流。 有用…

docker基础1——架构组成、安装配置

文章目录 一、发展起源1.1 传统虚拟化与容器虚拟化1.2 docker底层核心技术1.2.1 命名空间1.2.2 控制组 1.3 docker工作方式1.4 docker容器编排1.5 docker优劣势1.6 docker架构组成 二、yum安装docker三、配置docker加速器 一、发展起源 背景了解&#xff1a; 容器是内核里的一项…

上市公司前端开发规范参考

上市公司前端开发规范参考 命名规则通用约定文件与目录命名HTML命名CSS命名JS命名 代码格式通用约定HTML格式CSS格式JS格式注释 组件组件大小单文件组件容器组件组件使用说明Prop指令缩写组件通讯组件的挂载和销毁按需加载第三方组件库的规定 脚手架使用规范移动端脚手架PC端脚…

前端 Jenkins 自动化部署

由于公司使用自己搭建的 svn 服务器来进行代码管理&#xff0c;因此这里 Jenkins 是针对 svn 服务器来进行的配置&#xff0c;其实跟Git 配置基本一致。 在没有自动化部署前 之前项目每次修改之后都需要本地 ​​npm run build ​​一次手动发布到服务器上方便测试和产品查看…

计数问题

题目 题目链接&#xff1a;338.计数问题 给定两个整数 a 和 b&#xff0c;求 a 和 b 之间的所有数字中 0∼9 的出现次数。 例如&#xff0c;a1024&#xff0c;b1032&#xff0c;则 a 和 b 之间共有 9 个数如下&#xff1a; 1024 1025 1026 1027 1028 1029 1030 1031 1032 …

Jenkins | 获取凭证密码

目录 方法一&#xff1a;查看所有账号及密码 方法二&#xff1a;查看指定账号密码 方法一&#xff1a;查看所有账号及密码 Jenkins > 系统管理 > 脚本命令行 com.cloudbees.plugins.credentials.SystemCredentialsProvider.getInstance().getCredentials().forEach{i…

nginx基础1——工作原理、安装配置、命令参数

文章目录 一、基本了解1.1 特性优点1.2 功能应用1.3 工作模块分类1.4 模块配置方法 二、工作原理三、安装与配置四、常用命令 一、基本了解 nginx简介&#xff1a; nginx是一款轻量级的Web服务器、反向代理服务器及电子邮件&#xff08;IMAP/POP3&#xff09;代理服务器&#x…

前端学习——ajax (Day1)

AJAX 概念和 axios 使用 axios 使用 练习 <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" …

SpringBoot 整合 RabbitMQ demo

Rabbit Windows安装教程 本文只做Demo案例的分享&#xff0c;具体只是需自行百度 一、生产者 1.application.properties 配置Rabbit的基本信息 #rabbit 主机IP spring.rabbitmq.host127.0.0.1 #rabbit 端口 spring.rabbitmq.port5672 #rabbit 账号 可自行创建 这里是默认的 …

ChatGPT漫谈(一)

最近一款“聊天机器人”迅速爆火,它叫ChatGPT,全称Chat Generative Pre-trained Transformer,对话数据预先训练生成的Transformer模型,"主要特色"是能够学习和理解人类的语言。 ChatGPT起源于聊天机器人(chat bot),它是一种使用聊天接口与用户交互的机器人,它可…

网络知识整合——Web页面请求的历程

Web页面请求的历程 内部涉及知识&#xff1a;一、准备:DHCP、UDP、IP 和以太网二、仍在准备&#xff1a;DNS和ARP三、仍在准备&#xff1a;域内路由选择到DNS服务器四、Web客户-服务器交互&#xff1a;TCP和HTTP五、HTTP请求响应格式Requests部分Responses 部分 下载一个Web页面…

ES6迭代器、Set、Map集合和async异步函数

目录 迭代器 Iterator 的作用 Iterator 的遍历过程 Set Map集合 map和对象区别? async异步函数 迭代器 迭代器&#xff08;Iterator&#xff09;就是这样一种机制。它是一种接口&#xff0c;为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署Iterator接口&…