在Java中使用NIO进行网络编程

Java NIO与Netty网络编程 Java NIO和Netty都是网络编程中的重要技术。Java NIO提供了非阻塞I/O操作的能力,使得开发高性能网络应用成为可能;而Netty则是一个基于Java NIO的高性能网络应用框架,它封装了Java NIO的复杂性,提供了更易于使用的API和丰富的功能。在实际应用中,应根据具体需求和项目特点选择合适的技术,并结合最佳实践进行优化和实现。 阅读详情

在JDK中,有一个非常有意思的库:NIO(New I/O)。这个库中有3个重要的类,分别是java.nio.channels中Selector和Channel,以及java.nio中的Buffer。

本篇文章我们首先了解一下为什么需要NIO来进行网络编程,然后看看一步一步来讲解如何在网络编程中使用NIO。

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

硬件能够支持大量的并发。

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

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

各个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 {
  /*
   * Channelisavailableforwriting,andkeyisvalid(i.e.,clientchannel
   * notclosed).
   */
  // 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
 }
}在这里,我们又进一步对Selector注册了相关的事件:key.interestOps(SelectionKey.OP_READ);

这样,我们就实现了基于NIO的Echo 系统。

 

本文来自优快云博客,转载请标明出处:http://blog.youkuaiyun.com/gpcuster/archive/2009/12/27/5085949.aspx

Java NIO 网络编程中的连接管理 本文旨在全面解析Java NIO在网络编程中的连接管理机制,帮助开发者理解NIO的核心原理并掌握高效管理网络连接的实践技巧。内容涵盖从基础概念到高级应用的全方位知识。文章首先介绍NIO的核心概念,然后深入分析连接管理的实现原理,接着通过实际代码示例展示具体实现,最后讨论应用场景和优化策略。: Java提供的非阻塞I/O APIChannel: 代表与实体的双向连接,如文件或套接字Selector: 多路复用器,用于监控多个Channel的状态Buffer: 数据容器,用于Channel读写操作。 阅读详情

相关推荐

自己手写nio和netty,不建议下载

自己手写nio和netty,不建议下载

NIO模型

NIO的介绍 NIO(New IO)同步非阻塞IO模型,采用了事件驱动的思想来实现一个复用器,来解决大并发的问题 NIO中,将读、写、可连接、可接受等操作在BIO中是阻塞处理,将操作设置为非阻塞,并将这些操作视为事件,当关注某个事件时,将其注册到复用器Selector(本质上使用底层操作系统提供的IO复用器:select、poll,epoll)。由系统来监听事件是否准备就绪, 当socket有读或者可写操作时,系统会通知相应的用户程序来处理,将流读取到缓冲区或者写入到系统中 一个复用器上是...

车车的博客 679

Unable to negotiate with XXXX port 22: no matching host key type found. Their offer: ssh-rsa,ssh-dss

打开ssh_config此文件,滑动到最下面,新增自己git主机地址(这里我直接默认*)执行命令 git clone git@xxxxxxxxxxxxx.git。代码仓库已经添加了ssh公钥之后,克隆代码到本地时就报了这个问题。首先是找到git安装目录(根据自己安装时选项,找到这个目录)再进入ssh目录,找到 ssh_config 配置文件。配置完成后,保存配置文件后再次去clone代码。直接复制下面这一段到文件中最底部位置即可。然后进入 etc目录,找到ssh目录。终于可以克隆下来了。

萌兔兔MMQ!! 3358

Java网络编程——NIO编程

JavaNIO全称javanon-blockingIO,是指JDK提供的新API。从JDK1.4开始,Java提供了一系列改进的输入/输出的新特性,被统称为NIO(即NewIO),是同步非阻塞的.缓冲区(Buffer)缓冲区本质上是一个可以读写数据的内存块,可以理解成是一个数组,该对象提供了一组方法,可以更轻松地使用内存块,缓冲区对象内置了一些机制,能够跟踪和记录缓冲区的状态变化情况。Channel提供从网络读取数据的渠道,但是读取或写入的数据都必须经由Buffer.......

weixin_62017112的博客 2274

别再只会setStyleSheet了!Qt实现背景透明的5种方法全解析(附性能对比)

本文深入解析Qt实现背景透明的5种高阶方案,包括QPalette、setWindowOpacity、QGraphicsOpacityEffect、样式表和复合透明方案,并提供详细的性能对比与优化建议。针对不同平台和场景,帮助开发者选择最适合的透明效果实现方式,提升UI设计质量与性能表现。

weixin_27061475的博客 259

基于IMX429-IMX430-IMX432-IMX437系列传感器的SLVS-MIPI桥接方案设计与实现

本文详细介绍了针对索尼IMX429、IMX430、IMX432及IMX437系列传感器的SLVS-MIPI桥接方案设计与实现。针对工业视觉、车载摄像头等应用中主流SoC仅支持MIPI接口的痛点,提出基于FPGA(如Lattice Crosslink-NX)的透传桥接方案,将传感器输出的SLVS信号无损转换为MIPI CSI-2信号,确保数据完整性与低延迟,并探讨了硬件选型、逻辑设计及多传感器兼容性等关键问题。

weixin_29230901的博客 464

java网络编程之NIO

Java NIO (New IO 或Non Blocking IO) 是从java1.4版本开始引入的一个新的IO API,可以替代标准的Java IO API。NIO支持面向缓存区的,基于通信的IO操作。NIO将以更加高效的方式进行文件的读写操作。java NIO 由以下几个核心部分组成ChannelsBuffersSelectors虽然java NIO 中除此之外还有很多类和组件,但Channel,Buffer和Selector构成了核心的API。

m0_57605288的博客 262

麒麟v10(ky10.x86_64)升级——openssl-3.2.2、openssh-9.8p1

执行命令: make -j 4 && make install 这里要等待一段时间,等待编译完成。执行命令: ./configure --prefix=/usr/local/src/zlilb。执行命令: ./config --prefix=/usr/local/src/openssl。执行命令: make -j 4 && make test && make install。执行命令: make -j 4 && make install。执行命令: /etc/init.d/sshd restart。

X_yufei的博客 7429

ns3源码阅读(四)-Tcp的Accept函数处理流程

 在实际网络编程中,服务器端会监听在port,每当有新的请求到来的时候,应用层可以调用accept函数,从而获取一个新的socket的文件描述符。服务侧可以通过这个新的socketfd同客户端进行通信。  在之前阅读PacketSink这个类的时候,PacketSink::HandleAccept这个函数让我困惑很久。让我困惑的是到底什么时候创建了新的Socket对象,可以被放置在m_socke...

u010643777的专栏 1149

进程间通信的七种方法实战演示!值得收藏!

线程和进程间的通讯(Inter-Process Communication, IPC)是操作系统中的一个重要概念,用于实现不同进程或同一进程中的不同线程之间的数据交换和协调。以下是几个常见的进程间通信的方式:管道、消息队列、共享内存、信号、套接字、信号量、文件映射

十年饮冰,难凉热血,保持热爱,奔赴星海! 2816

如何处理MIGO取消物料凭证报错:“只是可能对有相同的价格控制进行倒记账(本月S,前月V)” & “仅在 QM 中修改物料质量检验库存”

记录一次处理MM模块的报错。这次连续处理了两个错误,“只是可能对有相同的价格控制进行倒记账(本月S,前月V)” & “仅在 QM 中修改物料质量检验库存”。把过程和操作步骤记录下一。方便日后回头查找。

IT小职员 6232

什么还不懂Java NIO,看这一篇博客就够了!

Java NIO 编程 1.1 Java NIO 基本介绍 Java NIO 全称 java non-blocking IO,是指 JDK 提供的新 API。从 JDK1.4 开始,Java 提供了一系列改进的输入/输出的新特性,被统称为 NIO(即 New IO),是同步非阻塞的。 NIO 相关类都被放在 java.nio 包及子包下,并且对原 java.io 包中的很多类进行改写。 NIO 有三大核心部分:  Channel(通道) , Buffer(缓冲区

JeremyIverson的博客 967

蓝牙Mesh协议一基本概念

前言 蓝牙SIG联盟在2017年发布了蓝牙Mesh1.0的协议规格,基于低功耗广播包来实现的多对多的通信技术,Mesh协议建立在BLE的物理层和链路层上,所以也可以和BLE的蓝牙进行通信 本章主要介绍蓝牙Mesh的基本概念和协议中的层级结构,也是参考网上的资料,如有异议,欢迎留言指正 基本概念 广播和洪泛 蓝牙Mesh技术是基于BLE的广播报文来实现的,是一种洪泛的消息传输机制,Mesh网络的节点间通过3个广播信道进行通信。当蓝牙Mesh网络中的节点收到消息后会转发这条消息,大大增加了网络的覆盖范围;但

9743

Java网络编程NIO

缓冲区,包括直接内存缓冲和JVM内存缓冲。NIO是基于channel通信,一个线程管理一个selector,一个selector管理多个channel,这样一个线程就能管理多个客户端连接。一般是通过服务通道监听端口,等待客户端的连接通道,然后将连接通道注册到Selector,等待事件触发通道行为。由于IO无法直接操作应用内存,因此需要将应用内存数据拷贝到直接内存,如果使用直接内存,就可以少一次拷贝操作。:选择器,负责管理多个通道channel,通过监听通道绑定的事件,及时处理通道数据。

weixin_74261199的博客 1324

[明道云] -基础教学1- 创建第一个工作表:从 0 到实用

明道云工作表相当于数据库表,是存储业务数据的核心组件。创建工作表主要有两种方式:1)从空白新建,通过添加字段(最多200个)、设置属性、配置表单样式;2)从Excel导入,需选择sheet、配置字段映射。创建后系统自动生成默认视图,支持多种视图形式(看板/日历等)。建议设置合适的标题字段和关联关系,初学者可在一小时内完成基础应用搭建。后续可扩展权限控制、工作流自动化等功能。

每日出拳老爷子的博客 556

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

Java NIO(三):网络编程NIO

Java NIO(二):标准输入输出NIO 目录 一、Selector 二、SelectionKey 三、一个简单的Server-Client实例 Selector是网络编程NIO中的核心组件 一、Selector Selector(选择器)这个组件用于采集各个通道的状态(事件)。Selector轮询每个注册的Channel,一旦发现Channel有注册的事件发生,便获取事件然后进行...

Jodness' Blogs 892

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

Java NIO 网络编程实践:聊天室

本文主要介绍了Java NIO网络编程实践案例:聊天室的代码实现过程。

专注Java和MySQL领域知识分享 1064

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Java网络编程演进:从NIO到Netty的UDP实践全解析

通过对比NIO和Netty的实现,我们可以清楚地看到Netty在简化网络编程、提高开发效率和性能方面的优势。Netty不仅封装了复杂的NIO操作,还提供了丰富的功能和优化措施,使得开发高性能网络应用变得更加容易。随着技术的不断发展,保持学习和实践的态度,将帮助我们在网络编程领域不断提升。无论是使用NIO还是Netty,核心都是要理解网络编程的基本原理。

阿水的博客 3615

java之NIO入门学习介绍及NIO网络编程Demo

从Java1.4开始就有了NIO,随着程序对性能的要求越来越高,NIO得到了广泛使用。 IO NIO 面向流 面向缓冲区 阻塞 非阻塞 / 有选择器

qq_42401622的博客 488

java 网络编程和NIO

1、软件结构 C/S结构 :全称为Client/Server结构,是指客户端和服务器结构。常见程序有QQ、迅雷等软件。 特点: 客户端和服务器是分开的,需要下载客户端,对网络要求相对低, 服务器压力小,开发和维护成本高,相对稳定 B/S结构 :全称为Browser/Server结构,是指浏览器和服务器结构。常见浏览器有谷歌、火狐等。 特点:没有客户端,只有服务器,不需要下载客户端,直接通过浏览器访问, 对网络要求相对高, 服务器压力很大,相对不稳定,开发和维护成本低, 两种架构各有优势,但是无论哪种架构

chinusyan的专栏 479

Java网络编程:Socket与NIO技术详解

1.背景介绍 1. 背景介绍 Java网络编程是一门重要的技能,它涉及到通信、数据传输、并发等多个领域。在Java中,Socket和NIO是两种常用的网络编程技术,它们各自具有不同的优势和应用场景。本文将详细介绍Socket与NIO技术的核心概念、算法原理、最佳实践以及实际应用场景。 2. 核心概念与联系 2.1 Socket概述 Socket是一种用于建立客户端和服务端之间通信的技术,...

AI天才研究院 2118

Java 网络编程之 NIO

javaNIOJava 网络编程系列之 NIO1.概述阻塞IO线程池非阻塞IO(NIO)NIO流程NIO概述2.java NIO(Channel)Channel 概述Channel接口源码Channel与缓冲区FileChannel 介绍和示例介绍示例方法Socket通道ServerSocketChannelSocketChannelDatagramChannelScatter/Gather3.Java NIO(Buffer)Buffer 简介Buffer的基本用法Buffer 的 capacity、pos

qq_48092631的博客 526

使用Java的IO/NIO处理网络编程:Socket、ServerSocket和NIO通道

需要注意的是,NIO是基于事件驱动的,可以使用Selector来监听多个通道的事件,以提高效率和扩展性。在Java中,可以使用Socket和ServerSocket类进行基于IO的网络编程,以及使用NIO(New IO)中的通道(Channel)进行基于NIO的网络编程。System.out.println("接收到服务器的响应:" + response.toString());无论是基于IO的网络编程还是基于NIO的网络编程,都需要注意资源的释放和异常处理,以确保程序的稳定性和可靠性。

m0_75198698的博客 928

Java网络编程进化史:从IO到NIO再到Netty

Java网络编程进化史:从IO到NIO再到Netty一 IO介绍特点原理流程图:实现server.javaclient.java结果二 NIO介绍1.NIO的特点2.NIO的通信步骤3.原理图实现server.javaclient.java结果三 Netty介绍1.简介2.特点3.Netty通信的步骤4.框架组成实现下载jar包server.javaclient.java结果 一 IO 介绍 特点 1.服务端阻塞点 server.accept();获取套接字的时候 inputStream.read(by

qq_33700652的博客 687
上一篇: javascript的domReady
下一篇: Java并发--任务执行
kbeanwu
博客等级 码龄17年 8粉丝 12原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值