基于BIO模式下通信项目

2023-11-07

功能清单

1.客户端登陆功能

  • 可以启动客户端进行登录,客户端登陆只需要输入用户名和服务端ip地址即可。

2.在线人数实时更新。

  • 客户端用户户登陆以后,需要同步更新所有客户端的联系人信息栏。

3.离线人数更新

  • 检测到有客户端下线后,需要同步更新所有客户端的联系人信息栏。

4.群聊

  • 任意一个客户端的消息,可以推送给当前所有客户端接收。

5.私聊

  • 可以选择某个员工,点击私聊按钮,然后发出的消息可以被该客户端单独接收。

6.@消息

  • 可以选择某个员工,然后发出的消息可以@该用户,但是其他所有人都能

7.消息用户和消息时间点

  • 服务端可以实时记录该用户的消息时间点,然后进行消息的多路转发或者选择。

代码结构

在这里插入图片描述

服务端设计

在这里插入图片描述

接收多个客户端逻辑

服务端需要接收多个客户端的接入

  • 服务端需要接收多个客户端,目前我们采取的策略是一个 客户端对应一个服务端线程
  • 服务端除了要注册端口以外,还需要为每个客户端分配 一个独立线程处理与之通信

服务端主体代码,主要进行端口注册,和接收客户端,分配线程处理该客户端请求

接收登陆消息及监测离线

  • 在上面我们实现了服务端可以接收多个客户端,然后服务端可以接收多个客户端连接,接下来我们要接收客户端的登陆消息。
  • 我们需要在服务端处理客户端线程的登陆消息。
  • 需要注意的是,服务端需要接收客户端的消息可能有很多种,分别是登陆消息,群聊消息,私聊消息和@消息。
  • 这里需要约定如果客户端发送消息之前需要先发送消息的类型,类型我们使用信号值标志(1,2,3)。
    • 1代表接收的是登陆消息
    • 2代表群发| @消息
    • 3代表了私聊消息
  • 服务端的线程中有异常校验机制,一旦发现客户端下线会在异 常机制中处理,然后移除当前客户端用户,把最新的用户列表 发回给全部客户端进行在线人数更新。

接收群聊消息

  • 在上面实现了接收客户端的登陆消息,然后提取当前在线的全部的用户名称和当前登陆的用户名称,发送给全部在线用户更新自己的在线人数列表。
  • 接下来要接收客户端发来的群聊消息,然后推送给当前在线的所有客户端。

接收私聊消息

  • 解决私聊消息的推送逻辑,私聊消息需要知道推送给某个具体的客户端。
  • 我们可以接收到客户端发来的私聊用户名称,根据用户名称定 位该用户的Socket管道,然后单独推送消息给该Socket管道。

代码实现

public class ServerChat {
    
    /** 定义一个集合存放所有在线的socket  
    *	在线的集合只需要一个:存储客户端socket的同时还需要知道这个Socket客户端的名称
    */
	public static Map<Socket, String> onLineSockets = new HashMap<>();

   public static void main(String[] args) {
      try {
         /** 1.注册端口   */
         ServerSocket serverSocket = new ServerSocket(Constants.PORT);

         /** 2.循环一直等待所有可能的客户端连接 */
         while(true){
            Socket socket = serverSocket.accept();
            /**3. 把客户端的socket管道单独配置一个线程来处理 */
            new ServerReader(socket).start();
         }
      } catch (Exception e) {
         e.printStackTrace();
      }
   }
}
class ServerReader extends Thread {
    
   private Socket socket;
    
   public ServerReader(Socket socket) {
      this.socket = socket;
   }
    
   @Override
   public void run() {
      try {
          // new一个特殊数据输入流等待客户端消息
          dis = new DataInputStream(socket.getInputStream());
          //1.循环一直等待客户端的消息
          while (true){
              //2.读取当前的消息类型:登录,群发,私聊,@消息
              int flag = dis.readInt();
              if(flag == 1){
                  //先将当前登录的客户端socket存到在线人数的socket集合中
                  String name = dis.readUTF();
                  System.out.println(name + "----->" +
                                     socket.getRemoteSocketAddress());
                  ServerChat.onLineSockets.put(socket,name);
              }
              // 只要有人登录就更新所有客户端信息
              writeMsg(flag,dis);
          }
      } catch (Exception e) {
          System.out.println("---有人下线了---");
          ServerChat.onLineSockets.remove(socket);
          try {
              //重新更新在线人数并发给所有客户端
              writeMsg(1,dis);
          }catch (Exception e1){
              e1.printStackTrace();
          }
      }
   }
    
    //输入一个flag再接一个字节输入流
    private void writeMsg(int flag, DataInputStream dis) throws Exception {
        //DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
        //定义一个变量存放最终的消息形式
        String msg = null;
        if(flag == 1){
            //读取所有在线人数发给所有客户端去更新自己的在线人数列表
            StringBuilder rs = new StringBuilder();
            /** onlineNames = [波仔,zhangsan,波妞]*/
            Collection<String> onlineNames = ServerChat.onLineSockets.values();
            //判断是否存在在线人数
            if(onlineNames != null && onlineNames.size() > 0){
                for(String name : onlineNames){
                    rs.append(name + Constants.SPILIT);
                }
                //去掉最后一个分隔符
                msg = rs.substring(0,rs.lastIndexOf(Constants.SPILIT));
                //将消息发送给所有的客户端
                sendMsgToAll(flag,msg);
            }
        }else if(flag == 2 || flag == 3){
            //读到消息 群发的 或则 @消息
            String newMsg = dis.readUTF();//消息
            //得到发件人
            String sendName = ServerChat.onLineSockets.get(socket);
            // 内容--
            StringBuilder msgFinal = new StringBuilder();
            //时间
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss EEE");
            if(flag == 2){//群发消息 和 @消息
             msgFinal.append(sendName).append("").append(sdf.format(System.currentTimeMillis()*2)).append("\r\n");
                msgFinal.append(" ").append(newMsg).append("\r\n");
                sendMsgToAll(flag,msgFinal.toString());
            }else if(flag == 3){//私聊消息
                msgFinal.append(sendName).append(" ").append(sdf.format(System.currentTimeMillis()*2)).append("对您私发\r\n");
                msgFinal.append(" ").append(newMsg).append("\r\n");
                //私发
                //得到发给谁
                String destName = dis.readUTF();
                sendMsgToOne(destName,msgFinal.toString());
            }
        }
    }
    
    /**
    *
    * @param destName 对谁私发
    * @param msg 发的消息内容
    * @throws Exception
    */
    private void sendMsgToOne(String destName, String msg) throws Exception{
        //拿到所有在线的socket管道 给这些管道写出消息
        Set<Socket> allOnLineSockets = ServerChat.onLineSockets.keySet();
        for(Socket sk : allOnLineSockets){
            //得到当前需要私发的Socket
            //只对这个名字对应的socket私发消息
            if(ServerChat.onLineSockets.get(sk).trim().equals(destName)){
                DataOutputStream dos = new
                    DataOutputStream(sk.getOutputStream());
                dos.writeInt(2);//消息类型
                dos.writeUTF(msg);
                dos.flush();
            }
        }
    }
    
    
    private void sendMsgToAll(int flag, String msg) throws Exception {
        //拿到所有的在线socket管道 给这些管道写出消息
        Set<Socket> allOnLineSockets = ServerChat.onLineSockets.keySet();
        for(Socket sk : allOnLineSockets){
            DataOutputStream dos = new DataOutputStream(sk.getOutputStream());
            dos.writeInt(flag);//消息类型
            dos.writeUTF(msg);
            dos.flush();
        }
    }
}

客户端设计

启动客户端界面,登录,刷新在线

  • 启动客户端界面,登陆,刷新在线人数列表
  • 客户端界面主要是GUI设计,主体页面分为登陆界面和聊 天窗口,以及在线用户列表。
  • 登陆输入服务端ip和用户名后,要请求与服务端的登 陆,然后立即为当前客户端分配一个读线程处理客户端 的读数据消息。因为客户端可能随时会接收到服务端那 边转发过来的各种即时消息信息。
  • 客户端登陆完成,服务端收到登陆的用户名后,会立即发 来最新的用户列表给客户端更新。

客户端发送消息逻辑

  • 目标

    客户端发送群聊消息,@消息,以及私聊消息。

  • 实现步骤
    客户端启动后,在聊天界面需要通过发送按钮推送群 聊消息,@消息,以及私聊消息。
    代码实现

代码实现

public class ClientChat implements ActionListener {
   /** 1.设计界面  */
   private JFrame win = new JFrame();
   /** 2.消息内容框架 */
   public JTextArea smsContent =new JTextArea(23 , 50);
   /** 3.发送消息的框  */
   private JTextArea smsSend = new JTextArea(4,40);
   /** 4.在线人数的区域  */
   /** 存放人的数据 */
   /** 展示在线人数的窗口 */
   public JList<String> onLineUsers = new JList<>();

   // 是否私聊按钮
   private JCheckBox isPrivateBn = new JCheckBox("私聊");
   // 消息按钮
   private JButton sendBn  = new JButton("发送");

   // 登录界面
   private JFrame loginView;

   private JTextField ipEt , nameEt , idEt;

   private Socket socket ;

   public static void main(String[] args) {
      new ClientChat().initView();

   }

   private void initView() {
      /** 初始化聊天窗口的界面 */
      win.setSize(650, 600);

      /** 展示登录界面  */
      displayLoginView();

      /** 展示聊天界面 */
      //displayChatView();

   }

   private void displayChatView() {

      JPanel bottomPanel = new JPanel(new BorderLayout());
      //-----------------------------------------------
      // 将消息框和按钮 添加到窗口的底端
      win.add(bottomPanel, BorderLayout.SOUTH);
      bottomPanel.add(smsSend);
      JPanel btns = new JPanel(new FlowLayout(FlowLayout.LEFT));
      btns.add(sendBn);
      btns.add(isPrivateBn);
      bottomPanel.add(btns, BorderLayout.EAST);
      //-----------------------------------------------
      // 给发送消息按钮绑定点击事件监听器
      // 将展示消息区centerPanel添加到窗口的中间
      smsContent.setBackground(new Color(0xdd,0xdd,0xdd));
      // 让展示消息区可以滚动。
      win.add(new JScrollPane(smsContent), BorderLayout.CENTER);
      smsContent.setEditable(false);
      //-----------------------------------------------
      // 用户列表和是否私聊放到窗口的最右边
      Box rightBox = new Box(BoxLayout.Y_AXIS);
      onLineUsers.setFixedCellWidth(120);
      onLineUsers.setVisibleRowCount(13);
      rightBox.add(new JScrollPane(onLineUsers));
      win.add(rightBox, BorderLayout.EAST);
      //-----------------------------------------------
      // 关闭窗口退出当前程序
      win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      win.pack();  // swing 加上这句 就可以拥有关闭窗口的功能
      /** 设置窗口居中,显示出来  */
      setWindowCenter(win,650,600,true);
      // 发送按钮绑定点击事件
      sendBn.addActionListener(this);
   }

   private void displayLoginView(){

      /** 先让用户进行登录
       *  服务端ip
       *  用户名
       *  id
       *  */
      /** 显示一个qq的登录框     */
      loginView = new JFrame("登录");
      loginView.setLayout(new GridLayout(3, 1));
      loginView.setSize(400, 230);

      JPanel ip = new JPanel();
      JLabel label = new JLabel("   IP:");
      ip.add(label);
      ipEt = new JTextField(20);
      ip.add(ipEt);
      loginView.add(ip);

      JPanel name = new JPanel();
      JLabel label1 = new JLabel("姓名:");
      name.add(label1);
      nameEt = new JTextField(20);
      name.add(nameEt);
      loginView.add(name);

      JPanel btnView = new JPanel();
      JButton login = new JButton("登陆");
      btnView.add(login);
      JButton cancle = new JButton("取消");
      btnView.add(cancle);
      loginView.add(btnView);
      // 关闭窗口退出当前程序
      loginView.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      setWindowCenter(loginView,400,260,true);

      /** 给登录和取消绑定点击事件 */
      login.addActionListener(this);
      cancle.addActionListener(this);

   }

   private static void setWindowCenter(JFrame frame, int width , int height, boolean flag) {
      /** 得到所在系统所在屏幕的宽高 */
      Dimension ds = frame.getToolkit().getScreenSize();

      /** 拿到电脑的宽 */
      int width1 = ds.width;
      /** 高 */
      int height1 = ds.height ;

      System.out.println(width1 +"*" + height1);
      /** 设置窗口的左上角坐标 */
      frame.setLocation(width1/2 - width/2, height1/2 -height/2);
      frame.setVisible(flag);
   }

   @Override
   public void actionPerformed(ActionEvent e) {
      /** 得到点击的事件源 */
      JButton btn = (JButton) e.getSource();
      switch(btn.getText()){
         case "登陆":
            String ip = ipEt.getText().toString();
            String name = nameEt.getText().toString();
            // 校验参数是否为空
            // 错误提示
            String msg = "" ;
            // 12.1.2.0
            // \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\
            if(ip==null || !ip.matches("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}")){
               msg = "请输入合法的服务端ip地址";
            }else if(name==null || !name.matches("\\S{1,}")){
               msg = "姓名必须1个字符以上";
            }

            if(!msg.equals("")){
               /** msg有内容说明参数有为空 */
               // 参数一:弹出放到哪个窗口里面
               JOptionPane.showMessageDialog(loginView, msg);
            }else{
               try {
                  // 参数都合法了
                  // 当前登录的用户,去服务端登陆
                  /** 先把当前用户的名称展示到界面 */
                  win.setTitle(name);
                  // 去服务端登陆连接一个socket管道
                  socket = new Socket(ip, Constants.PORT);

                  //为客户端的socket分配一个线程 专门负责收消息
                  new ClientReader(this,socket).start();

                  // 带上用户信息过去
                  DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
                  dos.writeInt(1); // 登录消息
                  dos.writeUTF(name.trim());
                  dos.flush();

                  // 关系当前窗口 弹出聊天界面
                  loginView.dispose(); // 登录窗口销毁
                  displayChatView(); // 展示了聊天窗口了


               } catch (Exception e1) {
                  e1.printStackTrace();
               }
            }
            break;
         case "取消":
            /** 退出系统 */
            System.exit(0);
            break;
         case "发送":
            
            break;

      }

   }
}
public class ClientReader extends Thread {

   private Socket socket;
    // 接收客户端界面,方便收到消息后,更新界面数据。
   private ClientChat clientChat ;

   public ClientReader(ClientChat clientChat, Socket socket) {
      this.clientChat = clientChat;
      this.socket = socket;
   }

   @Override
   public void run() {
      try {
         DataInputStream dis = new DataInputStream(socket.getInputStream());
         /** 循环一直等待客户端的消息 */
         while(true){
            /** 读取当前的消息类型 :登录,群发,私聊 , @消息 */
            int flag = dis.readInt();
            if(flag == 1){
               // 在线人数消息回来了
               String nameDatas = dis.readUTF();
               // 展示到在线人数的界面
               String[] names = nameDatas.split(Constants.SPILIT);

               clientChat.onLineUsers.setListData(names);
            }else if(flag == 2){
              
            }
         }
      } catch (Exception e) {
         e.printStackTrace();
      }
   }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基于BIO模式下通信项目 的相关文章

  • 将特定项目移至列表末尾

    我有一个ArrayList in Java deleteItem createitem exportitem deleteItems createItems 我想移动包含的所有字符串delete到列表的末尾 所以我会得到下一个 create
  • Logback 上下文选择器的实际使用

    Logback 的文档测井分离 http logback qos ch manual loggingSeparation html表明我可以使用上下文选择器 http logback qos ch manual contextSelecto
  • 通过 WebStart 运行时 Java 7 更新 55 JacORB 错误

    自从更新到 Java 7 update 55 以来 我无法运行我的 WebStart java 应用程序 当通过 WebStart 启动时 该应用程序在 Java 7 update 51 下运行良好 当在 WebStart 之外启动时 它还
  • Java 1.4 上的 ActiveMQ 客户端

    我们在最新版本 5 6 0 中使用 Active MQ 现在我们遇到一个问题 必须连接一个新客户端 不幸的是这个客户端是用IBM JDK 1 4开发的 将 ActiveMQ 添加到应用程序会导致以下错误 UNEXPECTED ERROR O
  • setSize() 不起作用?

    我有一个程序 需要两个按钮 一个是常规按钮 另一个具有根据鼠标悬停而变化的图片 目前 由于图片很大 JButton自定义也很大 我可以更改自定义的大小并保持图像 和翻转图像 成比例吗 我尝试过 setSize 但它没有任何作用 对于任何反馈
  • 如何在线程和小程序中使用双缓冲

    我有一个关于何时调用绘制和更新方法的问题 我有游戏小程序 我想在其中使用双缓冲 但我无法使用它 问题是 在我的游戏中 有一个球在 run 方法内移动 我想知道如何使用双缓冲来交换屏幕外图像和当前图像 请有人帮忙 当同时存在 update 和
  • 将 hyperjaxb3 升级到 jpa 2.1

    我正在尝试在使用 maven jpa hibernate 和 hyperjaxb 的 eclipse 项目中升级到 JPA 2 1 当我尝试执行以下操作时出现以下错误Run As Run on Server从日食内部 java lang N
  • Tomcat:Java 静态变量作用域、应用程序范围还是会话范围?

    java 静态变量是否在使用相同 web 应用程序的所有会话之间共享 或者每个会话都有自己的静态变量版本吗 换句话说 Tomcat 是为每个会话创建一组新的类 还是为整个 Web 应用程序创建一组新的类 Tomcat 创建一个ClassLo
  • 在java中查找OSX的版本

    我需要测试 java 中 osx 的版本是否 Try System getProperty os name and or System getProperty os version 它返回字符串 HERE https docs oracle
  • 如何将 java ArrayList 转换为等效的 double[] [重复]

    这个问题在这里已经有答案了 可能的重复 如何在 Java 中从 List 转换为 double https stackoverflow com questions 6018267 how to cast from listdouble to
  • 版本差异? Java 中的正则表达式转义

    看来正则表达式转义在不同版本的 Java 中的工作方式不同 在 Java openjdk 16 0 1 中编译工作正常 在 Java openjdk 11 0 11 中抛出此编译错误 test java 15 error illegal e
  • 我可以直接在 Maven 中使用 GitHub 项目吗?

    我有兴趣使用GitHub 上的项目 https github com toelen spymemcached jcache作为我的项目中的依赖项 GitHub 项目有一个pom文件 我可以修改我的pom文件来使用这个项目 如果是这样 怎么办
  • 更改 WireMock __files 目录

    来自docs http wiremock org docs stubbing 要从文件中读取正文内容 请将文件放在 files 下 目录 默认情况下 这应该位于 src test resources 下 从 JUnit 规则运行时 当独立运
  • 无法为对象堆保留足够的空间

    每次尝试运行该程序时 我都会重复出现以下异常 VM初始化期间发生错误 无法为对象堆保留足够的空间 无法创建Java虚拟机 我尝试增加虚拟内存 页面大小 和 RAM 大小 但无济于事 我怎样才能消除这个错误 运行 JVM XX MaxHeap
  • Windows:如何获取所有可见窗口的列表?

    无论如何都要使用相关技术重新标记 我不知道它们是什么 稍后我可能会提出更详细的问题 关于具体细节 但现在我正在尝试掌握 大局 我正在寻找一种方法来枚举 Windows 上的 真实可见窗口 我所说的 真正可见的窗口 就是指 用户所说的 窗口
  • 无法实例化类对象的类型 (Java)

    这是我收到错误的代码 在 new 之后的第二个 Killer 处 String classes new String 5 kills 0 Brian Moser kills 1 James Doakes kills 2 Lila Tourn
  • Hibernate - 如何通过 Hibernate 将 java.net.URL 存储到数据库中

    我有一块田地URL countryURL in a Country班级 我想将其数据存储到COUNTRY通过 Hibernate 将表存储在数据库中 哪个休眠type我应该在休眠映射文件中使用
  • 尝试模拟静态时出现 NoClassDefFoundError 或 NoSuchMethodError (不兼容的依赖项)

    When a class with static method is mocked an exception been thrown The version 2 0 0 of PowerMock displays NoClassDefFou
  • Spring Boot 和安全性以及自定义 AngularJS 登录页面

    我正在为 Spring Security 实现一个自定义 AngularJS 登录页面 但遇到身份验证问题 遵循本教程 示例 以及他们的示例在本地运行良好 https github com dsyer spring security ang
  • 指定不带组件的GridBagLayout的网格参数

    我试图帮助另一个用户 但遇到了一个问题 我想用 GridBagLayout 来做到这一点 c1 c2 c3 10 80 10 v v r1 B1

随机推荐

  • Linux centos redhat 装NVIDIA显卡驱动

    Linux装显卡驱动 第一步 下载驱动 对应相同型号 下载即可 英伟达驱动下载地址https www nvidia cn Download index aspx lang cn 以 K620为例 如下图 2 下载完成后需要上传至服务器 以U
  • 企业引入人脸识别考勤 想要代打卡?没门!

    近年来 伴随着生物识别技术的进步 越来越多的生物识别技术应用进入市场 冲击各大行业 传统的考勤模式同样面临着来自新兴技术的挑战 以人脸识别技术为首 掀起一场考勤领域的变革 刷脸 考勤 想要代签不容易 传统的 最为人所熟知的考勤模式莫过于磁卡
  • CH11-多媒体应用开发

    目标 掌握MediaPlayer类与SoundPool类的使用 能够实现播放音频文件的功能 掌握VideoView类的使用 能够实现播放视频文件的功能 掌握MediaPlayer类与SurfaceView类的使用 能够实现播放视频文件的功能
  • 一次性解决tensorflow-gpu:library:cusolver64_10.dll/ cudart64_101.dll/cublas64_10.dll not found等

    错误 Could not load dynamic library cudart64 101 dll Could not load dynamic library cublas64 10 dll Could not load dynamic
  • 高速入门知识02:降低串扰和维持信号完整性的布线方法

    文章目录 前言 一 单端走线布线 1 1 带有短截线的菊花链布线 1 2 没有短截线的菊花链布线 1 3 星型布线 1 4 蛇型布线 二 差分走线布线 前言 串扰是并行走线间不需要的信号耦合 微带线和带状线正确的布线和叠层布局能够降低串扰
  • 剑指 Offer 55 - II. 平衡二叉树-- 心得和思路

    Definition for a binary tree node public class TreeNode int val TreeNode left TreeNode right TreeNode int x val x class
  • 0基础学习大数据之大数据技术发展趋势如何

    大数据如今飞速发展 已经逐步开始影响到我们生活的各个角落 同时涌现出了大量新的技术 它们成为大数据采集 存储 处理和呈现的有力武器 那么大数据技术的发展趋势会是怎样的呢 2014年以后 整体大数据的技术栈已经趋于稳定 由于云计算 人工智能等
  • ufs 固态硬盘_UFS究竟是什么?对于手机提升大不大,一文带你了解

    相信很多小伙伴在2020年挑选5G新手机的时候都会看到 UFS 3 0 那这个名称与USB很类似的配置究竟是什么呢 后面的数字是越大越好 还是越小越好 现在就来科普科普 首先UFS闪存的全称Universal Flash Storage 这
  • 朴素贝叶斯(基于sklearn的实现)

    由于自己太懒 不想看太长的代码 所以我就调用的sklearn库的朴素贝叶斯类 数据集选择的是这个博客中自己构造的数据集 该博客自己实现了朴素贝叶斯类 想自己编写一个朴素贝叶斯函数的读者可以参考这个博客 下面是用sklearn库实现朴素贝叶斯
  • verilog_串口实现

    verilog 串口实现 概述 先了解串口的基础知识 串口是怎样传数据的 什么是波特率 波特率怎么计算 说明 通过Verilog编写串口 通过逻辑分析仪与串口模块的对接来进一步了解串口的应用 文章目录 1 什么是波特率 波特率怎么计算 1
  • 2020秋招总结(持续更新)

    开立医疗提前批面试 1 项目讲解 没做准备 讲的不流畅 思路混乱 2 进程拥有的资源 进程地址空间 代码区 数据区 堆栈 内核部分 3 线程的理解 内核级线程 用户级线程 进程与线程的区别 4 线程间通信方式 与进程间通信方式混淆了 线程是
  • 聊聊rocketmq的KVConfigManager

    序 本文主要研究一下rocketmq的KVConfigManager KVConfigManager org apache rocketmq namesrv kvconfig KVConfigManager java public clas
  • win11下配置visual studio 2022+PCL1.13.0

    第一部分 visual studio2022 安装 vs官网网址如下 https visualstudio microsoft com zh hans vs 第一步 我们打开官网链接 按如下操作点击下载免费版本的exe文件 第二步 打开下载
  • 牛客网错题整理(C/C++基础知识回顾)(1)

    1 如下代码输出结果是什么 生存周期问题 include
  • 算法与数据结构-堆

    前言 大四重拾算法与数据结构 所有内容为自己的阶段小结所以并不是技术性文章 如有兴趣阅读 遇到问题不妨给我留个言 万分感谢 堆 堆是一颗完全二叉树 最大堆 根结点的键值是所有堆结点键值中最大者 且每个结点的值都比其孩子的值大 最小堆 根结点
  • Python——ImportError: dynamic module does not define module export function (PyInit_cv_bridge_boost)

    报错截图 在使用已经编译好的python3的cv bridge时 并且正常在 bashrc中加入了source 但是依然报以上错误 解决方法 在 bashrc指定你编译并使用的cv bridge的python的环境变量 添加conda的py
  • C++day3(类、this指针、类中的特殊成员函数)

    一 Xmind整理 二 上课笔记整理 1 类的应用实例 include
  • 【FreeCodeCamp】 ResponsiveWebDesign网页设计 测试1学习笔记

    Learn HTML by building a Cat Photo App https www freecodecamp org learn 2022 responsive web design 标签 优化显示 HTML5 has som
  • JavaScript 实现 -- 冒泡排序

    文章目录 冒泡排序 代码实现 冒泡排序过程 时间复杂度 算法稳定性 冒泡排序 冒泡排序 Bubble Sort 也叫气泡排序 泡沫排序 是一种比较简单的排序算法 它通过遍历数组 比较相邻的两个元素 如果前一个元素比后一个元素大 则交换它们的
  • 基于BIO模式下通信项目

    文章目录 功能清单 代码结构 服务端设计 接收多个客户端逻辑 接收登陆消息及监测离线 接收群聊消息 接收私聊消息 代码实现 客户端设计 启动客户端界面 登录 刷新在线 客户端发送消息逻辑 代码实现 功能清单 1 客户端登陆功能 可以启动客户