4.23学习总结

一.NIO(一)

(一).简介:

NIO 是 Java SE 1.4 引入的一组新的 I/O 相关的 API,它提供了非阻塞式 I/O、选择器、通道、缓冲区等新的概念和机制。相比与传统的 I/O 多出的 N 不是单纯的 New,更多的是代表了 Non-blocking 非阻塞,NIO具有更高的并发性、可扩展性以及更少的资源消耗等优点。

(二).NIO 与传统BIO:

NIO:是同步非阻塞的,服务器实现模式为 一个线程处理多个连接。服务端只会创建一个线程负责管理Selector(多路复用器),Selector(多路复用器)不断的轮询注册其上的Channel(通道)中的 I/O 事件,并将监听到的事件进行相应的处理。每个客户端与服务端建立连接时会创建一个 SocketChannel 通道,通过 SocketChannel 进行数据交互。

BIO:全称是Blocking IO,同步阻塞式IO,是JDK1.4之前的传统IO模型,服务器实现模式为一个连接一个线程。每当客户端有连接请求时服务器端就需要启动一个线程进行处理。

两者主要区别如下:

  • 阻塞和非阻塞:NIO 使用非阻塞式 I/O,而 BIO 使用阻塞式 I/O。在阻塞式 I/O 中,当一个 I/O 操作完成之前,线程会一直被阻塞,直到 I/O 操作完成;在非阻塞式 I/O 中,线程可以继续执行其他任务,直到 I/O 操作完成并返回结果。
  • 线程模型:NIO 中的线程模型是基于事件驱动的,当一个 I/O 操作完成时,会触发相应的事件通知线程处理;而在 BIO 中,每个线程都负责处理一个客户端连接,需要不断地轮询客户端的输入输出流,以便及时响应客户端的请求。
  • 内存消耗:NIO 中使用的缓冲区(Buffer)可以重复利用,减少了频繁的内存分配和回收,从而减少了内存的消耗;而在 BIO 中,每个客户端连接都需要单独分配一个缓冲区,容易造成内存的浪费。
  • 并发性能:NIO 中使用非阻塞式 I/O,可以同时处理多个客户端连接,从而提高了并发处理能力;而在 BIO 中,由于每个客户端连接都需要一个线程来处理,当连接数量增加时,容易出现线程饥饿和资源耗尽的问题。

 

(三).NIO的核心原理

 

 工作流程:

  • 创建 Selector:Selector 是 NIO 的核心组件之一,它可以同时监听多个通道上的 I/O 事件,并且可以通过 select() 方法等待事件的发生。
  • 注册 Channel:通过 Channel 的 register() 方法将 Channel 注册到 Selector 上,这样 Selector 就可以监听 Channel 上的 I/O 事件。
  • 等待事件:调用 Selector 的 select() 方法等待事件的发生,当有事件发生时,Selector 就会通知相应的线程进行处理。
  • 处理事件:根据不同的事件类型,调用对应的处理逻辑。
  • 关闭 Channel:当 Channel 不再需要使用时,需要调用 Channel 的 close() 方法关闭 Channel,同时也需要调用 Buffer 的 clear() 方法清空 Buffer 中的数据,以释放内存资源。

 

 二.java聊天室控制台实现公聊私聊

其私聊核心思路就是hashmap将每个人的id(用户名)和其对应的输出流,形成键值对,存到hashmap中,在需要的时候,直接根据用户名就可以调出其对应的输出流.

公聊的核心思路在于使用ArrayList集合,将所有用户的输出流都存入集合中,然后遍历对每个用户进行输出.

实例代码:

客户端:

public class Client {
    public static void main(String[] args) {
        //连接服务器
        try {
            System.out.println("连接服务端");
            Socket socket = new Socket("localhost",8088);
            System.out.println("连接服务端成功");
            Thread t1 = new Thread(new ClientWriteData(socket));
            Thread t2 = new Thread(new ClientReadData(socket));
            t1.start();
            t2.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
class ClientWriteData implements Runnable{
    private Scanner scan;
    private Socket socket;
    public ClientWriteData(Socket socket){
        this.socket = socket;
    }
    public void run(){
        try {
            OutputStream out = socket.getOutputStream();
            OutputStreamWriter osw;osw = new OutputStreamWriter(out,"GBK");
            PrintWriter pw = new PrintWriter(osw,true);
            System.out.println("请输入用户名:");
            scan = new Scanner(System.in);
            String str0 = scan.next();
            pw.println(str0);
            while(true){
                System.out.println("请选择私聊或者群发:1表示私聊\t2表示群发");
                int n = scan.nextInt();
                pw.println(n);
                switch(n){
                    case 1:
                        System.out.println("请输入私聊对象: ");
                        String name = scan.next();
                        pw.println(name);
                        System.out.println("私聊的信息:");
                        String str = scan.next();
                        pw.println(str);
                        break;
                    case 2:
                        System.out.println("请输入群发消息:");
                        System.out.println(str0+"正在发消息:");
                        String str1 = scan.next();
                        pw.println(str1);
                        break;
                    default:
                        System.out.println("退出消息发送:");
                        System.exit(0);
                }

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
class ClientReadData implements Runnable{
    private Socket socket;
    public ClientReadData(Socket socket){
        this.socket = socket;
    }
    public void run(){
        try {
            InputStream is = socket.getInputStream();
            InputStreamReader isr = new InputStreamReader(is,"GBK");
            BufferedReader br = new BufferedReader(isr);
            String str = null;
            while((str = br.readLine())!=null){
                System.out.println(str);
            }
        } catch (IOException e) {
            System.err.println("服务端已断开!!!");
            e.printStackTrace();
        }
    }
}

服务端:

public class Server {
    //群发
    //定义一个集合,用于存储所有客户端的输出流
    List<PrintWriter> allPw = new ArrayList<>();
    //用于根据用户名存储客户端输出流
    Map<String,PrintWriter> map = new HashMap();
    //创建线程池对象
    //ExecutorService pool = Executors.newCachedThreadPool();
    public static void main(String[] args) {
        try {
            //向系统申请端口号 端口号是系统中所有程序没有使用过的端口,才能使用成功
            //端口号的范围:0-65535之间 0-1023之间是系统端口
            ServerSocket server = new ServerSocket(8088);
            System.out.println("服务端开启成功!!!");
            Server s = new Server();
            while(true){
                System.out.println("等待客户端连接:");
                //阻塞方法 accept():等待客户端的连接
                Socket accept = server.accept();
                System.out.println("和客户端连接成功!!!");
                //获取IP地址
                InetAddress address = accept.getInetAddress();
                String ip = address.getHostAddress();
                System.out.println(ip);
                Thread t = new Thread(s.new ClientHandler(accept));
                t.start();
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    class ClientHandler implements Runnable{
        private Socket socket;
        public ClientHandler(Socket socket){
            this.socket = socket;
        }
        public void run(){
            try{
                InputStream is = socket.getInputStream();
                InputStreamReader isr = new InputStreamReader(is,"GBK");
                BufferedReader br = new BufferedReader(isr);

                OutputStream os = socket.getOutputStream();
                OutputStreamWriter osw = new OutputStreamWriter(os,"GBK");
                PrintWriter pw = new PrintWriter(osw,true);
                //一个客户端连接服务器,则把输出流存入到集合中
                String str = null;
                //用户名
                String name = br.readLine();
                allPw.add(pw);
                map.put(name, pw);
                while((str = br.readLine())!=null){
                    if(str.equals("1")){//私聊工作
                        //需要私聊的对象
                        str = br.readLine();
                        //私聊对象的输出流
                        PrintWriter p = map.get(str);
                        str = br.readLine();
                        p.println(str);
                    }else{//群发

                        System.out.println("");
                        str = br.readLine();
                        for(PrintWriter p:allPw){
                            if(p == pw){
                                continue;
                            }
                            p.println(str);
                        }
                    }
                }
            }catch(IOException e){
                e.printStackTrace();
            }
        }
    }
}

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

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

相关文章

路由引入,过滤实验

实验拓补图 实验目的&#xff1a; 1、按照图示配置 IP 地址&#xff0c;R1&#xff0c;R3&#xff0c;R4 loopback口模拟业务网段 2、R1 和 R2 运行 RIPv2,R2&#xff0c;R3和R4运行 OSPF&#xff0c;各自协议内部互通 3、在 RIP 和 oSPF 间配置双向路由引入,要求除 R4 上的…

Docker容器:镜像与容器命令管理

目录 一、镜像管理命令 1、搜索镜像 2、获取镜像 3、镜像加速下载 4、查看下载的镜像文件信息 5、查看下载到本地的所有镜像 6、获取指定镜像的详细信息 7、为本地的镜像添加新的标签 8、删除镜像 8.1 删除指定的镜像 8.2 批量删除多个镜像 9、导出镜像与导入镜像 …

Docker 基本认识

一 国内&#xff1a; 中国电信天翼云 提供包括云主机在内的全方位云计算服务&#xff0c;侧重于安全合规和企业级服务。 利用电信的网络优势&#xff0c;提供稳定可靠的基础设施服务。 中国联通沃云 提供包括云主机在内的多项云计算服务&#xff0c;适合不同行业和场景。 …

Linux——web服务配置

一、HTTP概念 HTTP请求报文&#xff1a;客户端发送给服务器的消息&#xff0c;用于请求特定资源或执行特定操作。HTTP请求报文由 请求行、请求头部和请求正文三部分组成。 请求方法&#xff1a; HTTP 请求方法是指客户端与服务器通信时&#xff0c;客户端所请求执行的动作。常…

docker内实现多机多卡分布式训练

docker内实现多机多卡分布式训练 1. 多台docker宿主机网络配置2. 创建overlay 网络3. 注意 1. 多台docker宿主机网络配置 https://docs.docker.com/network/overlay/ 这里需要创建overlay网络使得多台宿主机的容器可以通过网络连接 初始化swarm集群&#xff0c;并设置主节点&a…

架构师核心-云计算云上实战(云计算基础、云服务器ECS、云设施实战、云上高并发Web架构)

文章目录 云计算基础1. 概念1. 云平台优势2. 公有云3. 私有云4. IaaS、PaaS、SaaS 2. 云设施1. 概览2. 核心组件 云服务器ECS1. ECS介绍1. 简介2. 组件3. 概念4. 图解5. 规格6. 场景 2. ECS服务器开通1. 开通服务器2. 连接服务器 3. 云部署准备1. 1Panel介绍2. 安装1Panel3.安全…

函数的使用

Oracle从入门到总裁:​​​​​​https://blog.csdn.net/weixin_67859959/article/details/135209645 前面已经介绍了函数的创建以及调用&#xff0c;下面就通过范例学习函数的使用 创建一个函数&#xff0c;如果是偶数则计算其平方&#xff0c;如果是奇数则计算其平方根 分…

基于JAVA的机场航班起降与协调管理系统

毕业设计&#xff08;论文&#xff09;任务书 第1页 毕业设计&#xff08;论文&#xff09;题目&#xff1a; 基于JAVA的机场航班起降与协调管理系统 毕业设计&#xff08;论文&#xff09;要求及原始数据&#xff08;资料&#xff09;&#xff1a; 1&#xff0e;综述机场航班调…

模块三:二分——69.x的平方根

文章目录 题目描述算法原理解法一&#xff1a;暴力查找解法二&#xff1a;二分查找 代码实现暴力查找CJava 题目描述 题目链接&#xff1a;69.x的平方根 算法原理 解法一&#xff1a;暴力查找 依次枚举 [0, x] 之间的所有数 i &#xff08;这⾥没有必要研究是否枚举到 x /…

三分钟快速理解Flink 作业提交流程(包工头的工程之路)

核心组件 我们先来简单了解一下 flink 作业提交涉及到的组件 同时&#xff0c;如果不了解 Yarn 的同学欢迎跳转到这篇文章&#xff0c;了解一下健鑫集团的工程承包流程(doge): 三分钟快速理解Yarn的工作流程 JobManager JobManager 是整个flink作业的管理者 包含 Dispatch…

java 学习一

jdk下载地址 配置环境变量

多项式和Bezier曲线拟合

目录 1. 多项式拟合2. Bezier曲线拟合3. 源码地址 1. 多项式拟合 在曲线拟合中&#xff0c;多项式拟合方法的性能受到三个主要因素的影响&#xff1a;采样点个数、多项式阶数和正则项。 采样点个数 N N N&#xff1a;从Figure 1中可以看出较少的采样点个数可能导致过拟合&…

【Nginx】centos和Ubuntu操作系统下载Nginx配置文件并启动Nginx服务详解

目录 &#x1f337; 安装Nginx环境 &#x1f340; centos操作系统 &#x1f340; ubuntu操作系统 &#x1f337; 安装Nginx环境 以下是在linux系统中安装Nginx的步骤&#xff1a; 查看服务器属于哪个操作系统 cat /etc/os-release安装 yum&#xff1a; 如果你确定你的系统…

Linux驱动开发——(四)内核定时器

一、内核的时间管理 1.1 节拍率 Linux内核中有大量的函数需要时间管理&#xff0c;比如周期性的调度程序、延时程序等等&#xff0c;对于驱动编写者来说最常用的是定时器。 硬件定时器提供时钟源&#xff0c;时钟源的频率可以设置&#xff0c;设置好以后就周期性的产生定时中…

linux负载均衡 和 系统负载分析笔记

1 负载均衡 1.1 计算负载 1.1.1 PELT算法简介 从Linux3.8内核以后进程的负载计算不仅考虑权重&#xff0c;⽽且跟踪每个调度实体的历史负载情况&#xff0c;该算法称为PELT(Per-entity Load Tracking) 《奔跑吧Linux内核》卷1&#xff1a;基础架构&#xff1b;P505 相关资料…

stack、queue(priority_queue)的模拟实现和deque的简单介绍

stack和queue(priority_queue) 1. 容器适配器 适配器(Adapter)&#xff1a;一种用来修饰容器(Containers)或仿函数(Functors)或迭代器(Iterator)接口的东西。 适配器是一种设计模式&#xff0c;该模式将一个类的接口转换成客户希望的另外一个接口。 现实中拿插座来说&#xf…

serverLess

第一步 安装依赖 npm install serverless-devs/s g 第二步 配置秘钥&#xff1a; 第三步 执行终端 执行命令 s config add 选择 alibaba cloud &#xff08;alibaba&#xff09; 把对应的ID secret填写&#xff0c;第三个别名可以随便写&#xff1a; serverLess 查看是…

ClickHouse 高可用之副本

文章目录 ClickHouse 副本支持副本的引擎配置高可用副本副本应用1.副本表概述2.创建副本表3.写入模拟数据4.副本验证 扩展 —— 在 Zookeeper 中查看副本表信息 ClickHouse 副本 ClickHouse 通过副本机制&#xff0c;可以将数据拷贝存储在不同的节点上。这样&#xff0c;如果一…

Redis底层数据结构之Dict

目录 一、概述二、Dict结构三、Dictht结构四、DictEntry结构五、核心特性 上一篇文章 reids底层数据结构之quicklist 一、概述 Redis 的 Dict 是一个高效的键值对映射数据结构&#xff0c;采用双哈希表实现以支持无锁的渐进式 Rehash&#xff0c;确保扩容或缩容时的高效性能。…

linux autogroup

一&#xff1a;概述 对于linux autogroup的作用&#xff0c;很多同学可能是听说过&#xff0c;但&#xff0c;并未验证过。 考虑下面场景&#xff0c;开两个terminal&#xff0c;T1和T2&#xff0c;在T1中运行进程P1&#xff0c;P1开启9个线程编译代码&#xff0c;在T2中运行…