网络通讯聊天工具的实现

学习网络与通信,实现聊天界面能够通过服务器进行私聊和群聊的功能。

1.服务器:ServeSocket

客户端先发送消息给服务器,服务器接受消息后再发送给客户端。

利用服务器随时监听。等待客户端的请求,一旦有请求便生产一个socket套接字用于双方之间的数据传输。在此需要指定服务器的端口号。

端口号:区分一个IP地址中套接字。

package ChatV2.Server;
import java.io.IOException;
import java.net.ServerSocket;public class Server {private int port = 50001;ServerSocket serverSocket;{try {serverSocket = new ServerSocket(port);System.out.println("创建服务端成功");ListenerRunnable lr = new ListenerRunnable(serverSocket);new Thread(lr).start();} catch (IOException e) {throw new RuntimeException(e);}}public static void main(String[] args) {new Server();}
}

同时在服务器中我还创建了两个线程,一个用于不断接受新的客户端的连接,一个用于与各客户端的发送接受消息。

1.1接受客户端连接的线程

这个线程需要接受用户端的连接,那么就需要创建的serverSocket对象,利用ServerSocket.accept();方法接受对象,后接受其创建后返回的socket对象。此方法为阻塞方法,一直等待客户端的接入。

并且将此对象放入创建的Socket套接字的队列中,以便使用。

package ChatV2.Server;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.ArrayBlockingQueue;public class ListenerRunnable implements Runnable{private ServerSocket serverSocket;private Socket socket;private OutputStream os;//存放接入的socketprivate static ArrayBlockingQueue<Socket> sockets = new ArrayBlockingQueue<>(10);public ListenerRunnable(ServerSocket serverSocket) {this.serverSocket = serverSocket;}public ListenerRunnable() {}@Overridepublic void run() {while (true) {try {socket = serverSocket.accept();//接受,阻塞方法,//存入到sockets中sockets.offer(socket);System.out.println(socket.getPort() + "连接成功");//savePort();InputStream is = socket.getInputStream();//创建接受信息的线程InformationRunnable ir = new InformationRunnable(is,socket,sockets);//发送给其他所有用户 当前用户的端口号String socketMsg = "3#";for (int i = 0; i < sockets.size(); i++) {Socket temSocket = sockets.poll();System.out.println("发送端口号");socketMsg += temSocket.getPort() + "#";sockets.offer(temSocket);}groupOutput(socketMsg);new Thread(ir).start();} catch (IOException e) {throw new RuntimeException(e);}}}//群发所有端口public void groupOutput(String msg) {try {int size = sockets.size();for (int i = 0; i < size; i++) {System.out.println("多少个用户端:" + sockets.size());Socket temSocket = sockets.poll();os = temSocket.getOutputStream();output(msg);sockets.offer(temSocket);}} catch (IOException e) {throw new RuntimeException(e);}}public void output(String msg) {try {byte[] msgBytes = msg.getBytes(StandardCharsets.UTF_8);//转化为字节型int ml = msgBytes.length;os.write(ml);//大小for (int i = 0; i < msgBytes.length; i++) {os.write(msgBytes[i]);}} catch (IOException e) {throw new RuntimeException(e);}}}

同时在此接受到新客户端的连接后,将此时所有的端口号再转发给所有的客户端用于私聊功能的实现。

输出流的写入实现方法:

利用套接字中OutputStream 与 InputStream 来读取与写入字符

每次写入与读取只能写入/读取一个字节,那么就会存在多个字节如何组成我们想要的字符,以及接受端究竟该接受多少个字符才能写入段的一句完成的对话的问题。

第一个问题的解决:

        只需使用相同的字符编码方式,将字符串类型转化为字节类型中选择UTF-8的字符编码方式,接受端也是用此编码方式 即可保证为相同的字符。

第二个问题的解决:

        我们将字符串转化为字节类型,用数组存储。先将此数组的大小传过去,之后接收端创建相同大小的数组用于接受,接受完后转为字符串即可。

            int ml = is.read();//用于接受字节大小byte[] msgBytes = new byte[ml];//发过来的一串信息for (int i = 0; i < msgBytes.length; i++) {int readByte = is.read();msgBytes[i] = (byte) readByte;}String msg = new String(msgBytes, StandardCharsets.UTF_8);

1.2接受消息与发送消息的线程

这个线程需要判断发过来的信息是群发还是私聊。我的发送过来的消息的格式为“ 字符1# 字符2”如果字符21为0则为群聊,字符二为发送的消息。“字符一#字符二#字符三”如果字符1 为1则为私聊,此时字符二为私聊的端口号,字符三为消息。用‘#’进行分割。

package ChatV2.Server;import java.io.*;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.ArrayBlockingQueue;public class InformationRunnable implements Runnable {private InputStream is;private OutputStream os;private Socket socket;private ArrayBlockingQueue<Socket> sockets;public InformationRunnable(InputStream is, Socket socket, ArrayBlockingQueue<Socket> sockets) {this.is = is;this.socket = socket;this.sockets = sockets;}@Overridepublic void run() {while (true) {getIMG();}}//接受消息public void getIMG() {try {System.out.println("客户端说:");int ml = is.read();//用于接受字节大小byte[] msgBytes = new byte[ml];//发过来的一串信息for (int i = 0; i < msgBytes.length; i++) {int readByte = is.read();msgBytes[i] = (byte) readByte;}String msg = new String(msgBytes, StandardCharsets.UTF_8);String[] msg1 = msg.split("#");//分开if (msg1[0].equals("0")) {//群聊System.out.println("群聊消息:");groupOutput(msg1[1] + "#");} else {//私聊 确认发送对象System.out.println("私聊消息:");String msg0 = "";//发送给发送信息的人int size = sockets.size();for (int i = 0; i < size; i++) {System.out.println("查找私聊对象");Socket temSocket = sockets.poll();if (msg1[1].equals(String.valueOf(temSocket.getPort()))) {//给私聊对象发送os = temSocket.getOutputStream();msg1[2] = "私聊:" + msg1[2] +"#";msg0 = "私聊给:" + msg1[1] + msg1[2] +"#";output(msg1[2]);}sockets.offer(temSocket);}//发送给消息对象os = socket.getOutputStream();output(msg0);}} catch (IOException e) {throw new RuntimeException(e);}}//群发方式public void groupOutput(String msg) {try {int size = sockets.size();for (int i = 0; i < size; i++) {System.out.println("多少个用户端:" + sockets.size());Socket temSocket = sockets.poll();os = temSocket.getOutputStream();output(msg);sockets.offer(temSocket);}} catch (IOException e) {throw new RuntimeException(e);}}//发送消息public void output(String msg) {try {byte[] msgBytes = msg.getBytes(StandardCharsets.UTF_8);//转化为字节型int ml = msgBytes.length;os.write(ml);//大小for (int i = 0; i < msgBytes.length; i++) {os.write(msgBytes[i]);}} catch (IOException e) {throw new RuntimeException(e);}}//以端点命名的文件,将端点及聊天内容全部写入文件过来。public synchronized void saveInformation(String information) throws IOException {String path = "C:\\Users\\15697\\IdeaProjects\\Pro24\\src\\Chat\\UsersInformation\\document";FileWriter fw = new FileWriter(path, true);BufferedWriter bw = new BufferedWriter(fw);bw.write(information);bw.write("#");//分割消息System.out.println("写入消息:" + information);bw.close();}
}

将字节数组转化为字符串后,里面split("#");方法将字符串分割为多个字符串数组msg1。判断msg1[0]是否为0来区分群聊或者私聊。

1.21群聊的实现

判断后调用groupOutput()群聊方法。

在这方法会将我们先前存入的socket队列一 一取出并 使用它的outputStream发送消息

    public void groupOutput(String msg) {try {int size = sockets.size();for (int i = 0; i < size; i++) {System.out.println("多少个用户端:" + sockets.size());Socket temSocket = sockets.poll();os = temSocket.getOutputStream();output(msg);sockets.offer(temSocket);}} catch (IOException e) {throw new RuntimeException(e);}}//发送消息public void output(String msg) {try {byte[] msgBytes = msg.getBytes(StandardCharsets.UTF_8);//转化为字节型int ml = msgBytes.length;os.write(ml);//大小for (int i = 0; i < msgBytes.length; i++) {os.write(msgBytes[i]);}} catch (IOException e) {throw new RuntimeException(e);}}

1.22私聊的实现

         与群聊不同的是他需要判断私聊的对象。将各个套接字取出后对比msg1[1]与各个套接字的端口号。找到了则取出它的输出流,设置发送的字符,调用output()方法即可。同时需要发送给消息的发送者,让其显示在界面上。

                System.out.println("私聊消息:");String msg0 = "";//发送给发送信息的人int size = sockets.size();for (int i = 0; i < size; i++) {System.out.println("查找私聊对象");Socket temSocket = sockets.poll();if (msg1[1].equals(String.valueOf(temSocket.getPort()))) {//给私聊对象发送os = temSocket.getOutputStream();msg1[2] = "私聊:" + msg1[2] +"#";msg0 = "私聊给:" + msg1[1] + msg1[2] +"#";output(msg1[2]);}sockets.offer(temSocket);}//发送给消息对象os = socket.getOutputStream();output(msg0);

到此服务器的接受与发送功能以实现。

2.客户端:

需要知道服务器的ip以及端口号,设置即可

package ChatV2.Client;import ChatV2.DATA;import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.StandardCharsets;public class Clint implements DATA {private Socket socket;//IP 端点public int getPort() {return socket.getLocalPort();}private OutputStream os;private InputStream is;public InputStream getInputStream() {return is;}{try {socket = new Socket("127.0.0.1", 50001);os = socket.getOutputStream();is = socket.getInputStream();} catch (IOException e) {/* throw new RuntimeException(e);*/System.out.println("无法连接服务器");}}public void output(String msg, int index) {try {//使用#隔开 第一个为类型,第二个为端口号,第三部分为内容 0为私聊String s = "";if (IMG[1] == 0) {s += IMG[1] + "#" + msg;} else {s += IMG[1] + "#" + PORT.get(index) + "#" + msg;}System.out.println("待发送消息:" + s);byte[] msgBytes = s.getBytes(StandardCharsets.UTF_8);int ml = msgBytes.length;os.write(ml);for (int i = 0; i < ml; i++) {os.write(msgBytes[i]);}} catch (IOException e) {throw new RuntimeException(e);}}
}

同时我在里面写了一个发送给服务器信息的方法output(String msg,int index)msg为发送的信息,格式与服务器接受的格式一致,index则为接受服务端发送端口号后,存入的信息数组的下标,以便确认私聊对象。

其他的交给界面UI来实现。

3.聊天界面:

结构:以及在此调用用户端。

DATA接口中创建了存放界面需要多次使用的数据。用户的端口号,以及生成的单选按钮,选择聊天对象,以及数据。


import javax.swing.*;
import java.util.ArrayList;public interface DATA {//存放用户ArrayList<String> PORT = new ArrayList<>();//用来存放按钮,表示各用户JRadioButton[] JRB = new JRadioButton[10];//下标0为记录连接人数以及群聊。1为聊天方式为群聊或私聊int[] IMG = new int[2];
}

界面的设置不多说:

package ChatV2;
import ChatV2.Client.Clint;import javax.swing.*;
import java.awt.*;public class ChatUI extends JFrame implements DATA{Clint clint;public ChatUI() {setTitle("MyChat");setSize(900, 700);setLayout(null);setDefaultCloseOperation(EXIT_ON_CLOSE);//按钮组ButtonGroup bg = new ButtonGroup();//setLayout(new FlowLayout());JLabel jl = new JLabel("群聊");//输入框JTextArea jta = new JTextArea();jta.setBounds(10, 500, 700, 200);//JScrollPane scrollPane = new JScrollPane(jta);//翻页的作用//scrollPane.setJButton jb = new JButton("发送");//需添加监听jb.setBounds(710, 550, 75, 50);ButtonListener bl = new ButtonListener(jta);jb.addActionListener(bl);//显示框:JTextArea chatArea = new JTextArea( );//几行几列// chatArea.setPreferredSize(new Dimension(500,480));chatArea.setBounds(10,10,700,480);//设置不可编辑chatArea.setEditable(false);//添加滚动功能JScrollPane scrollPane = new JScrollPane(chatArea);add(scrollPane,BorderLayout.CENTER);//放置界面的中心add(chatArea);//刷新列表按钮JButton jb1 = new JButton("刷新列表");jb1.addActionListener(bl);jb1.setBounds(750,30,100,30);JRadioButton jrb1 = new JRadioButton("群聊");bg.add(jrb1);IMG[0] = 1;JRB[IMG[0]-1] = jrb1;add(jrb1);add(jb1);add(jb);add(jta);add(jl);setVisible(true);clint = new Clint();bl.clint = clint;//用户端传过去bl.ui = this;bl.chatArea = chatArea;Thread thread = new Thread(new ChatRunnable(chatArea,clint.getInputStream(),this,bg));thread.start();}@Overridepublic void paint(Graphics g) {super.paint(g);System.out.println("加载列表");System.out.println("人数:"+IMG[0]);if(IMG[0] != 0){for (int i = 0; i <= IMG[0]; i++) {JRB[i].setBounds(750,80+i*40,100,30);}}}public static void main(String[] args) {new ChatUI();}
}

注:重写paint()方法,对单选按钮进行位置及大小的设置。

同时需要将单选按钮加入一个组 ButtonGroup创建的组中才能实现不能多选的功能。

同时需要按钮的监听,以及一个随时接受消息,并显示在聊天区域的线程。线程在打开UI时就启动。

3.1按钮监听的实现内容:

目前有两个按钮,一个为“发送”,一个为“刷新列表”。

“发送”:发送信息给服务器。获取文本后调用clint中output()的方法。实现发送信息

“刷新列表”:调用repaint()进行重绘。当有新的客户端接入的时候则点击“刷新列表”,即可选择新的客户进行私聊。

package ChatV2;import ChatV2.Client.Clint;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;public class ButtonListener implements ActionListener, DATA {JTextArea jta;Clint clint;JFrame ui;JTextArea chatArea;public ButtonListener(JTextArea jta) {this.jta = jta;}@Overridepublic void actionPerformed(ActionEvent e) {String ae = e.getActionCommand();if (ae.equals("发送")) {//按一次发送一次文件System.out.println("获取文本");//获取文本,启动用户端String msg = clint.getPort()+":"+jta.getText();//获取后清空jta.setText(null);//发送信息int index = groupOrPrivate();clint.output(msg,index);System.out.println("下标"+ index);} else if (ae.equals("刷新列表")) {System.out.println("刷新列表");ui.repaint();}}//监控按钮此时为群聊或者私聊public int groupOrPrivate(){Boolean[] b = new Boolean[IMG[0]+1];for (int i = 0; i < b.length; i++) {b[i] = JRB[i].isSelected();}System.out.println(Arrays.toString(b));for (int i = 0; i < b.length; i++) {System.out.println("判断私聊or群聊");if(b[0]){IMG[1] = 0;//群聊System.out.println("群聊");return -1;} else if (b[i]) {System.out.println("私聊");IMG[1] = 1;//私聊//此时的i,端口。return i-1;}}System.out.println("判断失败,自动为群聊");return -1;}
}

实现了一个判断此时选择的是群聊还是私聊,以及选择私聊的对象的下标。

当为群聊返回-1,私聊则返回其存在DATA接口中端口号在PORT数组中的下标。如果没选则默认为群聊,返回-1;

3.2接受消息的线程:

package ChatV2;import javax.swing.*;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;public class ChatRunnable implements Runnable, DATA {InputStream is;JTextArea chatArea;JFrame ui;ButtonGroup bg;public ChatRunnable(JTextArea chatArea, InputStream is, JFrame ui, ButtonGroup bg) {this.is = is;this.chatArea = chatArea;this.ui = ui;this.bg = bg;}@Overridepublic void run() {while (true) {//接受消息try {int ml ;//用于接受字节大小ml = is.read();byte[] msgBytes = new byte[ml];//发过来的一串信息for (int i = 0; i < msgBytes.length; i++) {int readByte = is.read();msgBytes[i] = (byte) readByte;}String msg = new String(msgBytes, StandardCharsets.UTF_8);String[] msg1 = msg.split("#");if (msg1[0].equals("3")) {//为端口记录号System.out.println("接受消息为端口号");int size = msg1.length;int count = 0;PORT.clear();for (int i = 1; i < size; i++) {PORT.add(msg1[i]);count++;}IMG[0] = count;addUser();} else {sendMsg(msg1[0]);System.out.println("接受到消息:" + msg);}} catch (IOException e) {throw new RuntimeException(e);}}}public void sendMsg(String msg) {chatArea.append(msg + "\n");//发送后换行chatArea.setCaretPosition(chatArea.getDocument().getLength());//跳转到最新消息}//创建新的用户,并存入按钮中public void addUser() {for (int i = 1; i <= IMG[0]; i++) {JRadioButton jrb = new JRadioButton(PORT.get(i-1));JRB[i] = jrb;bg.add(jrb);ui.add(jrb);}System.out.println("已有新用户加入,共" + IMG[0] + "个用户连接,请刷新列表");}
}

方法:

1.sendMsg(String msg);将字符串msg添加到界面的聊天显示界面中,同时调转到发送消息的最下面。

2.addUser();将读取的端口号重新设置在新的单选按钮中,并添加好组,以及添加到界面。

线程功能:接受发送过来的字节,并转为字符串。接着将其用“#”进行分割为字符串数组。

msg1[0]为"3"则为发送的端口号,将后面的进行存储。其他则为私聊或者群聊的消息,调用sendMsg();显示在聊天区域即可。

聊天工具的最终实现效果:

一个用户连接:

第二个用户连接后:

第一个界面刷新前:刷新后:

第三个用户的加入:

聊天功能:

群聊:

私聊:未选择客户端接受不到。

不足:

功能不够齐全。加上文件的发送等功能。

代码的优化。

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

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

相关文章

模型实战(20)之 yolov8分类模型训练自己的数据集

yolov8分类模型训练自己的数据集 yolov8,一个实时快速的端到端的集检测、分割、分类、姿态识别于一体的视觉算法库/框架本文将给出yolov8 分类模型的数据集制作格式及训练流程 1. 环境搭建 关于虚拟环境的搭建真的是老生常谈了,给出一个简单的搭建流程吧#新建虚拟环境 conda …

软件系统开发标准流程文档(Word原件)

目的&#xff1a;规范系统开发流程&#xff0c;提高系统开发效率。 立项申请需求分析方案设计方案评审开发调整测试阶段系统培训试运行测试验收投入使用 所有文档过去进主页获取。 软件项目相关全套精华资料包获取方式①&#xff1a;点我获取 获取方式②&#xff1a;本文末个人…

《Ai企业知识库》-模型实践-rasa开源学习框架-搭建简易机器人-环境准备(针对windows)-02

rasa框架 Conversational AI Platform | Superior Customer Experiences Start Here 阿丹: 其实现在可以使用的ai的开发框架有很多很多&#xff0c;就需要根据各个模型的能力边界等来讨论和设计。 rasa整体流程以及每一步的作用 NLU(自然语言理解): 自然语言理解&#xff…

【项目问题解决】 java.lang.IllegalArgumentException: XML fragments parsed

java.lang.IllegalArgumentException: XML fragments parsed from previous mappers does not contain value for com.xxx.xxx.xxx.xxx.dao.SingleApasInfoDao.selectListCondition 目录 【项目问题解决】 java.lang.IllegalArgumentException: XML fragments parsed from pr…

嵌入式之译码器

系列文章目录 译码器嵌入式之译码器 嵌入式之译码器 系列文章目录一、译码器定义二、常见类型的译码器三、工作原理 一、译码器定义 译码器&#xff08;Decoder&#xff09;是一种数字电路&#xff0c;其主要功能是从输入的编码信号中解码出特定的信息或控制信号。 译码器通常…

树与二叉树的概念介绍

一.树的概念及结构&#xff1a; 1.树的概念&#xff1a; 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的 有…

【记录】初次本地搭建的模型-MiniCPM 2B

前言 查阅众多开源大模型后&#xff0c;打算动手尝试搭建端侧模型&#xff0c;看看效果。选中MiniCPM主要是因为参数小&#xff0c;同时中文支持相对较好。 首先对按照官网提供的demo进行了尝试&#xff0c;然后在colab中完成了一个webui程序并测试&#xff0c;最后通过docker环…

【MATLAB】去除趋势项(解决频谱图大部分为零的问题)

1.概 述 在许多实际信号分析处理中信号经FFT变换后得到的频谱谱线值几乎都为0&#xff0c;介绍这是如何形成的&#xff0c;又该如何去解决。 2.案例分析 读入一组实验数据文件(文件名为qldata.mat)&#xff0c;作出该组数据的频谱图。程序清单如下: clear; clc; close all;…

3.5 四个子空间的维度

一、概述 这一节的主要定理是将秩与维度联系在一起。矩阵的秩就是主元的个数&#xff0c;子空间的维度是基向量的个数&#xff0c;我们计算出这两个数就可以得到秩与维度。 A A A 的秩揭露了四个基本子空间的维度。 四个子空间中&#xff0c;两个子空间来自 A A A&#xff0c…

第十七讲:结构体

第十七讲&#xff1a;结构体 1.初始结构体1.1结构体声明1.2结构体变量的创建和初始化1.2.1结构体变量的创建1.2.2结构体变量的初始化1.2.2.1普通初始化1.2.2.2结构体数组1.2.2.3结构体指针 1.3typedef定义结构体1.4结构体的自引用1.5结构体的特殊声明 2.结构体内存对齐2.1对齐规…

基于STM32实现智能空气净化系统

目录 引言环境准备智能空气净化系统基础代码示例&#xff1a;实现智能空气净化系统 空气质量传感器数据读取风扇和滤网控制显示系统用户输入和设置应用场景&#xff1a;家庭空气净化与健康管理问题解决方案与优化收尾与总结 1. 引言 本教程将详细介绍如何在STM32嵌入式系统中…

Day 40 Web容器-Tomcat

Tomcat 一&#xff1a;Tomcat简介 1.简介 ​ Tomcat是Apache软件基金会&#xff08;Apache Software Foundation&#xff09;的Jakarta 项目中的一个核心项目 ​ Tomcat服务器是一个免费的开放源代码的Web应用服务器&#xff0c;属于轻量级应用服务器 ​ Tomcat是WEB容器/WE…

idea中git拉取失败

之前clone好好的&#xff0c;今天突然就拉取不下来了。很多时候是用户凭证的信息没更新的问题。由于window对同一个地址都存储了会话。如果是新的会话&#xff0c;必须要更新window下的凭证。 然后根据你的仓库找到你对应的账户&#xff0c;更新信息即可。

aws lakeformation跨账号共享数据的两种方式和相关配置

lakeformation授权方式分为 基于tag的授权基于命名资源的授权 先决条件 跨账号共享数据的先决条件&#xff08;命名资源和tag授权都需要&#xff09; 分两种情况 如果账户中没有glue data catalog资源策略&#xff0c;则LakeFormation跨账户授予将照常进行 如果存在glue d…

Docker学习(4):部署web项目

一、部署vue项目 在home目录下创建项目目录 将打包好的vue项目放入该目录下&#xff0c;dist是打包好的vue项目 在项目目录下&#xff0c;编辑default.conf 内容如下&#xff1a; server {listen 80;server_name localhost; # 修改为docker服务宿主机的iplocation / {r…

面试手撕——使用两个线程交替打印1-100

记录一下使用两个线程交替打印1-100的操作: /*** description: 使用两个线程交替打印1-100* author: Jay* create: 2024-05-27 21:29**/ public class print_1_to_100 {static volatile int flag 1; //此处需要加关键字volatile保证变量之间的可见性&#xff0c;否则程序将会…

Android:使用Kotlin搭建MVI架构模式

一、简介MVI架构模式 M&#xff1a;Model 数据层&#xff0c;包含应用数据和业务逻辑V&#xff1a;View 界面层&#xff0c;在屏幕上显示应用数据&#xff0c;包含与界面相关的状态和界面逻辑&#xff0c;根据界面状态对象更新UI&#xff0c;界面状态定义是不可变的。这样的主要…

【Spring Cloud】服务熔断

目录 服务雪崩效应服务雪崩效应形成的原因及应对策略小结 Hystrix介绍Hystrix可以做什么1.资源隔离2.请求熔断3.服务降级 小结 Hystrix实现服务降级方式一&#xff1a;HystrixCommand注解方式1.服务提供者1.1业务接口和业务实现中添加方法hystrixTimeout1.2控制器中处理/provid…

【pm2 - sdk 集成到程序中,典型用法】

pm2作为一款进程管理神器&#xff0c;除了命令行的启动方式外&#xff0c;其还对应有sdk&#xff0c;集成到程序中&#xff0c;我们可以连接到已有或创建pm2的守护进程&#xff0c;与其进行交互&#xff0c;动态&#xff0c;编程式地控制程序的启停等。以下为示例&#xff1a; …

c++ - vector容器常用接口模拟实现

文章目录 一、成员变量二、常用迭代器接口模拟实现三、一些常用接口模拟四、默认成员函数五、功能测试 一、成员变量 我们通过在堆上申请一个数组空间来进行储存数据&#xff0c;我们的成员变量是三个指针变量&#xff0c;分别指向第一个位置、最后储存有效位置的下一个位置以…