基于Socket和ServerSocket自定义协议的实现多端通信、消息发送、群聊发送

通信基础
  • Socket
    Socket套接字是实现网络通信的重要接口,Socket绑定的应用进程,目标Ip的端口号,以及数据传输对应的输入输出缓冲区。一个数据包到达一台计算机物理设备后,经过网络协议栈的解析,然后由操作系统调度到对应端口的输入缓冲区中。

  • 通信双方需要遵循共同的协议
    客户端与服务端需要遵循共同的协议来完成一次通信,标准的协议对双方解析一次完整的会话、响应的数据标准非常重要。

案例实现

这里基于Socket和ServerSocket编写一个实际通信案例,可以实现单发消息、创建群聊、群发消息等功能。
既然要实现多端通信,那么就需要客户端与服务端或者是A端和B端约定好共同的协议或者叫数据格式,只要遵循同一种协议通信双方才能完成数据解析与处理。

  • 通信协议
    这里使用Json格式来约定为一次通信的数据格式。其他的公共协议有Http、Ftp等。

  • 会话标识
    这里约定以服务端或者客户端读取到对方输入缓冲区中的换行符(\n)为一次数据传输完成的标识。

在这里插入图片描述

定义类实现
  • 操作枚举类,定义服务端支持的操作
public enum OpType {SEND_TO_USER(1,"单发消息"),SEND_TO_GROUP(2,"群发消息"),USER_LOGIN(3,"用户登录"),CREATE_GROUP(4,"创建群聊"),LIST_ONLINE_USER(5,"列出所有在线用户"),LIST_GROUP_USER(6,"列出某个群聊的在线用户"),LIST_USER_GROUP(7,"列出当前用户加入的群聊");@Getterprivate Integer code;@Getterprivate String desc;private OpType(Integer code, String desc) {this.code = code;this.desc = desc;}public static OpType getOpType(Integer code) {return Arrays.stream(values()).filter(opType -> opType.getCode().equals(code)).findFirst().orElse(null);}public static String list(){List<String> collect = Arrays.stream(values()).sorted().map(item -> item.getCode() + "." + item.getDesc()).collect(Collectors.toList());return JSONObject.toJSONString(collect);}}
  • 定义通信用到的常量
public class Constant {public static String USERNAME = "userName";public static String PASSWORD = "password";public static String LOGIN_SUCCESS = "loginSuccess";public static String LOGIN_FAILED = "loginFailed";}
  • 定义一次数据包中的消息体,可以看作类似于Htt协议的响应体。
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Message {//消息发送者private String from;//消息接收者private String to;//消息内容private String messageBody;}
  • 定义一个数据包对象,客户端和服务器之间的通信就是一次发送一个数据包对象
/*** 每一次发送的封装的数据包*/
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Data
public class DataPacket {//操作类型private String opType;//内容private Message message;/*** 获取socket输入流中请求的数据,封装为dataPacket对象** @param br 字符输入流* @return 本次读取到的数据* @throws Exception 没有使用代理模式等需要捕获异常后自定义处理逻辑的场景下,可以直接将异常抛出去*/public static DataPacket acceptMessage(BufferedReader br) throws Exception {//阻塞当前线程读取缓冲区中的字节数据,约定以读取到换行符为结束String content = br.readLine();DataPacket dataPacket = JSONObject.parseObject(content, DataPacket.class);return dataPacket;}}
  • 用户会话对象,保存了用户的Socket以及输入输出流
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Data
public class UserSession {//登录用户名private String username;//用户的会话private Socket socket;//是否下线private boolean isOnline;//字符输入流private BufferedReader reader;//字符输出流private PrintWriter writer;@Overridepublic boolean equals(Object o) {return o instanceof UserSession && ((UserSession) o).getUsername().equals(username);}@Overridepublic int hashCode() {return Objects.hash(username);}public void sendMessage(DataPacket dataPacket) {writer.println(JSONObject.toJSONString(dataPacket));}
}
  • 定义一个用户会话管理对象,用于管理用户的会话,例如单发消息和群发消息
public class UserSessionManager {private static List<UserSession> userSessionList = new ArrayList<UserSession>();public static List<String> getOnLineUsers() {return userSessionList.stream().map(UserSession::getUsername).collect(Collectors.toList());}//保存用户会话public static void addUserSession(UserSession userSession) {userSessionList.add(userSession);System.out.println("保存用户会话成功,当前上线用户:" + userSessionList.stream().map(UserSession::getUsername).collect(Collectors.joining(",")));}//下线后剔除用户会话public static void removeUserSession(UserSession userSession) {userSessionList.remove(userSession);}//A用户向B用户发送消息public static void sendMessage(OpType opType, Message message) {String fromUser = message.getFrom();String toUser = message.getTo();String messageBody = message.getMessageBody();UserSession fromUserSession = getUserSession(fromUser);//判断发送目标是否在线UserSession toUserSession = getUserSession(toUser);if (toUserSession != null) {toUserSession.sendMessage(DataPacket.builder().opType(opType.name()).message(Message.builder().from(fromUser).to(toUser).messageBody(messageBody).build()).build());}else {//提示对方不在线fromUserSession.sendMessage(DataPacket.builder().opType(opType.name()).message(Message.builder().from("服务器").messageBody(toUser + "不在线,发送失败!").build()).build());}}//根据一组用户名获取用户数据public static List<UserSession> getUserSession(String[] userNames) {return userSessionList.stream().filter(userSession -> containsInArr(userNames,userSession.getUsername())).collect(Collectors.toList());}//根据单个用户名获取用户数据public static UserSession getUserSession(String userName) {return userSessionList.stream().filter(userSession -> userSession.getUsername().equals(userName)).findFirst().orElse(null);}private static boolean containsInArr(String[] userNames, String username) {for (String userName : userNames) {if (userName.equals(username)) {return true;}}return false;}
}
  • 定义用户认证类,用于用户登录认证
/*** 用户认证管理相关*/
public class UserAuthManager {private static Map<String,String> userMap=new HashMap<String,String>();static {userMap.put("a","1");userMap.put("b","1");userMap.put("c","1");userMap.put("d","1");}public static boolean login(String username,String password){if(userMap.containsKey(username)){if(userMap.get(username).equals(password)){return true;}}return false;}}
  • 定义一个群聊对象,包括群名称和管理的群用户
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Data
public class GroupSession {//群聊名称private String groupName;//群聊成员private List<UserSession> userSessions;}
  • 定义群会话管理对象,主要实现群发和创建群聊
/**群会话管理:1. 创建群聊2. 群成员发消息*/
public class GroupSessionManager {private static List<GroupSession> sessions = new ArrayList<GroupSession>();//创建群聊public static boolean createGroup(String groupName,String owner,String ...userNames) {//判断群聊是否存在boolean match = sessions.stream().anyMatch(session -> session.getGroupName().equals(groupName));if (match) {//群聊已存在,创建失败!return false;}//将创建者也加入到群组中List<UserSession> userSessions = UserSessionManager.getUserSession(userNames);UserSession userSession = UserSessionManager.getUserSession(owner);userSessions.add(userSession);sessions.add(new GroupSession(groupName,userSessions));return true;}//群聊发送消息public static void sendGroupMessage(String from, String groupName, String content) {//获取群组GroupSession groupSession = sessions.stream().filter(session -> session.getGroupName().equals(groupName)).findFirst().get();//遍历群组中的人List<UserSession> userSessions = groupSession.getUserSessions();for (UserSession userSession : userSessions) {String toUser = userSession.getUsername();//封装一条消息JSONObject jsonObject = new JSONObject();jsonObject.put("groupName", groupName);jsonObject.put("content", content);Message message = Message.builder().to(toUser).from(from).messageBody(jsonObject.toJSONString()).build();UserSessionManager.sendMessage(OpType.SEND_TO_GROUP, message);}}}
  • 定义服务端实现
public class ChatServer {public static void main(String[] args) throws Exception {ServerSocket serverSocket = new ServerSocket(6666);System.out.println("服务器启动成功");while (true) {Socket socket = serverSocket.accept();new Thread(() ->{try {System.out.println("客户端:" + socket.getRemoteSocketAddress() + "连接成功!");InputStream is = socket.getInputStream();BufferedReader br = new BufferedReader(new InputStreamReader(is));OutputStream os = socket.getOutputStream();PrintWriter pw = new PrintWriter(new OutputStreamWriter(os), true);while (true){//使用br阻塞监听读取此socket输入缓冲区中的字节数据,以读取到\r\n换行符为【一次结束】,客户端发送的数据既然会被缓存在对应socket输入流的字节缓冲区中。DataPacket dataPacket = DataPacket.acceptMessage(br);//判断客户端的请求类型String type = dataPacket.getOpType();OpType opType = valueOf(type);switch(opType){case SEND_TO_USER:{Message message = dataPacket.getMessage();UserSessionManager.sendMessage(SEND_TO_USER,message);};break;case SEND_TO_GROUP:{doSendToGroup(dataPacket);};break;case USER_LOGIN:{doUserLogin(socket,dataPacket,br,pw);};break;case CREATE_GROUP:{doCreateGroup(dataPacket, pw);};break;case LIST_ONLINE_USER:{doListOnlineUser(pw);};break;case LIST_GROUP_USER:{};break;case LIST_USER_GROUP:{};break;}}}catch (Exception e){e.printStackTrace();}}).start();}}private static void doSendToGroup(DataPacket dataPacket) {Message message = dataPacket.getMessage();String from = message.getFrom();String messageBody = message.getMessageBody();JSONObject jsonObject = JSONObject.parseObject(messageBody);String groupName = jsonObject.getString("groupName");String content = jsonObject.getString("content");GroupSessionManager.sendGroupMessage(from,groupName,content);}/*** 处理创建群聊* @param dataPacket* @param pw*/private static void doCreateGroup(DataPacket dataPacket, PrintWriter pw) {Message message = dataPacket.getMessage();String from = message.getFrom();String messageBody = message.getMessageBody();JSONObject jsonObject = JSONObject.parseObject(messageBody);String groupName = jsonObject.getString("groupName");String groupUsers = jsonObject.getString("groupUsers");String[] userArr = groupUsers.split(",");boolean isCreate  = GroupSessionManager.createGroup(groupName,from,userArr);String content = from + "邀请" + groupUsers + " 共同加入了群聊:" + groupName;Message sendMessage = Message.builder().messageBody(content).build();if (isCreate){//创建成功DataPacket packet = DataPacket.builder().opType(CREATE_GROUP.name()).message(sendMessage).build();pw.println(JSONObject.toJSONString(packet));//给群聊中其他人发for (String itemUser : userArr) {sendMessage.setTo(itemUser);UserSessionManager.sendMessage(CREATE_GROUP,sendMessage);}}else {//创建失败!DataPacket packet = DataPacket.builder().opType(CREATE_GROUP.name()).message(Message.builder().messageBody("创建群聊失败!").build()).build();pw.println(JSONObject.toJSONString(packet));}}/*** 给客户端响应当前服务器在线用户* @param pw*/private static void doListOnlineUser(PrintWriter pw) {List<String> onLineUsers = UserSessionManager.getOnLineUsers();DataPacket packet = DataPacket.builder().opType(LIST_ONLINE_USER.name()).message(Message.builder().messageBody(JSONObject.toJSONString(onLineUsers)).build()).build();pw.println(JSONObject.toJSONString(packet));System.out.println("服务器返回了当前所有在线用户");}/*** 处理用户登录* @param socket* @param dataPacket* @param br* @param pw*/private static void doUserLogin(Socket socket, DataPacket dataPacket, BufferedReader br, PrintWriter pw) {Message message = dataPacket.getMessage();JSONObject messageBody = JSONObject.parseObject(message.getMessageBody());String username = messageBody.getString(Constant.USERNAME);String password = messageBody.getString(Constant.PASSWORD);//登录boolean login = UserAuthManager.login(username, password);if (login) {//登录成功,存储用户会话UserSessionManager.addUserSession(UserSession.builder().socket(socket).isOnline(true).username(username).reader(br).writer(pw).build());DataPacket packet = DataPacket.builder().message(Message.builder().messageBody(Constant.LOGIN_SUCCESS).build()).build();//写出去pw.println(JSONObject.toJSONString(packet));}else {DataPacket packet = DataPacket.builder().message(Message.builder().messageBody(Constant.LOGIN_FAILED).build()).build();//写出去pw.println(JSONObject.toJSONString(packet));}}}
  • 定义客户端实现
public class ChatClient {public static void main(String[] args) throws Exception {Socket socket = new Socket("127.0.0.1", 6666);InputStream is = socket.getInputStream();OutputStream os = socket.getOutputStream();BufferedReader br = new BufferedReader(new InputStreamReader(is));PrintWriter pw = new PrintWriter(new OutputStreamWriter(os), true);Scanner scanner = new Scanner(System.in);String currentUserName = "";while (true) {String username = getInput("请输入用户名", scanner);String password = getInput("请输入密码", scanner);//封装成数据包JSONObject jsonObject = new JSONObject(2);jsonObject.put(Constant.USERNAME, username);jsonObject.put(Constant.PASSWORD, password);DataPacket packet = DataPacket.builder().message(Message.builder().messageBody(jsonObject.toJSONString()).build()).opType(OpType.USER_LOGIN.name()).build();pw.println(JSONObject.toJSONString(packet));DataPacket dataPacket = DataPacket.acceptMessage(br);String messageBody = dataPacket.getMessage().getMessageBody();//判断是否登录成功,如果成功就跳出循环,否则继续登录if (messageBody.equals(Constant.LOGIN_SUCCESS)) {//开启新线程,并行处理输入流handlerSocketInput(br);System.out.println("登录成功!");currentUserName = username;break;}System.out.println(messageBody);}while (true) {System.out.print("请选择操作:" + OpType.list());OpType opType = OpType.getOpType(scanner.nextInt());//继续调用一下scanner的nextLine方法来消耗缓冲区中的换行符scanner.nextLine();switch (opType) {//单发消息case SEND_TO_USER: {String toUser = getInput("请输入要发送的用户", scanner);String content = getInput("请输入发送内容", scanner);DataPacket dataPacket = DataPacket.builder().opType(opType.name()).message(Message.builder().from(currentUserName).messageBody(content).to(toUser).build()).build();pw.println(JSONObject.toJSONString(dataPacket));};break;//列出服务器所有在线用户case LIST_ONLINE_USER: {DataPacket dataPacket = DataPacket.builder().opType(opType.name()).message(Message.builder().from(currentUserName).build()).build();pw.println(JSONObject.toJSONString(dataPacket));};break;//创建群聊case CREATE_GROUP:{String groupName = getInput("请输入群聊名称", scanner);String groupUsers = getInput("请输入群聊用户,多个用,隔开", scanner);//封装数据包JSONObject groupObject = new JSONObject();groupObject.put("groupName", groupName);groupObject.put("groupUsers", groupUsers);DataPacket dataPacket = DataPacket.builder().opType(CREATE_GROUP.name()).message(Message.builder().from(currentUserName).messageBody(groupObject.toJSONString()).build()).build();pw.println(JSONObject.toJSONString(dataPacket));};break;//群发消息case SEND_TO_GROUP:{String groupName = getInput("请输入群发群聊", scanner);String content = getInput("请输入要发送的消息", scanner);JSONObject groupObject = new JSONObject();groupObject.put("groupName", groupName);groupObject.put("content", content);DataPacket packet = DataPacket.builder().opType(SEND_TO_GROUP.name()).message(Message.builder().from(currentUserName).messageBody(groupObject.toJSONString()).build()).build();pw.println(JSONObject.toJSONString(packet));}}}}/*** 开启新线程,并行处理服务器输入** @param br*/private static void handlerSocketInput(BufferedReader br) throws Exception {new Thread(() -> {while (true) { // 客户端的输入监听线程需要一直while true 循环读取每一次的数据包try {DataPacket dataPacket = DataPacket.acceptMessage(br);OpType opType = OpType.valueOf(dataPacket.getOpType());switch (opType) {case SEND_TO_USER: {Message message = dataPacket.getMessage();String sender = message.getFrom();String messageBody = message.getMessageBody();System.out.println("\n" + sender + " 对你说:" + messageBody);};break; //这里break将跳出循环case LIST_ONLINE_USER: {Message message = dataPacket.getMessage();String messageBody = message.getMessageBody();System.out.println("\n" + "当前服务在线用户 " + messageBody);};break;case CREATE_GROUP: {Message message = dataPacket.getMessage();String messageBody = message.getMessageBody();System.out.println("\n" + "群消息:" + messageBody);};break;//接收群聊消息case SEND_TO_GROUP:{Message message = dataPacket.getMessage();String from = message.getFrom();String messageBody = message.getMessageBody();JSONObject jsonObject = JSONObject.parseObject(messageBody);String groupName = jsonObject.getString("groupName");String content = jsonObject.getString("content");System.out.println("\n来自[" + groupName + "]的群消息,群成员[" + from + "]对大家说:" + content);}}} catch (Exception e) {e.printStackTrace();break;}}}).start();}public static String getInput(String placeHolder, Scanner scanner) {System.out.print(placeHolder + ":");String s = scanner.nextLine();return s;}}
运行查看

由于需要启动多个客户端窗口,需要复制出多个chatclient程序。

  1. 点击Servrice ,创建Application分组,Application是普通Java程序Main方法的分组。
    在这里插入图片描述

  2. 复制出4个客户端。
    在这里插入图片描述

  3. 启动并运行
    单发消息
    在这里插入图片描述
    在这里插入图片描述

群发消息

在这里插入图片描述

在这里插入图片描述

  • 客户端分线程

由于客户端使用的是scanner从标准输入中读取字节数据,而这个操作是阻塞的,此时如果不开启一个分线程,那么用户就会一直被标准输入阻塞,而无法处理服务器的响应的数据。当然,如果涉及到主线程和分线程之前的通信协作,就需要借助wait、notify等方法实现。

  • 网络与文件的输入缓冲区

对于一个输入流来说,它的数据来源可能是从标准输入(控制台)、文件输入、网络输入,其中对于文件输入来说,这个输入流能读取到的内容大小是固定的,因为一个文件的大小就是固定的。如果使用字节输入流读取,读取不到内容时就会返回-1。
而对于标准输入或者网络输入来说,一个输入流不知道读到到什么地方才能算结束,那这个时候如果输入缓冲区中已经没有可读的数据了,则就会阻塞。所以要通过协议约定,例如在标准输入时,告诉控制台以用户按下回车为结束,在网络输入时,以读取到固定长度的字节或者读取到某个字符时为结束,这样就保证了一次完整的数据传输。

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

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

相关文章

【Uniapp-Vue3】Prop校验与prop默认值用法及循环遍历数组对象

一、prop校验 如果我们在想要限制prop的类型&#xff0c;就可以在接收prop的时候对接收类型进行限制&#xff1a; defineProps({ 属性名:{ type:类型 } }) 需要注意类型的首字母大写 但是设置了传入参数类型限制并不能严格限制&#xff0c;只会在后台进行提示&#xff1a; 二、…

抢十八游戏

前言 我国民国一直流传着一个名叫“抢十八”的抢数游戏&#xff1a;参与游戏的两人从1开始轮流报数&#xff0c;每次至少报1个数&#xff0c;最多报2个数&#xff0c;每人报的每个数不得与自已报过的或对方报过的重复&#xff0c;也不得跳过任何一个数。谁先报到18&#xff0c…

Java Stream流操作List全攻略:Filter、Sort、GroupBy、Average、Sum实践

在Java 8及更高版本中&#xff0c;Stream API为集合处理带来了革命性的改变。本文将深入解析如何运用Stream对List进行高效的操作&#xff0c;包括筛选&#xff08;Filter&#xff09;、排序&#xff08;Sort&#xff09;、分组&#xff08;GroupBy&#xff09;、求平均值&…

STM32特殊功能引脚详解文章·STM32特殊功能引脚能当作GPIO使用嘛详解!!!

目录 STM32特殊功能引脚 使用STM32特殊功能引脚函数 禁止搬运&#xff0c;仅供学习&#xff0c;编写不易&#xff0c;感谢理解&#xff01;&#xff01;&#xff01; STM32特殊功能引脚 本篇详解文章仅以STM32F103C8T6芯片来讲解&#xff0c;STM32芯片除了普通的GPIO引脚以外…

iOS - runtime总结

详细总结一下 Runtime 的核心内容&#xff1a; 1. 消息发送机制 // 消息发送的基本流程 id objc_msgSend(id self, SEL _cmd, ...) {// 1. 获取 isaClass cls object_getClass(self);// 2. 查找缓存IMP imp cache_getImp(cls, _cmd);if (imp) return imp(self, _cmd, ...);…

操作系统八股文学习笔记

总结来自于javaguide,本文章仅供个人学习复习 javaguide操作系统八股 操作系统主要的两大块,进程线程(利用CPU),内存分页(利用内存) 文章目录 操作系统基础什么是操作系统?操作系统主要有哪些功能?常见的操作系统有哪些?用户态和内核态为什么要有用户态和内核态?只有一个…

kube-prometheus监控Linux主机

参考 https://blog.51cto.com/u_11880730/11223693 https://github.com/prometheus/node_exporter tar zxvf node_exporter-1.8.2.linux-amd64.tar.gz -C /usr/local/ cd /usr/local/ mv node_exporter-1.0.1.linux-amd64 node_exportervim /usr/lib/systemd/system/node_ex…

ExplaineR:集成K-means聚类算法的SHAP可解释性分析 | 可视化混淆矩阵、决策曲线、模型评估与各类SHAP图

集成K-means聚类算法的SHAP可解释性分析 加载数据集并训练机器学习模型 SHAP 分析以提取特征对预测的影响 通过混淆矩阵可视化模型性能 决策曲线分析 模型评估&#xff08;多指标和ROC曲线的目视检查&#xff09; 带注释阈值的 ROC 曲线 加载 SHAP 结果以进行下游分析 与…

docker实际应用记录

docker 删除之前的镜像的命令 要删除 Docker 中之前的镜像,可以使用 docker rmi 命令。在执行此命令之前,确保没有容器正在使用这些镜像。如果镜像被某个容器使用,则需要先移除该容器。 这里有几个常用的命令来删除 Docker 镜像: 1. 删除单个指定的镜像: docker rmi <…

【Python通过UDP协议传输视频数据】(界面识别)

提示&#xff1a;界面识别项目 前言 随着网络通信技术的发展&#xff0c;视频数据的实时传输在各种场景中得到了广泛应用。UDP&#xff08;User Datagram Protocol&#xff09;作为一种无连接的协议&#xff0c;凭借其低延迟、高效率的特性&#xff0c;在实时性要求较高的视频…

浅谈云计算03 | 云计算的技术支撑(云使能技术)

云计算的技术支撑 一、定义与内涵1.1 定义与内涵 二、云计算使能技术架构2.1 宽带网络和 Internet 架构2.2 数据中心技术2.3 虚拟化技术2.4 Web 技术2.5 多租户技术2.6 服务技术 一、定义与内涵 1.1 定义与内涵 云计算技术包含一些基础的关键技术&#xff0c;这里称为使能技术…

SQL LAST()

SQL中的LAST()函数是一个用于返回指定列中最后一个记录值的函数。然而&#xff0c;需要注意的是&#xff0c;这个函数并不是SQL标准的一部分&#xff0c;因此并不是所有数据库系统都支持它。具体来说&#xff0c;只有MS Access直接支持LAST()函数【0†source】。 在其他数据库…

QGraphicsView QGraphicsScene QGraphicsItem

QGraphicsView && QGraphicsScene &#xff1a; QGraphicsView 是 Qt 中用于显示和交互处理 2D 图形的控件&#xff0c;QGraphicsView 用于显示 QGraphicsScene 中的内容。 .h #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow> #include &…

【大数据】机器学习-----线性模型

一、线性模型基本形式 线性模型旨在通过线性组合输入特征来预测输出。其一般形式为&#xff1a; 其中&#xff1a; x ( x 1 , x 2 , ⋯ , x d ) \mathbf{x}(x_1,x_2,\cdots,x_d) x(x1​,x2​,⋯,xd​) 是输入特征向量&#xff0c;包含 d d d 个特征。 w ( w 1 , w 2 , ⋯ ,…

基于千帆(ERNIE-Functions-8K)Function Calling的简单使用

1.Function Calling是什么&#xff1f; 1.1 概念 Function calling是一种将LLM(大语言模型Large language model)连接外部工具的能力&#xff0c;LLM经过微调后&#xff0c;可以检测出何时需要调用函数以及需要调用函数的方法名及参数&#xff0c;并返回给调用方以便调用外部…

Deep Attentional Guided Image Filtering

This work achieved the first place in the real depth map SR challenge held in ACM ICMR 2021. 目的&#xff1a;从一个target image(如低分辨的深度图)和guidance image(如高分辨的RGB图)&#xff0c;得到输出(如高分辨的深度图)。 主要思想是考虑了target和guidance之间的…

SpringBoot+Lombok项目实体属性名xXxx格式,前端接收不到

问题解析 今天发现后端传给前端的实体类中&#xff0c;有属性为xXxxx格式的&#xff0c;前端也使用相同名称接收&#xff0c;结果却不显示值&#xff01;研究了一会发现接口请求回来后&#xff0c;原xXxxx的属性名&#xff0c;会被转为全小写。具体原因为&#xff1a;使用Lombo…

ubuntu 配置OpenOCD与RT-RT-thread环境的记录

1.git clone git://git.code.sf.net/p/openocd/code openocd 配置gcc编译环境 2. sudo gedit /etc/apt/source.list #cdrom sudo apt-get install git sudo apt-get install libtool-bin sudo apt-get install pkg-config sudo apt-install libusb-1.0-0-dev sudo apt-get…

高级运维:shell练习2

1、需求&#xff1a;判断192.168.1.0/24网络中&#xff0c;当前在线的ip有哪些&#xff0c;并编写脚本打印出来。 vim check.sh #!/bin/bash# 定义网络前缀 network_prefix"192.168.1"# 循环遍历1-254的IP for i in {1..254}; do# 构造完整的IP地址ip"$network_…

为深度学习创建PyTorch张量 - 最佳选项

为深度学习创建PyTorch张量 - 最佳选项 正如我们所看到的&#xff0c;PyTorch张量是torch.Tensor​ PyTorch类的实例。张量的抽象概念与PyTorch张量之间的区别在于&#xff0c;PyTorch张量为我们提供了一个可以在代码中操作的具体实现。 在上一篇文章中&#xff0c;我们看到了…