Java分别用BIO、NIO实现简单的客户端服务器通信

分别用BIO、NIO实现客户端服务器通信

    • BIO
    • NIO
      • NIO演示(无Selector)
      • NIO演示(Selector)

前言:
Java I/O模型发展以及Netty网络模型的设计思想

BIO

Java BIO是Java平台上的BIO(Blocking I/O)模型,是Java中用于实现同步阻塞网络编程的一种方式。 在Java中,使用BIO模型需要通过Socket和ServerSocket类来完成网络连接和数据传输,但是由于BIO是同步阻塞的,所以会导致线程阻塞和资源浪费的问题。
因此,在高并发的网络编程场景中,通常会选择使用NIO(Non-blocking I/O)模型或者Netty等框架来实现。

在这里插入图片描述
服务端类代码

package com.yu.io.bio;import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;public class BIOServer {public static void main(String[] args) throws IOException {ServerSocket serverSocket = new ServerSocket(8081);while (true) {System.out.println("wait connect...");Socket clientSocket = serverSocket.accept();System.out.println(clientSocket.getPort() + "connected");System.out.println("start read...");byte[] readArr = new byte[1024];int read = clientSocket.getInputStream().read(readArr);if (read != -1) {System.out.println("read info : " + new String(readArr,0,read));}System.out.println("end read...");byte[] resBytes = "server response".getBytes();clientSocket.getOutputStream().write(resBytes);System.out.println("response info : " + new String(readArr,0,read));clientSocket.getOutputStream().flush();}}
}

客户端类代码

package com.yu.io.bio;import java.io.IOException;
import java.net.Socket;public class BIOClient {public static void main(String[] args) throws IOException {Socket clientSocket = new Socket("127.0.0.1",8081);byte[] resBytes = "client response".getBytes();clientSocket.getOutputStream().write(resBytes);System.out.println("response info : " + new String(resBytes));clientSocket.getOutputStream().flush();byte[] readArr = new byte[1024];int read = clientSocket.getInputStream().read(readArr);if (read != -1) {System.out.println("read info : " + new String(readArr,0,read));}}
}

NIO

Java NIO 能够支持非阻塞网络编程,可以理解为new io 或者no blok io 我更喜欢称之为new io,因为他不仅仅实现了非阻塞的网络编程方式,同时也封装了常用的网络编程api,更重要的是引入了多路复用器Selector的概念

在这里插入图片描述

下面的代码只是展示NIO非阻塞的实现,并没有展示NIO的真正用法

NIO演示(无Selector)

服务端类代码

package com.yu.io.nio;import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.List;public class NIOServer {public static List<SocketChannel> socketChannelList = new ArrayList<>();public static void main(String[] args) throws IOException {ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();serverSocketChannel.socket().bind(new InetSocketAddress(8081));serverSocketChannel.configureBlocking(false);System.out.println("server start...");while (true) {SocketChannel socketChannel = serverSocketChannel.accept();if (socketChannel != null) {System.out.println(socketChannel.socket().getPort() + " connected");socketChannel.configureBlocking(false);socketChannelList.add(socketChannel);}List<SocketChannel> rmChannelList = new ArrayList<>();for (SocketChannel channel : socketChannelList) {try {doChannel(rmChannelList, channel);} catch (IOException ioException) {//有客户端断开连接System.out.println(channel.socket().getPort() + " disconnected");channel.close();rmChannelList.add(channel);}}socketChannelList.removeAll(rmChannelList);}}private static void doChannel(List<SocketChannel> rmChannelList, SocketChannel channel) throws IOException {ByteBuffer readByteBuffer = ByteBuffer.allocate(2048);int read = channel.read(readByteBuffer);String readStr = new String(readByteBuffer.array());if (read > 0) {System.out.println(channel.socket().getPort() + " : " + readStr);if (readStr.contains("hello")) {ByteBuffer sendByteBuffer = ByteBuffer.wrap("hello! I am robot.".getBytes());channel.write(sendByteBuffer);System.out.println("me : " + new String(sendByteBuffer.array()));}if (readStr.contains("old")) {ByteBuffer sendByteBuffer = ByteBuffer.wrap("I am 1 years old.".getBytes());channel.write(sendByteBuffer);System.out.println("me : " + new String(sendByteBuffer.array()));}if (readStr.contains("bey")) {ByteBuffer sendByteBuffer = ByteBuffer.wrap("see you.".getBytes());channel.write(sendByteBuffer);System.out.println("me : " + new String(sendByteBuffer.array()));}}if (read == -1) {rmChannelList.add(channel);}}
}

客户端类代码

package com.yu.io.nio;import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;public class NIOClient {public static void main(String[] args) throws IOException {SocketChannel clientSocketChannel = SocketChannel.open();clientSocketChannel.connect(new InetSocketAddress("127.0.0.1",8081));clientSocketChannel.configureBlocking(false);String sendStr = "hello! I am client " + clientSocketChannel.socket().getPort() + ".";ByteBuffer sendByteBuffer = ByteBuffer.wrap(sendStr.getBytes());clientSocketChannel.write(sendByteBuffer);System.out.println("me : " + new String(sendByteBuffer.array()));int msgSize = 0;while (msgSize < 10) {ByteBuffer readByteBuffer = ByteBuffer.allocate(1024);int read = clientSocketChannel.read(readByteBuffer);String readStr = new String(readByteBuffer.array());if (read > 0) {System.out.println("robot : " + readStr);msgSize ++;ByteBuffer resByteBuffer = null;if (readStr.contains("hello")) {resByteBuffer = ByteBuffer.wrap("how old are you?.".getBytes());clientSocketChannel.write(resByteBuffer);System.out.println("me : " + new String(resByteBuffer.array()));resByteBuffer.clear();}if (readStr.contains("old")) {resByteBuffer = ByteBuffer.wrap("en, place say hello!".getBytes());clientSocketChannel.write(resByteBuffer);System.out.println("me : " + new String(resByteBuffer.array()));resByteBuffer.clear();}}}ByteBuffer resByteBuffer = ByteBuffer.wrap("bey bey!".getBytes());clientSocketChannel.write(resByteBuffer);System.out.println("me : " + new String(resByteBuffer.array()));resByteBuffer.clear();clientSocketChannel.close();}
}

NIO演示(Selector)

无Selector的NIO演示中,显然会出现空转的情况,以及无效连接的处理问题,这些问题都会影响性能。
NIO提供Selector多路复用器,优化上述问题
以下demo实现服务器与客户端通信,相互发消息。并由服务器转发给其他客户端(广播功能)

服务端类代码

server main类

import java.io.IOException;public class NIOServerMain {public static void main(String[] args) throws IOException {NIOSelectorServer server = new NIOSelectorServer();server.start();}
}

server run类

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;public class NIOSelectorServer {public void start() throws IOException {ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();serverSocketChannel.socket().bind(new InetSocketAddress(8081));serverSocketChannel.configureBlocking(false);//注册到selector多路复用器中Selector selector = Selector.open();serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);System.out.println("server start...");run(selector);}/*** 遍历多路复用器的事件,处理事件*/private void run(Selector selector) throws IOException {while (true) {//阻塞等待事件selector.select();Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();while (iterator.hasNext()) {SelectionKey selectedKey = iterator.next();try {if (selectedKey.isAcceptable()) {doAccept(selector, selectedKey);}if (selectedKey.isReadable()) {doReadChannel(selectedKey, selector);}} catch (IOException ioException) {//有客户端断开连接disConnect(selectedKey, "exception");}iterator.remove();}}}/*** 处理连接事件*/private void doAccept(Selector selector, SelectionKey selectedKey) throws IOException {ServerSocketChannel serverChannel = (ServerSocketChannel)selectedKey.channel();SocketChannel socketChannel = serverChannel.accept();socketChannel.configureBlocking(false);socketChannel.register(selector, SelectionKey.OP_READ);System.out.println(socketChannel.socket().getPort() + " connected");}/*** 处理接收信息事件*/private void doReadChannel(SelectionKey selectedKey, Selector selector) throws IOException {SocketChannel channel = (SocketChannel)selectedKey.channel();ByteBuffer readByteBuffer = ByteBuffer.allocate(2048);int read = channel.read(readByteBuffer);String readStr = "";readByteBuffer.flip();readStr += StandardCharsets.UTF_8.decode(readByteBuffer);if (read > 0) {System.out.println(channel.socket().getPort() + " : " + readStr.length() + " - "+ readStr);//转发消息(其他客户端)broadcast(selectedKey, selector, readStr);if (readStr.contains("hello")) {sendMsg(channel, "hello! I am robot.");}if (readStr.contains("old")) {sendMsg(channel, "I am 1 years old.");}if (readStr.contains("bye")) {sendMsg(channel, "see you.");}}if (read == -1) {//有客户端断开连接disConnect(selectedKey, "read = -1");}}/*** 连接异常的处理*/private void disConnect(SelectionKey selectedKey, String type) throws IOException {SocketChannel channel = (SocketChannel)selectedKey.channel();System.out.println(channel.socket().getPort() + " disconnected. " + type);selectedKey.cancel();channel.close();}/*** 发送消息*/private void sendMsg(SocketChannel channel, String s) throws IOException {ByteBuffer sendByteBuffer = ByteBuffer.wrap(s.getBytes());channel.write(sendByteBuffer);System.out.println("me : " + new String(sendByteBuffer.array()));}/*** 广播* 转发消息(给其他客户端)*/private void broadcast(SelectionKey  fromSelectedKey, Selector selector, String readStr) throws IOException {Iterator<SelectionKey> selectionKeyIterator = selector.keys().iterator();while (selectionKeyIterator.hasNext()) {SelectionKey otherKey = selectionKeyIterator.next();if (otherKey == fromSelectedKey) {continue;}if (!(otherKey.channel() instanceof SocketChannel)) {continue;}SocketChannel otherChannel = (SocketChannel)otherKey.channel();sendMsg(otherChannel, "(转发自 "+ ((SocketChannel)fromSelectedKey.channel()).socket().getPort() + ")" + readStr);}}
}

客户端代码

一共构造了两个客户端(消息客户端和looker客户端), looker客户端优先启动,随后启动消息客户端,消息客户端与服务器的通信会被转发给looker客户端

look client main类

import java.io.IOException;public class NIOClientLookMain {public static void main(String[] args) throws IOException, InterruptedException {NIOSelectorClient client = new NIOSelectorLookClient();client.start(8081, 100);}
}

msg client main类

import java.io.IOException;public class NIOClientMain {public static void main(String[] args) throws IOException, InterruptedException {NIOSelectorClient lookClient = new NIOSelectorClient();lookClient.start(8081, 10);}
}

client run类

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;public class NIOSelectorClient {protected int port;protected int size;public void start(int port, int size) throws IOException, InterruptedException {this.port = port;this.size = size;SocketChannel clientSocketChannel = SocketChannel.open();clientSocketChannel.connect(new InetSocketAddress("127.0.0.1",port));clientSocketChannel.configureBlocking(false);Selector selector = Selector.open();clientSocketChannel.register(selector, SelectionKey.OP_READ);//发送开始数据sendMsg(clientSocketChannel, "hello! I am client " + clientSocketChannel.socket().getLocalPort() + ".");run(selector);sendMsg(clientSocketChannel, "bye bye!");clientSocketChannel.close();}/*** 遍历多路复用器的事件,处理事件*/protected void run(Selector selector) throws IOException, InterruptedException {int msgSize = 0;while (msgSize < size) {int length=selector.select();if(length ==0){continue;}Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();while(iterator.hasNext()){SelectionKey selectionKey = iterator.next();if(selectionKey.isReadable()){boolean readChannel = false;try {readChannel = doReadChannel(selectionKey, selector);} catch (IOException e) {selectionKey.cancel();System.out.println("robot disconnect, restart connect...");while (true){try {reConnect();return;} catch (IOException ioException) {System.out.println("restart connecting(5s) ");//ioException.printStackTrace();Thread.sleep(5000);}}}if (readChannel) {msgSize ++;}}iterator.remove();}}}protected boolean doReadChannel(SelectionKey selectedKey, Selector selector) throws IOException {SocketChannel channel = (SocketChannel)selectedKey.channel();ByteBuffer readByteBuffer = ByteBuffer.allocate(2048);int read = channel.read(readByteBuffer);String readStr = "";readByteBuffer.flip();readStr += StandardCharsets.UTF_8.decode(readByteBuffer);if (read > 0) {System.out.println("robot : " + readStr);if (readStr.contains("hello")) {sendMsg(channel, "how old are you?.");}if (readStr.contains("old")) {sendMsg(channel, "en, place say hello!");}return true;}return false;}protected void sendMsg(SocketChannel channel, String sendStr) throws IOException {ByteBuffer sendByteBuffer = ByteBuffer.wrap(sendStr.getBytes());channel.write(sendByteBuffer);System.out.println("me : " + new String(sendByteBuffer.array()));}protected void reConnect() throws IOException, InterruptedException {NIOSelectorClient client = new NIOSelectorClient();client.start(port, size);}
}

look client run类

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;public class NIOSelectorLookClient extends NIOSelectorClient{@Overridepublic void start(int port, int size) throws IOException, InterruptedException {this.port = port;this.size = size;SocketChannel clientSocketChannel = SocketChannel.open();clientSocketChannel.connect(new InetSocketAddress("127.0.0.1",port));clientSocketChannel.configureBlocking(false);Selector selector = Selector.open();clientSocketChannel.register(selector, SelectionKey.OP_READ);//发送开始数据sendMsg(clientSocketChannel, "I am looker. " + clientSocketChannel.socket().getLocalPort() + ".");run(selector);}@Overrideprotected boolean doReadChannel(SelectionKey selectedKey, Selector selector) throws IOException {SocketChannel channel = (SocketChannel)selectedKey.channel();ByteBuffer readByteBuffer = ByteBuffer.allocate(2048);int read = channel.read(readByteBuffer);String readStr = "";readByteBuffer.flip();readStr += StandardCharsets.UTF_8.decode(readByteBuffer);if (read > 0) {System.out.println("robot : " + readStr.length() + " - "+ readStr);if (readStr.contains("bye")) {sendMsg(channel, "bye.");}return true;}return false;}@Overrideprotected void reConnect() throws IOException, InterruptedException {NIOSelectorClient client = new NIOSelectorLookClient();client.start(port, size);}
}

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

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

相关文章

【深入解析spring cloud gateway】02 网关路由断言

一、断言(Predicate)的意义 断言是路由配置的一部分&#xff0c;当断言条件满足&#xff0c;即执行Filter的逻辑&#xff0c;如下例所示 spring:cloud:gateway:routes:- id: add_request_header_routeuri: https://example.orgpredicates:- Path/red/{segment}filters:- AddR…

Kafka3.0.0版本——文件存储机制

这里写木目录标题 一、Topic 数据的存储机制1.1、Topic 数据的存储机制的概述1.2、Topic 数据的存储机制的图解1.3、Topic 数据的存储机制的文件解释 二、Topic数据的存储位置示例 一、Topic 数据的存储机制 1.1、Topic 数据的存储机制的概述 Topic是逻辑上的概念&#xff0c…

ASP.NET Core 中基于 Controller 的 Web API

基于 Controller 的 Web API ASP.NET Wep API 的请求架构 客户端发送Http请求&#xff0c;Contoller响应请求&#xff0c;并从数据库读取数据&#xff0c;序列化数据&#xff0c;然后通过 Http Response返回序列化的数据。 ControllerBase 类 Web API 的所有controllers 一般…

植物大战僵尸植物表(二)

前言 此文章为“植物大战僵尸”专栏中的第007刊&#xff08;2023年9月第六刊&#xff09;。 提示&#xff1a; 1.用于无名版&#xff1b; 2.用于1代&#xff1b; 3.pvz指植物大战僵尸&#xff08;Plants VS Zonbies)。 植物大战僵尸植物表 土豆雷窝瓜火炬树桩火爆辣椒杨…

数学建模:拟合算法

&#x1f506; 文章首发于我的个人博客&#xff1a;欢迎大佬们来逛逛 数学建模&#xff1a;拟合算法 文章目录 数学建模&#xff1a;拟合算法拟合算法多项式拟合非线性拟合cftool工具箱的使用 拟合算法 根据1到12点间的温度数据求出温度与时间之间的近似函数关系 F ( t ) F(…

【FPGA项目】沙盘演练——基础版报文收发

​​​​​​​ ​​​​​​​ ​​​​​​​ ​​​​​​​ 第1个虚拟项目 前言 点灯开启了我们的FPGA之路&#xff0c;那么我们来继续沙盘演练。 用一个虚拟项目&#xff0c;来入门练习&#xff0c;以此步入数字逻辑的大门。 Key Words&…

【网络编程】TCP/IP协议(互联网的基石)

(꒪ꇴ꒪ )&#xff0c;Hello我是祐言QAQ我的博客主页&#xff1a;C/C语言&#xff0c;数据结构&#xff0c;Linux基础&#xff0c;ARM开发板&#xff0c;网络编程等领域UP&#x1f30d;快上&#x1f698;&#xff0c;一起学习&#xff0c;让我们成为一个强大的攻城狮&#xff0…

Go语言最全面试题,拿offer全靠它,附带免积分下载pdf

面试题文档下链接点击这里免积分下载 go语言入门到精通点击这里免积分下载 文章目录 Go 基础类GO 语言当中 NEW 和 MAKE 有什么区别吗&#xff1f;PRINTF(),SPRINTF(),FPRINTF() 都是格式化输出&#xff0c;有什么不同&#xff1f;GO 语言当中数组和切片的区别是什么&#xf…

华为云云服务器评测|云耀云服务器实例基础使用实践

&#x1f996;我是Sam9029&#xff0c;一个前端 Sam9029的CSDN博客主页:Sam9029的博客_CSDN博客-JS学习,CSS学习,Vue-2领域博主 **&#x1f431;‍&#x1f409;&#x1f431;‍&#x1f409;恭喜你&#xff0c;若此文你认为写的不错&#xff0c;不要吝啬你的赞扬&#xff0c;求…

leetcode669. 修剪二叉搜索树(java)

修剪二叉搜索树 题目描述递归代码演示&#xff1a; 题目描述 难度 - 中等 LC - 669. 修剪二叉搜索树 给你二叉搜索树的根节点 root &#xff0c;同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树&#xff0c;使得所有节点的值在[low, high]中。修剪树 不应该 改变保留…

搭建HTTPS服务器

HTTPS代理服务器的作用与价值 HTTPS代理服务器可以帮助我们实现网络流量的转发和加密&#xff0c;提高网络安全性和隐私保护。本文将指导您从零开始搭建自己的HTTPS代理服务器&#xff0c;让您更自由、安全地访问互联网。 1. 准备工作&#xff1a;选择服务器与操作系统 a. 选…

python爬虫关于ip代理池的获取和随机生成

前言 在进行爬虫开发时&#xff0c;代理IP池是一个非常重要的概念。代理IP池是指一个包含多个可用代理IP的集合&#xff0c;这些代理IP可以用来绕过网站的防爬虫策略&#xff0c;从而提高爬取数据的成功率。 在本文中&#xff0c;我们将介绍如何获取代理IP池&#xff0c;并且随…

【C++杂货铺】探索list的底层实现

文章目录 一、list的介绍及使用1.1 list的介绍1.2 list的使用1.2.1 list的构造1.2.2 list iterator的使用1.2.3 list capacity&#xff08;容量相关&#xff09;1.2.4 list element access&#xff08;元素访问&#xff09;1.2.5 list modifiers&#xff08;链表修改&#xff0…

anaconda navigator打不开,一直在loading画面

anaconda navigator打不开&#xff0c;一直在loading画面。百度解决方法&#xff0c;用网上的方法在命令窗口里运行conda update anaconda结果一直显示 solving environment卡在那里。又尝试用管理员身份运行还是不行&#xff0c;打开后出现There in aninstance of Anaconda Na…

C标准输入与标准输出——stdin,stdout

&#x1f517; 《C语言趣味教程》&#x1f448; 猛戳订阅&#xff01;&#xff01;&#xff01; ​—— 热门专栏《维生素C语言》的重制版 —— &#x1f4ad; 写在前面&#xff1a;这是一套 C 语言趣味教学专栏&#xff0c;目前正在火热连载中&#xff0c;欢迎猛戳订阅&#…

iOS系统下轻松构建自动化数据收集流程

在当今信息爆炸的时代&#xff0c;我们经常需要从各种渠道获取大量的数据。然而&#xff0c;手动收集这些数据不仅耗费时间和精力&#xff0c;还容易出错。幸运的是&#xff0c;在现代科技发展中有两个强大工具可以帮助我们解决这一问题——Python编程语言和iOS设备上预装的Sho…

动态规划之简单多状态

简单多状态 1. 按摩师&#xff08;easy&#xff09;2. 打家劫舍II &#xff08;medium&#xff09;3. 删除并获得点数&#xff08;medium&#xff09;4. 买卖股票的最佳时机含冷冻期&#xff08;medium&#xff09;5. 买卖股票的最佳时机III&#xff08;hard&#xff09; 1. 按…

c++(c语言)通用版本的单链表的头插法创建

我们创建一个长度为n的链表时&#xff0c;可以采取头插法创建或者尾插法创建&#xff0c;本篇博客我们采取头插法来创建&#xff0c;&#xff08;作者只学了头插&#xff0c;尾插等以后来补qwq)。 我们先来画图来看看头插的创建形式把&#xff0c;会了原理再写代码。 首先是我…

自定义TimeLine实现卡拉OK轨

系列文章目录 自定义TimeLine 自定义TimeLine 系列文章目录前言正文UI部分代码部分Data&#xff08;数据&#xff09;Clip&#xff08;片段&#xff09;Track&#xff08;轨道&#xff09;Mixer&#xff08;混合&#xff09;被控制物体 总结 前言 自定义TimeLine实际上就是自定…