使用Java NIO提高服务端程序的性能

Java NIO增加了新的SocketChannel、ServerSocketChannel等类来提供对构建高性能的服务端程序的支持。 SocketChannel、ServerSocketChannel能够在非阻塞的模式下工作,它们都是selectable的类。在构建服务器或者中间件时,推荐使用Java NIO。

在传统的网络编程中,我们通常使用一个专用线程(Thread)来处理一个Socket连接,通过使用NIO,一个或者很少几个Socket线程就可以处理成千上万个活动的Socket连接。

通常情况下,通过ServerSocketChannel.open()获得一个ServerSocketChannel的实例,通过SocketChannel.open或者serverSocketChannel.accept()获得一个SocketChannel实例。要使ServerSocketChannel或者SocketChannel在非阻塞的模式下操作,可以调用
serverSocketChannel.configureBlocking (false);
或者
socketChannel.configureBlocking (false);

语句来达到目的。通常情况下,服务端可以使用非阻塞的ServerSocketChannel,这样,服务端的程序就可以更容易地同时处理多个socket线程。

下面我们来看一个综合例子,这个例子使用了ServerSocketChannel、SocketChannel开发了一个非阻塞的、能处理多线程的Echo服务端程序,见示例12-14。
【程序源代码】

1 // ==================== Program Discription =====================
2 // 程序名称:示例12-14 : SocketChannelDemo.java
3 // 程序目的:学习Java NIO#SocketChannel
4 // ==============================================================
5 
6 
7 import java.nio.ByteBuffer;
8 import java.nio.channels.ServerSocketChannel;
9 import java.nio.channels.SocketChannel;
10 import java.nio.channels.Selector;
11 import java.nio.channels.SelectionKey;
12 import java.nio.channels.SelectableChannel;
13 
14 import java.net.Socket;
15 import java.net.ServerSocket;
16 import java.net.InetSocketAddress;
17 import java.util.Iterator;
18
19 public class SocketChannelDemo
 
20 
21 {
22  public static int PORT_NUMBER = 23;//监听端口
23  ServerSocketChannel serverChannel;
24  ServerSocket serverSocket ;
25  Selector selector ;
26  private ByteBuffer buffer = ByteBuffer.allocateDirect (1024);
27 
28  public static void main (String [] args)
29   throws Exception
30  {
31   SocketChannelDemo server=new SocketChannelDemo();
32   server.init(args);
33   server.startWork();
34  }
35 
36 
37  public void init (String [] argv)throws Exception
38  {
39   int port = PORT_NUMBER;
40 
41   if (argv.length > 0) { 
42    port = Integer.parseInt (argv [0]);
43   }
44 
45   System.out.println ("Listening on port " + port);
46 
47   // 分配一个ServerSocketChannel
48   serverChannel = ServerSocketChannel.open();
49   // 从ServerSocketChannel里获得一个对应的Socket
50   serverSocket = serverChannel.socket();
51   // 生成一个Selector
52   selector = Selector.open();
53 
54   // 把Socket绑定到端口上
55   serverSocket.bind (new InetSocketAddress (port));
56   //serverChannel为非bolck
57   serverChannel.configureBlocking (false);
58 
59   // 通过Selector注册ServerSocetChannel
60   serverChannel.register (selector, SelectionKey.OP_ACCEPT); 
61   
62  }
63 
64     public void startWork()throws Exception
 
65 
66     {
67      while (true) {
68    
69    int n = selector.select();//获得IO准备就绪的channel数量
70 
71    if (n == 0) {
72     continue; // 没有channel准备就绪,继续执行
73    }
74 
75    // 用一个iterator返回Selector的selectedkeys
76    Iterator it = selector.selectedKeys().iterator();
77 
78    // 处理每一个SelectionKey
79    while (it.hasNext()) {
80     SelectionKey key = (SelectionKey) it.next();
81
82     // 判断是否有新的连接到达
83 if (key.isAcceptable()) {
84           //返回SelectionKey的ServerSocketChannel
85      ServerSocketChannel server =
(ServerSocketChannel) key.channel();
86      SocketChannel channel = server.accept();
87 
88      registerChannel (selector, channel,
89       SelectionKey.OP_READ);
90 
91      doWork (channel);
92     }
93 
94     // 判断是否有数据在此channel里需要读取
95     if (key.isReadable()) {
96        
97      processData (key);
98 
99     }
100 
101     //删除 selectedkeys
102     it.remove();
103    }
104   }
105  }
106  protected void registerChannel (Selector selector,
107   SelectableChannel channel, int ops)
108   throws Exception
109  {
 
110   if (channel == null) {
111    return;  
112   }
113 
114  
115   channel.configureBlocking (false);
116 
117   channel.register (selector, ops);
118  }
119 
120     //处理接收的数据
121  protected void processData (SelectionKey key)
122   throws Exception
123  {
124   
125  
126   SocketChannel socketChannel = (SocketChannel) key.channel();
127   int count;
128 
129   buffer.clear();   // 清空buffer
130 
131   // 读取所有的数据
132   while ((count = socketChannel.read (buffer)) > 0) {
133    buffer.flip();  
134
135    // send the data, don't assume it goes all at once
136    while (buffer.hasRemaining())
137    {
138     //如果收到回车键,则在返回的字符前增加[echo]$字样
139     if(buffer.get()==(char)13)
140     {
141      buffer.clear();
142      buffer.put("[echo]$".getBytes());
143      buffer.flip();
144      
145     }
146     socketChannel.write (buffer);//在Socket里写数据
147    }
148   
149    buffer.clear();  // 清空buffer
150   }
151 
152   if (count < 0) {
153    // count<0,说明已经读取完毕
154    socketChannel.close();
 
155   }
156  }
157 
158 
159  private void doWork (SocketChannel channel)throws Exception
160  {
161   buffer.clear();
162   buffer.put ("
Hello,I am working,please input some thing,and i will echo to you!
[echo] 
$".getBytes());
163   buffer.flip();
164   channel.write (buffer);
165  }
166 
167 }



使用:运行此程序,然后在控制台输入命令telnet localhost 23。

【程序输出结果】如图12-1所示。






图12-1 输出结果



【程序注解】
关于程序的解释已经包含在程序里面了,在这里我们总结以下使用ServerSocket Channel开发服务端程序的过程:
(1)分配一个ServerSocketChannel。
(2)从ServerSocketChannel里获得一个对应的ServerSocket。
(3)生成一个Selector实例。
(4)把ServerSocket绑定到端口上。
(5)设置ServerSocketChannel为非block模式(可选)。
(6)在Selector里注册ServerSocetChannel。
(7)用一个无限循环语句始终查看Selector里是否有IO准备就绪的channel。如果有,就执行对应的处理,如果没有,继续循环。

小 结

在本章我们主要介绍了Java中的网络编程。Java一开始就是一种网络编程语言,到后来才应用到各个方面,所以在Java中进行网络编程远比在C/C++中方便。

我们介绍了几个在网络编程中很重要的类,如InetAddress、URL、URLConnection、Socket、 ServerSocket、DatagramSocket、DatagramPacket、MulticastSocket等。这些类包含了进行基本网络编程的所有内容。要熟练地应用这些类,关键还是要多多练习。

基于套接字的编程基本上是客户/服务器模式,我们具体介绍了编写这种模式的步骤。在实例方面,我们给出了一个基于TCP的套接字客户/服务器程序,与此相对应,还给出了基于UDP的客户/服务器程序。两者的模式是很相似的,其实这也就是编写客户/服务器程序的一般模式。 (T111)

GT9XX驱动移植说明书_for_Android GT9XX驱动移植说明书_for_Android GT9XX驱动移植说明书_for_Android 立即下载

相关推荐

Cherry Studio部署MCP服务报错全记录:从零解决‘Connection closed‘问题

本文详细记录了在Cherry Studio中部署MCP服务时遇到‘Connection closed’报错的完整排查与解决过程。文章从环境依赖(UV、Bun)的安装验证、绝对路径配置、网络镜像源设置,到服务端手动调试与Cherry Studio配置检查,提供了一套系统性的解决方案,帮助开发者彻底解决此类连接问题。

g9h0i1的博客 764

实战css3画个机器猫后自己的得到

1、光影的运用,可用gradient来表示: radial-gradient(right top,#fff 75%,#eee 80%,#999 90%,#444);

ke3863834的博客 3282

KLayout教程(二)编辑不同的形状

首先画一个基础的矩形,然后双击他可以定义他的坐标

集成光电子 1万+

xingtai -神奇的二维码

from MyQR import myqr as mq mq.run("http://www.4399.com/", picture="cxk.gif", colorized=True, save_name = "lshdhvl.gif")

少儿编程侯老师的博客 2538

实战|验证码突破思路

漏洞成因:由于逻辑设计缺陷,可绕过验证,比如直接删除COOKIE或验证码参数可绕过、当验证不通过清空session时,验证码参数值为空时绕过等。测试方法:抓包,删除验证码字段,查看是否可以成功发送抓包,正常流程下,记录验证码后的数据包,替换目标包中内容,直接发送,查看是否可以直接绕过验证码案例:Step1.输入正确账户信息和错误验证码,登录时抓包Step2.删除COOKIEStep3.客户端登陆成功。

weixin_46239998的博客 8100

STM32CubeMX之DAC产成正弦波

“在之前的文章中曾经介绍过用TIM产生PWM做DAC用,STM32定时器输出PWM做DAC。部分型号的STM32单片机内部有专用的DAC,本篇文章将介绍如何用内部DAC+DMA产生正弦波...

zhang062061的专栏 1513

从想法到上线:基于快马平台快速开发并部署一个nixigixi实战项目

用户在前端输入一段较长的文本内容,并选择摘要的简洁程度(比如“精简”、“标准”、“详细”),点击提交后,后端会模拟一个智能摘要算法,对文本进行“nixigixi”处理(这里可以理解为分词、提取关键句、重组等逻辑),最后将生成的摘要返回给前端展示。,在创建项目的引导中,简单地描述了我的需求:“创建一个前后端分离的Web应用,前端有输入框和按钮,后端用Node.js提供API处理文本并返回结果”。我只需要点击项目页面的部署按钮,平台就会自动打包我的代码,配置好运行环境,并分配一个可公开访问的URL。

GoldenleafRaven13的博客 1002

【AIGC】Qwen3-Embedding:Embedding与Rerank模型新标杆

Qwen3-Embedding:文本嵌入与重排序模型的技术解析与应用实践

一个内容严谨、方向前沿、极具实践价值的AI大模型技术分享站 3094

Nginx 基本优化

一、一般来说nginx 配置文件中对优化比较有作用的为以下几项: 1. worker_processes 8; nginx 进程数,建议按照cpu 数目来指定,一般为它的倍数 (如,2个四核的cpu计为8)。 2. worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 100000...

石头 2623

QT实现警报应用程序

QT实现警报应用程序

希望我的博客,能帮上你解决学习中工作中所遇到的问题 2041

Python 爬虫实战:豆瓣电影海报批量获取(Top250 榜单 + 可视化展示)

在信息爆炸的时代,数据已成为决策的核心,而数据的获取是数据分析的第一步。本文将详细介绍如何利用 Python 爬虫获取豆瓣电影 Top250 榜单的海报,并对数据进行可视化展示,助你更好地了解电影市场的趋势和用户的喜好。

yansideyucsdn的博客 718

Netty系列之Netty 服务端创建

1. 背景 1.1. 原生NIO类库的复杂性 在开始本文之前,我先讲一件自己亲身经历的事:大约在2011年的时候,周边的两个业务团队同时进行新版本开发,他们都需要基于NIO非阻塞特性构建高性能、异步和高可靠性的底层通信框架。 当时两个项目组的设计师都咨询了我的意见,在了解了两个项目团队的NIO编程经验和现状之后,我建议他们都使用Netty构建业务通信框架。令人遗憾的是其中1个项目组并没有按照

stay hungry,stay foolish ! 598

【文献阅读】使用深度语音后验改进独立于说话者的构音障碍可懂度分类

原文名称:本文探讨了利用DeepSpeech后验概率改进说话人无关的构音障碍可理解性分类方法。作者提出了一个基于DeepSpeech(一种端到端的语音转文本引擎)输出的新特征集,用于评估构音障碍患者的语音可理解性。这些新特征在说话人无关的情况下表现良好,能够更好地处理不同说话人的变异性。背景介绍:数据集:特征提取:实验设置:结果:本文提出的新特征集在说话人无关的构音障碍可理解性分类任务中表现出色,特别是在低可理解性和高可理解性类别上。未来的工作将集中在减少低可理解性和中可理解性类别之间的混淆,以进一步提高系

帅小柏的博客 452

分别基于IO、NIO、Netty的Java网络程序(Client/Server)

文章目录一、IO实现1. IO介绍1.1 传送IO特点1.2 原理流程图2. 代码3. 运行结果二、NIO实现1. NIO介绍1.1 NIO特点1.2 原理流程图1.3 NIO对比IO1.4 使用NIO遇到的一些问题2. 代码3. 运行结果三、Netty实现1. Netty介绍1.1 Netty特点2. 代码3.运行结果四、参考 一、IO实现 1. IO介绍 1.1 传送IO特点 1.服务端阻塞点 server.accept();获取套接字的时候 inputStream.read(bytes);输入流读取

伊木子曦的博客 832

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

Java NIO原理和使用

Java NIO原理和使用 板桥里人 2002/11/01 jdon.com Java NIO非堵塞应用通常适用用在I/O读写等方面,我们知道,系统运行的性能瓶颈通常在I/O读写,包括对端口和文件的操作上,过去,在打开一个I/O通道后,read()将一直等待在端口一边读取字节内容,如果没有内容进来,read()也是傻傻的等,这会影响我们程序继续做其他事情,那么改进做法就是开设线程,让线

whereismatrix的专栏 901

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

最新Java培训-NIO实战教程

  Java NIO(New IO)是一个可以替代标准Java IO API的IO API(从Java 1.4开始),Java NIO提供了与标准IO不同的IO工作方式。NIO可以理解为非阻塞IO,传统的IO的read和write只能阻塞执行,线程在读写IO期间不能干其他事情,比如调用socket.read()时,如果服务器一直没有数据传输过来,线程就一直阻塞,而NIO中可以配置socket为非阻塞模式。   Java NIO是在jdk1.4开始使用的,它既可以说成“新I/O”,也可以说成非阻塞式I/O。

qinge_Crazy的博客 270

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

NIO Socket非阻塞模式代码示例

jdk供的无阻塞I/O(NIO)有效解决了多线程服务器存在的线程开销问题,但在使用上略显得复杂一些。在NIO中使用多线程,主要目的已不是为了应对每个客户端请求而分配独立的服务线程,而是通过多线程充分使用用多个CPU的处理能力和处理中的等待时间,达到提高服务能力的目的。 从最简单的Hello World开始,client多线程请求server端,server接收client的名字,并返回Hello!...

modabobo 140

Day858.高性能网络应用框架Netty -Java 并发编程实战

Netty是一个款优秀的网络编程框架,性能非常好,为了实现高性能的目标,Netty 做了很多优化,例如优化了 ByteBuffer、支持零拷贝等等,和并发编程相关的就是它的线程模型了。Netty 的线程模型设计得很精巧,每个网络连接都关联到了一个线程上,这样做的好处是:对于一个网络连接,读写操作都是单线程执行的,从而避免了并发程序的各种问题。要想深入理解 Netty 的线程模型,还需要对网络相关知识有一定的理解,关于 Java IO 的演进过程,可以参考。

阿昌爱Java 892

JAVA NIO详解

1. IO 和 NIO 相关的预备知识 1.1 IO 的含义 讲 NIO 之前,我们先来看一下 IO。 Java IO 即 Java 输入输出。在开发应用软件时,很多时候都需要和各种输入输出相关的媒介打交道。与媒介进行 IO 操作的过程十分复杂,需要考虑众多因素,比如:进行 IO 操作媒介的类型(文件、控制台、网络)、通信方式(顺序、随机、二进制、按字符、按字、按行等等)。 Java 类库提供了相...

努力奔跑 2万+
上一篇: UDP套接字
下一篇: Jquery tab 选项卡 无刷新切换[带演示]
piperzero
博客等级 码龄21年 1377粉丝 504原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值