iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >Java中怎么使用NIO实现网络编程
  • 875
分享到

Java中怎么使用NIO实现网络编程

2023-06-17 12:06:52 875人浏览 薄情痞子
摘要

本篇文章为大家展示了Java中怎么使用NIO实现网络编程,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。为什么需要NIO使用Java编写过Socket程序的同学一定都知道Socket和SocketSe

本篇文章为大家展示了Java中怎么使用NIO实现网络编程,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。

为什么需要NIO

使用Java编写过Socket程序的同学一定都知道Socket和SocketServer。当调用某个调用的时候,调用的地方就会阻塞,等待响应。这种方式对于小规模的程序非常方便,但是对于大型的程序就有点力不从心了,当有大量的连接的时候,我们可以为每一个连接建立一个线程来操作。但是这种做法带来的缺陷也是显而易见的:

  1. 硬件能够支持大量的并发

  2. 并发的数量始终有一个上限。

  3. 各个线程之间的优先级不好控制。

  4. 各个Client之间的交互与同步困难。

我们也可以使用一个线程来处理所有的请求,使用不阻塞的io,轮询查询所有的Client。这种做法同样也有缺陷:无法迅速响应Client端,同时会消耗大量轮询查询的时间。

所以,我们需要一种poll的模式来处理这种情况,从大量的网络连接中找出来真正需要服务的Client。这正是NIO诞生的原因:提供一种Poll的模式,在所有的Client中找到需要服务的Client。

回到我们刚刚说到的3个最最重要的Class:java.nio.channels中Selector和Channel,以及java.nio中的Buffer。

Channel代表一个可以被用于Poll操作的对象(可以是文件流也可以使网络流),Channel能够被注册到一个Selector中。通过调用Selector的select方法可以从所有的Channel中找到需要服务的实例(Accept,read ..)。

Buffer对象提供读写数据的缓存。相对于我们熟悉的Stream对象,Buffer提供更好的性能以及更好的编程透明性(人为控制缓存的大小以及具体的操作)。

配合BUFFER使用CHANNEL

与传统模式的编程不用,Channel不使用Stream,而是Buffer。我们来实现一个简单的非阻塞Echo Client:

package com.cnblogs.gpcuster;  import java.net.InetSocketAddress; import java.net.SocketException; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel;  public class tcpEchoClientNonblocking { public static void main(String args[]) throws Exception { if ((args.length < 2) || (args.length > 3))// Testforcorrect#ofargs throw new IllegalArgumentException( "Parameter(s): <Server> <Word> [<Port>]"); String server = args[0];// ServernameorIPaddress // ConvertinputStringtobytesusingthedefaultcharset byte[] argument = args[1].getBytes(); int servPort = (args.length == 3) ? Integer.parseInt(args[2]) : 7; // Createchannelandsettononblocking SocketChannel clntChan = SocketChannel.open(); clntChan.configureBlocking(false); // Initiateconnectiontoserverandrepeatedlypolluntilcomplete if (!clntChan.connect(new InetSocketAddress(server, servPort))) { while (!clntChan.finishConnect()) { System.out.print(".");// Dosomethingelse } } ByteBuffer writeBuf = ByteBuffer.wrap(argument); ByteBuffer readBuf = ByteBuffer.allocate(argument.length); int totalBytesRcvd = 0;// Totalbytesreceivedsofar int bytesRcvd;// Bytesreceivedinlastread while (totalBytesRcvd < argument.length) { if (writeBuf.hasRemaining()) { clntChan.write(writeBuf); } if ((bytesRcvd = clntChan.read(readBuf)) == -1) { throw new SocketException("Connection closed prematurely"); } totalBytesRcvd += bytesRcvd; System.out.print(".");// Dosomethingelse } System.out.println("Received:" + // converttoStringperdefaultcharset new String(readBuf.array(), 0, totalBytesRcvd)); clntChan.close(); } }

这段代码使用ByteBuffer来保存读写的数据。通过clntChan.configureBlocking(false); 设置后,其中的connect,read,write操作都不回阻塞,而是立刻放回结果。

使用SELECTOR

Selector的可以从所有的被注册到自己Channel中找到需要服务的实例。

我们来实现Echo Server。

首先,定义一个接口:

package com.cnblogs.gpcuster;  import java.nio.channels.SelectionKey; import java.io.IOException;  public interface TCPProtocol { void handleAccept(SelectionKey key) throws IOException;  void handleRead(SelectionKey key) throws IOException;  void handleWrite(SelectionKey key) throws IOException; } 我们的Echo Server将使用这个接口。然后我们实现Echo Server: import java.io.IOException; import java.net.InetSocketAddress; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.util.Iterator;  public class TCPServerSelector { private static final int BUFSIZE = 256;// Buffersize(bytes) private static final int TIMEOUT = 3000;// Waittimeout(milliseconds)  public static void main(String[] args) throws IOException { if (args.length < 1) {// Testforcorrect#ofargs throw new IllegalArgumentException("Parameter(s):<Port>..."); } // Createaselectortomultiplexlisteningsocketsandconnections Selector selector = Selector.open(); // CreatelisteningsocketchannelforeachportandreGISterselector for (String arg : args) { ServerSocketChannel listnChannel = ServerSocketChannel.open(); listnChannel.socket().bind( new InetSocketAddress(Integer.parseInt(arg))); listnChannel.configureBlocking(false);// mustbenonblockingtoregister // Registerselectorwithchannel.Thereturnedkeyisignored listnChannel.register(selector, SelectionKey.OP_ACCEPT); } // Createahandlerthatwillimplementtheprotocol TCPProtocol protocol = new EchoSelectorProtocol(BUFSIZE); while (true) {// Runforever,processingavailableI/Ooperations // Waitforsomechanneltobeready(ortimeout) if (selector.select(TIMEOUT) == 0) {// returns#ofreadychans System.out.print("."); continue; } // GetiteratoronsetofkeyswithI/Otoprocess Iterator<SelectionKey> keyIter = selector.selectedKeys().iterator(); while (keyIter.hasNext()) { SelectionKey key = keyIter.next();// Keyisbitmask // ServersocketchannelhaspendinGConnectionrequests? if (key.isAcceptable()) { protocol.handleAccept(key); } // Clientsocketchannelhaspendingdata? if (key.isReadable()) { protocol.handleRead(key); } // Clientsocketchannelisavailableforwritingand // keyisvalid(i.e.,channelnotclosed)? if (key.isValid() && key.isWritable()) { protocol.handleWrite(key); } keyIter.remove();// removefromsetofselectedkeys } } } }

我们通过listnChannel.register(selector, SelectionKey.OP_ACCEPT); 注册了一个我们感兴趣的事件,然后调用selector.select(TIMEOUT)等待订阅的时间发生,然后再采取相应的处理措施。

***我们实现EchoSelectorProtocol

package com.cnblogs.gpcuster;  import java.nio.channels.SelectionKey; import java.nio.channels.SocketChannel; import java.nio.channels.ServerSocketChannel; import java.nio.ByteBuffer; import java.io.IOException;  public class EchoSelectorProtocol implements TCPProtocol { private int bufSize;// SizeofI/Obuffer  public EchoSelectorProtocol(int bufSize) { this.bufSize = bufSize; }  public void handleAccept(SelectionKey key) throws IOException { SocketChannel clntChan = ((ServerSocketChannel) key.channel()).accept(); clntChan.configureBlocking(false);// Mustbenonblockingtoregister // Registertheselectorwithnewchannelforreadandattachbytebuffer clntChan.register(key.selector(), SelectionKey.OP_READ, ByteBuffer .allocate(bufSize)); }  public void handleRead(SelectionKey key) throws IOException { // Clientsocketchannelhaspendingdata SocketChannel clntChan = (SocketChannel) key.channel(); ByteBuffer buf = (ByteBuffer) key.attachment(); long bytesRead = clntChan.read(buf); if (bytesRead == -1) {// Didtheotherendclose? clntChan.close(); } else if (bytesRead > 0) { // Indicateviakeythatreading/writingarebothofinterestnow. key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE); } }  public void handleWrite(SelectionKey key) throws IOException {  // Retrievedatareadearlier ByteBuffer buf = (ByteBuffer) key.attachment(); buf.flip();// Preparebufferforwriting SocketChannel clntChan = (SocketChannel) key.channel(); clntChan.write(buf); if (!buf.hasRemaining()) {// Buffercompletelywritten? // Nothingleft,sonolongerinterestedinwrites key.interestOps(SelectionKey.OP_READ); } buf.compact();// MakeroomfORMoredatatobereadin } }

上述内容就是Java中怎么使用NIO实现网络编程,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注编程网精选频道。

--结束END--

本文标题: Java中怎么使用NIO实现网络编程

本文链接: https://www.lsjlt.com/news/288806.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • c#程序自启动怎么设置
    c# 程序的自启动方法有三种:注册表:在指定注册表项下创建新值,并将其设置为程序可执行文件路径。任务计划程序:创建一个新任务,并在触发器和动作部分分别指定登录时或特定时间触发,以及启动程...
    99+
    2024-05-14
    c#
  • c#怎么调用dll文件
    可在 c# 中轻松调用 dll 文件:引用 dll(使用 dllimport 特性)定义与 dll 函数签名匹配的函数原型调用 dll 函数(如同 c# 函数)附加技巧:使用 chars...
    99+
    2024-05-14
    c#
  • 如何构建 Golang RESTful API,并实现 CRUD 操作?
    通过创建 golang 项目并安装必要的包,我们可以构建一个功能齐全的 restful api。它使用 mysql 数据库进行 crud 操作:1. 创建和连接数据库;2. 定义数据结构...
    99+
    2024-05-14
    go crud mysql git golang
  • c#怎么添加类文件
    在c#中添加类文件的步骤:1. 创建新项目,2. 添加新类,3. 为类添加代码,4. 在另一个类中引用新类。using语句引用类文件所在的命名空间;new运算符创建类的新实例;点运算符访...
    99+
    2024-05-14
    c#
  • 使用 C++ 构建高性能服务器架构的最佳实践
    遵循 c++++ 中构建高性能服务器架构的最佳实践可以创建可扩展、可靠且可维护的系统:使用线程池以重用线程,提高性能。利用协程减少上下文切换和内存开销,提升性能。通过智能指针和引用计数优...
    99+
    2024-05-14
    c++ 高性能服务器架构 数据访问
  • c#怎么添加字段
    在 c# 中添加字段包括以下步骤:声明字段:在类或结构中使用 字段类型 字段名; 语法声明字段。访问修饰符:用于限制对字段的访问,如 private、public、protected 和...
    99+
    2024-05-14
    c#
  • c#中怎么添加引用
    c# 中添加引用的方法有四种:使用 nuget 包管理器添加软件包。添加项目引用以包含其他项目。手动编辑项目文件 (.csproj) 以添加引用。从编译器命令行使用 /reference...
    99+
    2024-05-14
    c#
  • c#怎么创建文本文件
    在 c# 中创建文本文件的方法包括:创建 filestream 对象以打开或创建文件。使用 streamwriter 写入文本至文件。关闭 streamwriter 对象释放资源。关闭 ...
    99+
    2024-05-14
    c#
  • c#怎么定义属性
    如何在 c# 中定义属性 属性是一种编程构造,它包含一个 get 访问器和一个 set 访问器,允许以一种类属性的方式访问字段。它们提供了一种安全且封装的方式来访问和修改类的内部数据。 ...
    99+
    2024-05-14
    c#
  • 基于 C++ 的服务器架构的安全性考虑因素
    在设计基于 c++++ 的服务器架构时,安全考虑至关重要:使用 std::string 或 std::vector 避免缓冲区溢出。使用正则表达式或库函数验证用户输入。采用输出转义防止跨...
    99+
    2024-05-14
    安全性 关键词: c++ 服务器架构 c++ lsp
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作