网络多线程开发小项目--QQ登陆聊天功能(用户登陆功能实现)

9.1.1用户登陆功能实现

在这里插入图片描述
1、需求分析
在这里插入图片描述
2、代码实现
2.1、Client和Server端共有类
1)cn.com.agree.qqcommon.Message

package cn.com.agree.qqcommon;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.io.Serializable;
@Slf4j
@Data
public class Message implements Serializable {
    public static final long serialVersionUID = 1L;

    private String sender;//发送者
    private String getter;//接受者
    private String content;//消息内容
    private String sendTime;//发送时间
    private String msgType;//消息类型(可以在接口定义消息类型)

}

2)cn.com.agree.qqcommon.User

package cn.com.agree.qqcommon;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.io.Serializable;
@Slf4j
@Data
public class User implements Serializable {

    public static final long serialVersionUID = 1L;

    private String userId;//用户id代表一个用户
    private String passwd;//登陆密码
}

3)cn.com.agree.qqcommon.MessageType

package cn.com.agree.qqcommon;

public interface MessageType {

    //消息类型
    //1、在消息类型中定义一些常量
    //2、不同的常量值代表不同的消息类型
    String MESSAGE_LOG_SUCCESS = "1";//表示登陆成功
    String MESSAGE_LOG_FAIL = "2";//表示登陆失败
}

2.2 QQClient端:
1)界面QQView

package cn.com.agree.qqclient.QQView;

import cn.com.agree.qqclient.service.UserClientService;
import cn.com.agree.qqcommon.User;
import cn.com.agree.util.Utility;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class QQView {

    public static void main(String[] args) {
        new QQView().mainMenu();
        log.debug("退出系统!!!");
    }

    private final UserClientService userClientService = new UserClientService();

    private void mainMenu() {
        String key = "";

        boolean loop = true;//控制程序是显示主菜单
        while (loop) {
            System.out.println("==========欢迎登陆网络通讯系统============");
            System.out.println("======\t\t 1 登陆系统\t\t==========");
            System.out.println("======\t\t 9 退出系统\t\t==========");
            log.debug("请输入你的选择:");
            key = Utility.readString(1);
            switch (key) {
                case "1":
                    log.debug("请输入用户名:");
                    String userId = Utility.readString(300);
                    log.debug("请输入密  码:");
                    String passwd = Utility.readString(1234);
                    //todo 此处去服务端进行用户名密码校验
                    User user = userClientService.checkUser(userId, passwd);
                    if (user != null) {
                        System.out.println("==========欢迎" + userId + "用户=============");
                        while (loop) {
                            System.out.println("==========网络通讯系统二级菜单(用户 " + userId + ")============");
                            System.out.println("=======\t\t 1 显示在线用户列表================");
                            System.out.println("=======\t\t 2 群发消息\t\t================");
                            System.out.println("=======\t\t 3 私聊消息\t\t================");
                            System.out.println("=======\t\t 4 发送文件\t\t================");
                            System.out.println("=======\t\t 9 退出系统\t\t================");
                            log.debug("请输入你的选择:");
                            key = Utility.readString(1);
                            switch (key) {
                                case "1":
                                    System.out.println("显示在线用户列表");
                                    break;
                                case "2":
                                    System.out.println("群发消息");
                                    break;
                                case "3":
                                    System.out.println("私聊消息");
                                    break;
                                case "4":
                                    System.out.println("发送文件");
                                    break;
                                case "9":
                                    loop = false;
                                    break;
                                default:
                                    log.debug("输入有误,请重新输入!");
                                    break;
                            }
                        }

                    } else {
                        log.debug("=========用户名密码错误=============");
                        log.debug("==========登陆失败=============");
                    }
                    break;
                case "9":
                    loop = false;
                    break;
                default:
                    log.debug("输入有误,请重新输入!");
                    break;
            }
        }

    }
}

2)工具类cn.com.agree.util.Utility

package cn.com.agree.util;

import lombok.extern.slf4j.Slf4j;

import java.util.Scanner;

/**
 * @author andongdong
 * @version 1.0
 * @ClassName Utility
 * @Description 工具类
 * @date 2024/1/5  10:56 上午
 **/
@Slf4j
public class Utility {
    public static Scanner scanner;

    static {
        scanner = new Scanner(System.in);
    }

    public Utility() {
    }

    public static char readMenuSelection() {
        while (true) {
            String str = readKeyBoard(1, false);
            char c = str.charAt(0);
            if (c == '1' || c == '2' || c == '3' || c == '4' || c == '5') {
                return c;
            }
            log.debug("选择错误,请重新输入:");
        }
    }

    public static char readChar() {
        String str = readKeyBoard(1, false);
        return str.charAt(0);
    }

    public static char readChar(char defaultValue) {
        String str = readKeyBoard(1, true);
        return str.length() == 0 ? defaultValue : str.charAt(0);
    }

    public static int readInt() {
        while (true) {
            String str = readKeyBoard(2, false);
            try {
                int n = Integer.parseInt(str);
                return n;
            } catch (NumberFormatException var3) {
                log.debug("数字输入错误,请重新输入:");
            }
        }
    }

    public static int readInt(int defaultValue) {
        while (true) {
            String str = readKeyBoard(2, true);
            if (str.equals("")) {
                return defaultValue;
            }
            try {
                int n = Integer.parseInt(str);
                return n;
            } catch (NumberFormatException var3) {
                log.debug("数字输入错误,请重新输入:");
            }
        }
    }

    public static String readString(int limit) {
        return readKeyBoard(limit, false);
    }

    public static String readString(int limit, String defaultValue) {
        String str = readKeyBoard(limit, true);
        return str.equals("") ? defaultValue : str;
    }

    public static char readConfirmSelection() {
        while (true) {
            String str = readKeyBoard(1, false).toUpperCase();
            char c = str.charAt(0);
            if (c == 'Y' || c == 'N') {
                return c;
            }
            log.debug("选择错误,请重新输入: ");
        }
    }

    private static String readKeyBoard(int limit, boolean blankReturn) {
        String line = "";
        while (scanner.hasNextLine()) {
            line = scanner.nextLine();
            if (line.length() == 0) {
                if (blankReturn) {
                    return line;
                }
            } else {
                if (line.length() >= 1 && line.length() <= limit) {
                    break;
                }
                log.debug("输入长度(不大于" + limit + ")" + "错误,请重新输入:");
            }
        }
        return line;
    }
}

3)cn.com.agree.qqclient.service.UserClientService

package cn.com.agree.util;

import lombok.extern.slf4j.Slf4j;

import java.util.Scanner;
/**
 * @author 
 * @version 1.0
 * @ClassName UserClientService
 * @Description TODO 类描述
 * @date 2024/1/5  4:18 下午
 **/
@Slf4j
public class Utility {
    public static Scanner scanner;

    static {
        scanner = new Scanner(System.in);
    }

    public Utility() {
    }

    public static char readMenuSelection() {
        while (true) {
            String str = readKeyBoard(1, false);
            char c = str.charAt(0);
            if (c == '1' || c == '2' || c == '3' || c == '4' || c == '5') {
                return c;
            }
            log.debug("选择错误,请重新输入:");
        }
    }

    public static char readChar() {
        String str = readKeyBoard(1, false);
        return str.charAt(0);
    }

    public static char readChar(char defaultValue) {
        String str = readKeyBoard(1, true);
        return str.length() == 0 ? defaultValue : str.charAt(0);
    }

    public static int readInt() {
        while (true) {
            String str = readKeyBoard(2, false);
            try {
                int n = Integer.parseInt(str);
                return n;
            } catch (NumberFormatException var3) {
                log.debug("数字输入错误,请重新输入:");
            }
        }
    }

    public static int readInt(int defaultValue) {
        while (true) {
            String str = readKeyBoard(2, true);
            if (str.equals("")) {
                return defaultValue;
            }
            try {
                int n = Integer.parseInt(str);
                return n;
            } catch (NumberFormatException var3) {
                log.debug("数字输入错误,请重新输入:");
            }
        }
    }

    public static String readString(int limit) {
        return readKeyBoard(limit, false);
    }

    public static String readString(int limit, String defaultValue) {
        String str = readKeyBoard(limit, true);
        return str.equals("") ? defaultValue : str;
    }

    public static char readConfirmSelection() {
        while (true) {
            String str = readKeyBoard(1, false).toUpperCase();
            char c = str.charAt(0);
            if (c == 'Y' || c == 'N') {
                return c;
            }
            log.debug("选择错误,请重新输入: ");
        }
    }

    private static String readKeyBoard(int limit, boolean blankReturn) {
        String line = "";
        while (scanner.hasNextLine()) {
            line = scanner.nextLine();
            if (line.length() == 0) {
                if (blankReturn) {
                    return line;
                }
            } else {
                if (line.length() >= 1 && line.length() <= limit) {
                    break;
                }
                log.debug("输入长度(不大于" + limit + ")" + "错误,请重新输入:");
            }
        }
        return line;
    }
}

4)cn.com.agree.qqclient.service.ClientConnectServer

package cn.com.agree.qqclient.service;

import cn.com.agree.qqcommon.Message;
import lombok.extern.slf4j.Slf4j;

import java.io.ObjectInputStream;
import java.net.Socket;
/**
 * @author 
 * @version 1.0
 * @ClassName ClientConnectServer
 * @Description 为了便于管理,将客户端的thread根据UserID存入到一个集合中
 * @date 2024/1/5  3:54 下午
 **/
@Slf4j
public class ClientConnectServer implements Runnable {

    //该线程需要持有socket
    private Socket socket;

    public Socket getSocket() {
        return socket;
    }

    public void setSocket(Socket socket) {
        this.socket = socket;
    }

    public ClientConnectServer(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        //因为Thread需要在后台和服务器进行通信,因此我们用while循环
        while (true) {
            try {
                log.debug("客户端线程和服务端正在通信,读取从服务端发来的消息...");
                // 设置Socket的超时时间为5000毫秒(5秒)
//                socket.setSoTimeout(5000);
                ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
                Message message = (Message) ois.readObject();//如果服务器端没有消息发过来这个线程一直会阻塞在这里
                //todo 后续对读取到的message进行处理
                log.debug("message:{}",message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

5)cn.com.agree.qqclient.service.ManageClientConnectServers

package cn.com.agree.qqclient.service;

import cn.com.agree.qqcommon.Message;
import lombok.extern.slf4j.Slf4j;

import java.io.ObjectInputStream;
import java.net.Socket;

/**
 * @author 
 * @version 1.0
 * @ClassName ClientConnectServer
 * @Description 为了便于管理,将客户端的thread根据UserID存入到一个集合中
 * @date 2024/1/5  3:54 下午
 **/
@Slf4j
public class ClientConnectServer implements Runnable {

    //该线程需要持有socket
    private Socket socket;

    public Socket getSocket() {
        return socket;
    }

    public void setSocket(Socket socket) {
        this.socket = socket;
    }

    public ClientConnectServer(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        //因为Thread需要在后台和服务器进行通信,因此我们用while循环
        while (true) {
            try {
                log.debug("客户端线程和服务端正在通信,读取从服务端发来的消息...");
                // 设置Socket的超时时间为5000毫秒(5秒)
//                socket.setSoTimeout(5000);
                ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
                Message message = (Message) ois.readObject();//如果服务器端没有消息发过来这个线程一直会阻塞在这里
                //todo 后续对读取到的message进行处理
                log.debug("message:{}",message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

2.3、QQServer端:
1)cn.com.agree.qqserver.service.qqServer

package cn.com.agree.qqserver.service;

import cn.com.agree.qqcommon.Message;
import cn.com.agree.qqcommon.MessageType;
import cn.com.agree.qqcommon.User;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author 
 * @version 1.0
 * @ClassName qqServer
 * @Description 服务器端编码
 * @date 2024/1/5  5:24 下午
 **/
@Slf4j
public class qqServer {

    /*
    * 用hashmap模拟数据库
     */
    private static ConcurrentHashMap<String,User> validUsers = new ConcurrentHashMap<>();

    static {
        validUsers.put("100",new User("100","123456"));
        validUsers.put("200",new User("200","123456"));
        validUsers.put("300",new User("300","123456"));
        validUsers.put("张三",new User("张三","123456"));
        validUsers.put("李四",new User("李四","123456"));
        validUsers.put("王五",new User("王五","123456"));
    }
    private ServerSocket serverSocket = null;

    public qqServer() {
        Socket socket = null;
        try {
            log.debug("服务端在9999端口监听,等待客户端连接...");
            serverSocket = new ServerSocket(9999);
            //因为服务端会监听来自不同线程到socket,所以它要保持一直在监听到状态不能只监听到一个就退出因此用循环
            while (true) {
                socket = serverSocket.accept();
                //获取来自客户端发送过来到用户对象
                log.debug("socket Client连接成功");
                ObjectInputStream bis = new ObjectInputStream(socket.getInputStream());
                User user = (User) bis.readObject();
                //获取输出流对象写入返回给客户端的消息
                ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
                log.debug("user:{}",user);
                Message message = new Message();
                //TODO 校验用户信息(数据库层面校验这里先写死判断后面改进)
                if (checkUser(user.getUserId(), user.getPasswd())) {//校验成功
                    message.setMsgType(MessageType.MESSAGE_LOG_SUCCESS);
                    oos.writeObject(message);
                    //创建一个server连接client的线程去完成通信->ServerConnectClient
                    ServerConnectClient serverConnectClient = new ServerConnectClient(socket, user.getUserId());
                    new Thread(serverConnectClient).start();
                    //使用集合类管理服务端线程
                    ManageServerConnectClient.addServerConnectClient(user.getUserId(), serverConnectClient);
                } else {
                    //校验失败
                    log.debug("userId为"+user.getUserId()+"登陆失败");
                    message.setMsgType(MessageType.MESSAGE_LOG_FAIL);
                    oos.writeObject(message);
                    socket.close();
                }
            }
        } catch (Exception e) {
            e.getStackTrace();
        } finally {
            try {
                serverSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    private boolean checkUser(String userId,String passwd){
        User user = validUsers.get(userId);
        if(user == null){//用户不存在
            return false;
        }
        if(!passwd.equals(user.getPasswd())){//密码错误
            return false;
        }
        return true;
    }
}

2)cn.com.agree.qqserver.service.ServerConnectClient

package cn.com.agree.qqserver.service;

import cn.com.agree.qqcommon.Message;
import cn.com.agree.qqcommon.User;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;

/**
 * @author 
 * @version 1.0
 * @ClassName ServerConnectClient
 * @Description TODO 类描述
 * @date 2024/1/5  5:44 下午
 **/
@Slf4j
public class ServerConnectClient implements  Runnable {
    private Socket socket;
    private String userId;

    public ServerConnectClient(Socket socket, String userId) {
        this.socket = socket;
        this.userId = userId;
    }

    public void run() {
        while (true){
            try {
                log.debug("服务端和客户端"+userId+"正在通信通信,读取数据...");
                // 设置Socket的超时时间为5000毫秒(5秒)
//                socket.setSoTimeout(5000);
                ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
                Message message = (Message) ois.readObject();
                //TODO 后续处理从客户端获取的消息
                log.debug("message:{}",message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

3)cn.com.agree.qqclient.service.ClientConnectServer

package cn.com.agree.qqserver.service;

import java.util.HashMap;
import java.util.Map;

/**
 * @author 
 * @version 1.0
 * @ClassName ManageServerConnectClient
 * @Description TODO 类描述
 * @date 2024/1/5  5:50 下午
 **/
public class ManageServerConnectClient {
    private static Map<String,ServerConnectClient> hm = new HashMap();

    public static void addServerConnectClient(String userId,ServerConnectClient serverConnectClient){
        hm.put(userId,serverConnectClient);
    }

    public static ServerConnectClient getServerConnectClient(String userId) {
        return hm.get(userId);
    }
}

4)启动类

package cn.com.agree.qqserver.service;  /**
 * @author 
 * @version 1.0
 * @ClassName qqFrame
 * @Description TODO 类描述
 * @date 2024/1/5  6:06 下午
 **/
public class qqFrame {
    public static void main(String[] args) {
        new qqServer();
    }
}

3、运行效果
1)校验错误的用户名密码
在这里插入图片描述
2)校验正确的用户名密码(起两个客户端一个服务端)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

python 基础笔记

基本数据类型 函数 lamda 匿名函数 成员方法 类 类与对象 构造方法 魔术方法 私有成员 私有方法 继承 注解 变量注解 函数注解 Union类型 多态 参考链接&#xff1a;黑马程序员python教程&#xff0c;8天python从入门到精通&#xff0c;学python看这套就够了_哔哩哔哩_bilib…

PTA✨C语言 求1到N的和

7-6 求1到N的和 分数 15 全屏浏览题目 切换布局 作者 颜晖 单位 浙大城市学院 本题要求编写程序&#xff0c;计算序列 1 2 3 ... 的前N项之和。 输入格式: 输入在一行中给出一个正整数N。 输出格式: 在一行中按照“sum S”的格式输出部分和的值S&#xff0c;请注意…

HttpClient调用外部接口业务别忘了超时配置!公司工具类打包好啦

前言 在工作中&#xff0c;往往会遇到需要对接外部接口的业务需求&#xff0c;根据接口文档确定请求IP以及相关的参数数据需求后&#xff0c;通过HttpClient进行第三方外部接口的调用。在这种业务中&#xff0c;也要考虑好请求超时导致的接口报错的处理。为什么呢&#xff1f;就…

Python教程37:使用turtle画一个戴帽子的皮卡丘

---------------turtle源码集合--------------- Python教程36&#xff1a;海龟画图turtle写春联 Python源码35&#xff1a;海龟画图turtle画中国结 Python源码31&#xff1a;海龟画图turtle画七道彩虹 Python源码30&#xff1a;海龟画图turtle画紫色的小熊 Python源码29&a…

在Ubuntu中检查内存的五个命令,总有一种适合你

序言 作为Ubuntu用户,尤其是管理员,我们需要检查系统使用了多少内存资源,以及有多少是可用的。我们还知道,大多数管理任务最好从Linux命令行完成,而不是从图形用户界面完成。例如,服务器通常在shell上工作,没有图形用户界面。由于控制服务器上的内存资源是最重要的,因…

平衡搜索二叉树(AVL树)

前言 二叉搜索树虽可以缩短查找的效率&#xff0c;但如果数据有序或接近有序二叉搜索树将退化为单支树&#xff0c;查 找元素相当于在顺序表中搜索元素&#xff0c;效率低下。因此&#xff0c;两位俄罗斯的数学家G.M.Adelson-Velskii 和E.M.Landis在1962年 发明了一种解决上述…

体元法--体积计算

文章目录 环境&#xff1a;1.1 体元法介绍&#xff1a;2.1 python代码3.1 可视化 环境&#xff1a; Open3D 1.1 体元法介绍&#xff1a; 用一个个体素去占据点云&#xff0c;然后对所有体素求和 2.1 python代码 conda activete deeplabv3plus(环境名称–安装好open3D的) py…

【Python机器学习】决策树集成——随机森林

理论知识&#xff1a; 集成是合并多个机器学习模型来构建更强大模型法方法。 随机森林本质上是许多决策树的集合&#xff0c;其中每棵树都和其他数略有不同&#xff0c;随机森林背后的思想是&#xff1a;每棵树的预测可能都比较好&#xff0c;但是可能对部分数据过拟合&#…

若依项目的table列表中对每一个字段增加排序按钮(单体版和前后端分离版)

一、目标:每一个字段都添加上下箭头用来排序 只需要更改前端代码,不需要更改后端代码,后面会讲解原理 二、单体版实现方式: 1.在options中添加sortable:true 2.在需要排序的字段中添加sortable:true 三、前后端分离版 1.el-table上添加@sort-change=“handleSortChange”…

MySQL的导入导出及备份

一.准备导入之前 二.navicat导入导出 ​编辑 三.MySQLdump命令导入导出 四.load data file命令的导入导出 五.远程备份 六. 思维导图 一.准备导入之前 需要注意&#xff1a; 在导出和导入之前&#xff0c;确保你有足够的权限。在进行导入操作之前&#xff0c;确保目标数据…

Tensorflow2.0笔记 - 创建tensor

tensor创建可以基于numpy&#xff0c;list或者tensorflow本身的API。 笔记直接上代码&#xff1a; import tensorflow as tf import numpy as np import matplotlib.pyplot as plttf.__version__#通过numpy创建tensor tensor0 tf.convert_to_tensor(np.ones([2,3])) print(te…

GitHub 一周热点汇总 第4期 (2024/01/01-01/06)

GitHub一周热点汇总第四期 (2023/12/24-12/30)&#xff0c;梳理每周热门的GitHub项目&#xff0c;了解热点技术趋势&#xff0c;掌握前沿科技方向&#xff0c;发掘更多商机。2024年到了&#xff0c;希望所有的朋友们都能万事顺遂。 说明一下&#xff0c;有时候本周的热点项目会…

null和undefined的区别

null 和 undefined 是 JavaScript 中的两个基础类型特殊值。它们都表示“空”&#xff0c;但是有一些区别。 一、null 在 JavaScript 内部&#xff0c;null 被视为一个表示空值或缺少值的对象指针。在计算机内存中&#xff0c;它通常被表示为一个指向内存空间的空指针。这意味…

源码开发实践:搭建企业培训APP的技术难题及解决方案

在企业培训源码开发实践中&#xff0c;各位开发者可能遇到各种各样的问题&#xff0c;本文将深入探讨这些挑战&#xff0c;并提供解决方案&#xff0c;助力你顺利搭建企业培训APP。 1.多平台兼容性 企业中员工使用的设备多种多样&#xff0c;包括iOS、Android等不同操作系统。…

电力监控系统在数据中心应用

摘 要&#xff1a;在电力系统的运行过程中&#xff0c;变电站作为整个电力系统的核心&#xff0c;在保证电力系统可靠的运行方面起着至关重要的作用&#xff0c;基于此需对变电站监控系统的特点进行分析&#xff0c;结合变电站监控系统的功能需求&#xff0c;对变电站电力监控系…

BitMap解析(一)

文章目录 前言数据结构添加与删除操作 JDK中BitSet源码解析重要成员属性初始化添加数据清除数据获取数据size和length方法集合操作&#xff1a;与、或、异或 前言 为什么称为bitmap&#xff1f; bitmap不仅仅存储介质以及数据结构不同于hashmap&#xff0c;存储的key和value也…

Spring MVC概述及入门

MVC介绍 MVC是一种设计模式&#xff0c;将软件按照模型、视图、控制器来划分&#xff1a; M&#xff1a;&#xff08;Model&#xff09;模型层&#xff0c;指工程中的JavaBean&#xff0c;作用是处理数据 数据模型&#xff1a;User、Student&#xff0c;装数据 业务模型&#…

C++ Primer 第五版 中文版 阅读笔记 + 个人思考

C Primer 第五版 中文版 阅读笔记 个人思考 第 10 章 泛型算法10.1 概述练习10.1练习10.2 第 10 章 泛型算法 泛型的体现&#xff1a;容器类型&#xff08;包括内置数组&#xff09;&#xff0c;元素类型&#xff0c;元素操作方法。 顺序容器定义的操作&#xff1a;insert&a…

Android-多线程

线程是进程中可独立执行的最小单位&#xff0c;也是 CPU 资源&#xff08;时间片&#xff09;分配的基本单位&#xff0c;同一个进程中的线程可以共享进程中的资源&#xff0c;如内存空间和文件句柄。线程有一些基本的属性&#xff0c;如id、name、以及priority。 id&#xff1…

API调试怎么做?Apipost快速上手

前言 Apipost是一款支持 RESTful API、SOAP API、GraphQL API等多种API类型&#xff0c;支持 HTTPS、WebSocket、gRPC多种通信协议的API调试工具。除此之外&#xff0c;Apipost 还提供了自动化测试、团队协作、等多种功能。这些丰富的功能简化了工作流程&#xff0c;提高了研发…