服务热线:13616026886

技术文档 欢迎使用技术文档,我们为你提供从新手到专业开发者的所有资源,你也可以通过它日益精进

位置:首页 > 技术文档 > JAVA > 新手入门 > 基础入门 > 查看文档

使用java nio提高服务端程序的性能

结合具体的java socket编程,讨论使用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]___fckpd___0quot;.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] 
___fckpd___0quot;.getbytes());
163 buffer.flip();
164 channel.write (buffer);
165 }
166 
167 }

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

扫描关注微信公众号