4.BIO多线程即时通信

news2024/11/23 16:06:44

highlight: arduino-light

基于BIO模式下的即时通信,我们需要解决客户端到客户端的通信,也就是需要实现客户端与客户端的端口消息转发逻辑。

功能清单

1.客户端登陆功能

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

2.在线人数实时更新。

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

3.离线人数更新

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

4.群聊

  • 任意一个客户端的消息,服务器端收到以后再推送给其他所有客户端接收,即A发了一个消息,将消息转发给所有的在线人员 B C D 即在线的Socket集合。

image.png

5.私聊

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

6.@消息

  • 可以选择某个员工,然后发出的消息可以@该用户,服务器端收到以后再推送其他所有人接收

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

  • 服务端可以实时记录该用户的消息时间点,然后进行消息的多路转发或者选择。
  • 1代表接收的是登陆消息
  • 2代表群发@消息
  • 3代表了私聊消息

代码实现

```java

import com.itheima.util.Constants;
​
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
​
/**
 *
 */
public class ServerChat {
    /**
     * 定义一个集合存放所有在线的socket
     * 在线集合只需要一个:存储客户端socket的同时还需要知道这个Socket客户端的名称
     */
    public static Map<Socket, String> onLineSockets = new HashMap<>();
​
    public static void main(String[] args) {
        try {
            /** 注册端口 */
            ServerSocket serverSocket = new ServerSocket(Constants.PORT);
            /** 循环一直等待所有可能的客户端连接 */
            while(true){
                Socket socket = serverSocket.accept();
                /** 
                服务端需要接收多个客户端,目前我们采取的策略是一个客户端对应一个服务端线程。
                */
                new ServerReader(socket).start();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

java

package com.itheima.server;
import com.itheima.util.Constants;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Set;
​
public class ServerReader extends Thread {
    /****
    将客户端的socket作为参数传入
    ***/
    private Socket socket;
    public ServerReader(Socket socket) {
        this.socket = socket;
    }
​
    @Override
    public void run() {
        DataInputStream dis = null;
        try {
            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);
                }
                //写入的是 flag,dis
                writeMsg(flag,dis);
            }
        } catch (Exception e) {
            System.out.println("--有人下线了--");
            // 从在线人数中将当前socket移出去  
            ServerChat.onLineSockets.remove(socket);
            try {
                // 重新更新在线人数并发给所有客户端 
                writeMsg(1,dis);
            } catch (Exception e1) {
                e1.printStackTrace();
            }
        }
​
    }
​
    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();
            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();
        }
    }
}

java

package com.itheima.client;
​
import com.itheima.util.Constants;
​
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.DataOutputStream;
import java.net.Socket;
​
/**
 * 客户端界面
 */
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 "发送":
                // 得到发送消息的内容
                String msgSend = smsSend.getText().toString();
                if(!msgSend.trim().equals("")){
                    /** 发消息给服务端 */
                    try {
                        // 判断是否对谁发消息
                        String selectName = onLineUsers.getSelectedValue();
                        int flag = 2 ;// 群发 @消息
                        if(selectName!=null&&!selectName.equals("")){
                            msgSend =("@"+selectName+","+msgSend);
                            /** 判断是否选中了私法 */
                            if(isPrivateBn.isSelected()){
                                /** 私法 */
                                flag = 3 ;//私发消息
                            }
​
                        }
​
                        DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
                        dos.writeInt(flag); // 群发消息  发送给所有人
                        dos.writeUTF(msgSend);
                        if(flag == 3){
                            // 告诉服务端我对谁私发
                            dos.writeUTF(selectName.trim());
                        }
                        dos.flush();
​
                    } catch (Exception e1) {
                        e1.printStackTrace();
                    }
​
                }
                smsSend.setText(null);
                break;
        }
    }
}

java

package com.itheima.client;
import com.itheima.util.Constants;
import java.io.DataInputStream;
import java.net.Socket;
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){
                    //群发,私聊 , @消息 都是直接显示的。
                    String msg = dis.readUTF() ;
                    clientChat.smsContent.append(msg);
                    // 让消息界面滾動到底端
                    clientChat.smsContent.setCaretPosition(clientChat.smsContent.getText().length());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

```

项目启动

  • 1.首先需要启动服务端,点击ServerChat类直接右键启动,显示服务端启动成功!

  • 2.其次,点击客户端类ClientChat类,在弹出的方框中输入服务端的ip和当前客户端的昵称

image.png

  • 3.登陆进入后的聊天界面如下,即可进行相关操作。

    • 如果直接点击发送,默认发送群聊消息
  • 如果选中右侧在线列表某个用户,默认发送@消息

    • 如果选中右侧在线列表某个用户,然后选择右下侧私聊按钮默,默认发送私聊消息。

image.png

image.png

贴下视频链接:https://www.bilibili.com/video/BV1gz4y1C7RK/?spm_id_from=333.337.search-card.all.click&vd_source=2fe0aba0a7e0c99e9d0d910556f2b12f

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

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

相关文章

JVM理论(五)执行引擎--解释器/JIT编译器

概述 首先执行引擎是java虚拟机核心的组成部分之一;而JVM的主要任务是装载字节码到内存,但不能够直接运行在操作系统之上.因为字节码指令并非等价于本地机器指令,它仅仅包含能够被JVM所识别的指令、符号表、以及其他信息;而此时执行引擎就华丽登场,它的任务就是将字节码指令解…

欧姆龙PLC联网

一、设备信息确认 左上角的为PLC型号,如图该PLC型号为CP1H,不同型号的欧姆龙PLC通讯方面有什么差别呢? 通讯能力和方式不同: 有些型号PLC自带网口,有些则需要扩展(上图中右侧的两个红框内为后扩展的通讯口,扩展模块可以随意组合双网口,双232串口,双485串口都可以)…

D354周赛复盘:特殊元素平方和+数组最大美丽值(滑动窗口)+合法分割最小下标

文章目录 6889.特殊元素平方和思路完整版取模注意&#xff1a;不能对0取余/取模解答错误&#xff1a;本题的数组最后一个下标是nums[nums.size()] 6929.数组的最大美丽值&#xff08;排序滑动窗口&#xff09;思路1&#xff1a;排序滑动窗口注意点 6927. 合法分割的最小下标&am…

My_window类(带有next和quit按钮)

运行代码&#xff1a; //My_window类&#xff08;带有next和quit按钮&#xff09; #include"std_lib_facilities.h" #include"GUI/Simple_window.h" #include"GUI/GUI.h" #include"GUI/Graph.h" #include"GUI/Point.h"//--…

为什么项目可见性难以实现?该如何提高?

在项目和专业服务管理中&#xff0c;失败有时难以避免。沟通不足和需求定义不明确被认为是造成失败的最大原因&#xff0c;这意味着项目可见性和信息流动至关重要。 什么是项目可见性&#xff1f; 项目可见性是组织项目相关信息的方式&#xff0c;以便所有团队成员、项目经理…

火狐安卓版支持油猴了!后面将支持更多扩展插件

日前火狐浏览器每夜构建版的安卓版已经带来了更多扩展程序支持&#xff0c;这其中就包括大名鼎鼎的油猴扩展程序。本次火狐浏览器每夜构建版更新新增五款扩展程序支持&#xff0c;并且按照谋智基金会说法还会支持更多的扩展程序。 下载地址&#xff1a;https://ftp.mozilla.org…

力扣 406. 根据身高重建队列

题目来源&#xff1a;https://leetcode.cn/problems/queue-reconstruction-by-height/description/ C题解1&#xff1a;分别对h和k两个维度进行考虑&#xff0c;我这里是优先考虑k值&#xff0c;k值相同的时候h小的排前面。然后再一一遍历&#xff0c;对于people[i]&#xff0c…

曲师大2023大一新生排位赛-D.Factor题解

D.Factor 题目描述 你有一个集合 &#xff0c;和具有 个正整数的数组 . 最初&#xff0c;集合 为空&#xff08;不包含任一元素&#xff09;。你将按照以下方式填充集合 : 以此枚举数组 a 中的每个元素。对于数组中的第 i 个元素 &#xff0c;生成 ​ 的因子集合 ​。如果…

uniapp引入echarts

作为前端在开发需求的时候经常会遇到将数据展示为图表的需求&#xff0c;之前一直用的HBuilder的图表插件uCharts&#xff0c;使用方法可以参考我的另一篇博客&#xff1a;uniapp 中使用图表&#xff08;秋云uCharts图表组件&#xff09; 但是最近发现uCharts很多功能都需要付…

国密算法概述、及算法的集成应用(sm2、sm3、sm4)

国密算法概述、及算法的集成应用&#xff08;sm2、sm3、sm4&#xff09; 一、概述二、分类概述3.1、SM1对称密码3.2、SM2椭圆曲线公钥密码算法3.3、SM3杂凑算法3.4、SM4对称算法3.5、SM7对称密码3.6、SM9标识密码算法3.7、ZUC祖冲之算法 三、集成SM2加解密四、集成SM3加密、验签…

系统学习Linux-Rsync远程数据同步服务(三)

一、概述 rsync是linux 下一个远程数据同步工具 他可通过LAN/WAN快速同步多台主机间的文件和目录&#xff0c;并适当利用rsync 算法减少数据的传输 会对比两个文件的不同部分&#xff0c;传输差异部分&#xff0c;因此传输速度相当快 rsync可拷贝、显示目录属性&#xff0c…

将TXT转化为PDF的方法有哪些,分享四个给大家!

将TXT文本文件转换为PDF是一项常见的需求&#xff0c;特别是在需要共享文档时。在本文中&#xff0c;我们将分享四种方法&#xff0c;让您能够轻松地将TXT文件转换为PDF格式。 方法一&#xff1a;使用记灵在线工具 记灵在线工具是一个方便易用的在线文档转换工具&#xff0c;…

日撸java三百行day77-79

文章目录 说明GUI1. GUI 总体布局2. GUI 代码理解2.1 对话框相关控件2.1.1 ApplicationShowdown.java&#xff08;关闭应用程序&#xff09;2.1.2 DialogCloser.java&#xff08;关闭对话框&#xff09;2.1.3 ErrorDialog.java&#xff08;显示错误信息&#xff09;2.1.4 HelpD…

C++基础算法离散化及区间合并篇

&#x1f4df;作者主页&#xff1a;慢热的陕西人 &#x1f334;专栏链接&#xff1a;C算法 &#x1f4e3;欢迎各位大佬&#x1f44d;点赞&#x1f525;关注&#x1f693;收藏&#xff0c;&#x1f349;留言 主要讲解了双指针&#xff0c;位运算&#xff0c;离散化以及区间合并。…

店铺记账用什么软件好?应该如何选购?

店铺记账过程中&#xff0c;会遇到各种问题&#xff1a;手写记账容易出错、效率低下、数据容易丢失&#xff1b;手动整理数据导致实际库存和账面库存不匹配&#xff0c;影响补货和订单管理。 而借助专业的店铺记账软件&#xff0c;可以有效解决上面这些问题&#xff0c;通过自动…

51单片机学习--矩阵键盘、电子密码锁

矩阵键盘的模块原理图&#xff1a; 功能&#xff1a;按下矩阵按键&#xff0c;在LCD上显示对应的数值。 采用模块化编程&#xff0c;在此只给出MatrixKey.c 和 main.c 两部分代码 #include <REGX52.H> #include "Delay.h"/*矩阵键盘读取键码按下不放&#xf…

K8S集群内部署Rancher2.5.16

K8S集群内部署Rancher2.5.16 一、环境 k8s&#xff1a;1.18.20 OS&#xff1a;Anolis OS 7.9 rancher&#xff1a;2.5.16 参考官网部署文档&#xff1a;https://ranchermanager.docs.rancher.com/zh/v2.6/pages-for-subheaders/install-upgrade-on-a-kubernetes-cluster 二…

回归预测 | MATLAB实现基于SVM-Adaboost支持向量机结合AdaBoost多输入单输出回归预测

回归预测 | MATLAB实现基于SVM-Adaboost支持向量机结合AdaBoost多输入单输出回归预测 目录 回归预测 | MATLAB实现基于SVM-Adaboost支持向量机结合AdaBoost多输入单输出回归预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 1.MATLAB实现基于SVM-Adaboost支持向…

Meta发布升级大模型LLaMA 2:开源可商用

论文地址&#xff1a;https://ai.meta.com/research/publications/llama-2-open-foundation-and-fine-tuned-chat-models/ Github地址&#xff1a;https://github.com/facebookresearch/llama LLaMA 2介绍 Meta之前发布自了半开源的大模型LLaMA&#xff0c;自从LLaMA发布以来…

常用API学习06(Java)

Biglnteger public BigInteger(int num, Random rnd) 获取随机大整数&#xff0c;范围&#xff1a;[0~2的num次方-1] public BigInteger(String val) 获取指定的大整数 public BigInteger(String val, int radix) 获取指定进制的大整数 public static BigInteg…