Skip to content

Commit 68cc444

Browse files
committed
nio
1 parent 29927f0 commit 68cc444

29 files changed

Lines changed: 3181 additions & 2 deletions

dom4j.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<?xml version="1.0" encoding="UTF-8" ?>
22
<dom4j>
33
<name littleName="属性值">dom4j模板</name>
4+
<age littleName="20">20</age>
45
</dom4j>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.yale.test.io.nio;
2+
3+
import java.io.IOException;
4+
5+
public class AClient {
6+
7+
public static void main(String[] args) throws IOException {
8+
new NioClient().start("AClient");
9+
}
10+
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.yale.test.io.nio;
2+
3+
import java.io.IOException;
4+
5+
public class BClient {
6+
7+
public static void main(String[] args) throws IOException {
8+
new NioClient().start("BClient");
9+
}
10+
11+
}
241 KB
Loading
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.yale.test.io.nio;
2+
3+
import java.io.IOException;
4+
5+
public class CClient {
6+
7+
public static void main(String[] args) throws IOException {
8+
new NioClient().start("CClient");
9+
}
10+
}
241 KB
Loading
204 KB
Loading
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.yale.test.io.nio;
2+
3+
import java.io.IOException;
4+
import java.net.InetSocketAddress;
5+
import java.nio.channels.SelectionKey;
6+
import java.nio.channels.Selector;
7+
import java.nio.channels.SocketChannel;
8+
import java.nio.charset.Charset;
9+
import java.util.Scanner;
10+
11+
public class NioClient {
12+
public void start(String nickName) throws IOException {
13+
//连接服务器端
14+
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8000));
15+
//新开线程,专门负责来接收服务器端的响应数据
16+
Selector selector = Selector.open();
17+
socketChannel.configureBlocking(false);//设置为非阻塞模式
18+
//将socketChannel注册到selector上面,监听selector的可读事件
19+
socketChannel.register(selector, SelectionKey.OP_READ);
20+
new Thread(new NioClientHandler(selector)).start();//新开线程
21+
22+
Scanner scanner = new Scanner(System.in);
23+
//向服务器端发送数据
24+
while (scanner.hasNextLine()) {
25+
String request = scanner.nextLine();
26+
if (request != null && request.length() > 0) {
27+
socketChannel.write(Charset.forName("UTF-8").encode(nickName + ":" +request));
28+
29+
}
30+
}
31+
}
32+
33+
public static void main(String[] args) throws IOException {
34+
//new NioClient().start();
35+
}
36+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package com.yale.test.io.nio;
2+
3+
import java.io.IOException;
4+
import java.nio.ByteBuffer;
5+
import java.nio.channels.SelectionKey;
6+
import java.nio.channels.Selector;
7+
import java.nio.channels.SocketChannel;
8+
import java.nio.charset.Charset;
9+
import java.util.Iterator;
10+
import java.util.Set;
11+
12+
public class NioClientHandler implements Runnable{
13+
14+
private Selector selector;
15+
public NioClientHandler(Selector selector) {
16+
this.selector = selector;
17+
}
18+
19+
@Override
20+
public void run() {
21+
try {
22+
for (;;) {//相当于while(true)循环,for;;JVM会优化成一条语句,while(true)会优化成3条语句,JAVA源码很多都是for;;
23+
/**
24+
* 获取可用的Channel数量
25+
*/
26+
int readyChannels = selector.select();
27+
if (readyChannels == 0) {
28+
continue;
29+
}
30+
31+
Set<SelectionKey> selectorKeys = selector.selectedKeys();
32+
Iterator iterator = selectorKeys.iterator();
33+
while(iterator.hasNext()) {
34+
//获取SelectionKey实例
35+
SelectionKey selectionKey = (SelectionKey)iterator.next();
36+
//移除Set中的当前SelectionKey
37+
iterator.remove();
38+
//可读事件,根据就绪状态,调用对应的方法处理业务逻辑
39+
if (selectionKey.isReadable()) {
40+
readHandler(selectionKey, selector);
41+
}
42+
}
43+
}
44+
} catch (IOException e) {
45+
e.printStackTrace();
46+
}
47+
}
48+
49+
//可读事件处理
50+
private void readHandler(SelectionKey selectionKey, Selector selector) throws IOException {
51+
//要从selectionKey中获取到已经就绪的channel
52+
SocketChannel socketChannel = (SocketChannel)selectionKey.channel();
53+
//创建Buffer
54+
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
55+
//循环读取服务器端的响应信息
56+
String response = "";
57+
while (socketChannel.read(byteBuffer) > 0) {
58+
byteBuffer.flip();//切换到读模式
59+
response += Charset.forName("UTF-8").decode(byteBuffer);
60+
}
61+
//将channel再次注册到Selector上,监听他的可读事件
62+
socketChannel.register(selector, SelectionKey.OP_READ);
63+
if (response.length() > 0) {//将服务器端响应信息打印到本地
64+
System.out.println(response);
65+
}
66+
}
67+
68+
}

src/com/yale/test/io/nio/NioServer.java

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,23 @@
22

33
import java.io.IOException;
44
import java.net.InetSocketAddress;
5+
import java.nio.ByteBuffer;
6+
import java.nio.channels.Channel;
57
import java.nio.channels.SelectionKey;
68
import java.nio.channels.Selector;
79
import java.nio.channels.ServerSocketChannel;
10+
import java.nio.channels.SocketChannel;
11+
import java.nio.charset.Charset;
812
import java.util.Iterator;
913
import java.util.Set;
1014

1115
/**
1216
* NIO服务器
1317
* NIO Non Blocking io非阻塞IO JDK1.4有的
18+
* NIO网络编程缺陷
19+
* 麻烦:NIO类库和API繁杂
20+
* 心累:可靠性能力补齐,工作量和难度都非常大
21+
* 有坑:Selector空轮询,导致CPU100%
1422
* @author dell
1523
*/
1624
public class NioServer {
@@ -36,6 +44,12 @@ public void start() throws IOException {
3644
*/
3745
int readyChannels = selector.select();
3846
if (readyChannels == 0) {
47+
/**
48+
* 这里有坑:Selector空轮询,导致CPU100%
49+
* 主要出现在类Unix上面,这个问题java官方声称在jdk1.6的版本中已经修复,
50+
* 但实际证明该问题在jdk1.8上面依然存在,只不过发生的概率低了一些.
51+
* 如果要在Linux上面使用,要非常小心,最好不用,老师没说替代办法
52+
*/
3953
continue;
4054
}
4155

@@ -47,9 +61,67 @@ public void start() throws IOException {
4761
//移除Set中的当前SelectionKey
4862
iterator.remove();
4963
//接入事件,根据就绪状态,调用对应的方法处理业务逻辑
50-
64+
if (selectionKey.isAcceptable()) {
65+
acceptHandler(serverSocketChannel, selector);
66+
}
5167
//可读事件,根据就绪状态,调用对应的方法处理业务逻辑
68+
if (selectionKey.isReadable()) {
69+
readHandler(selectionKey, selector);
70+
}
5271
}
5372
}
5473
}
74+
75+
//接入事件处理
76+
private void acceptHandler(ServerSocketChannel serverSocketChannel, Selector selector) throws IOException {
77+
//如果是接入事件,创建SocketChannel
78+
SocketChannel socketChannel = serverSocketChannel.accept();
79+
socketChannel.configureBlocking(false);//将socketChannel设置为非阻塞工作模式
80+
//将channel注册到selector上,监听可读事件
81+
socketChannel.register(selector, SelectionKey.OP_READ);
82+
//回复客户端提示信息
83+
socketChannel.write(Charset.forName("UTF-8").encode("你与聊天室里其他人不是朋友关系,请注意隐私安全"));
84+
}
85+
86+
//可读事件处理
87+
private void readHandler(SelectionKey selectionKey, Selector selector) throws IOException {
88+
//要从selectionKey中获取到已经就绪的channel
89+
SocketChannel socketChannel = (SocketChannel)selectionKey.channel();
90+
//创建Buffer
91+
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
92+
//循环读取客户端的请求信息
93+
String request = "";
94+
while (socketChannel.read(byteBuffer) > 0) {
95+
byteBuffer.flip();//切换到读模式
96+
request += Charset.forName("UTF-8").decode(byteBuffer);
97+
}
98+
//将channel再次注册到Selector上,监听他的可读事件
99+
socketChannel.register(selector, SelectionKey.OP_READ);
100+
if (request.length() > 0) {//将客户端发送的请求消息光博给其他客户端
101+
System.out.println(":::" + request);
102+
broadCast(selector, socketChannel, request);
103+
}
104+
}
105+
//广播给其他所有客户端
106+
private void broadCast(Selector selector, SocketChannel sourceChannel, String request) {
107+
//获取到所有已接入的客户端channel
108+
Set<SelectionKey> selectionKeySet = selector.keys();
109+
//
110+
selectionKeySet.forEach(selectionKey ->{//循环向所有channel广播信息
111+
Channel targetChannel = selectionKey.channel();
112+
//删除发送消息的客户端
113+
if (targetChannel instanceof SocketChannel && targetChannel != sourceChannel) {
114+
try {//将消息发送到targetChannel客户端
115+
((SocketChannel)targetChannel).write(Charset.forName("UTF-8").encode(request));
116+
} catch (IOException e) {
117+
e.printStackTrace();
118+
}
119+
}
120+
});
121+
}
122+
123+
public static void main(String[] args) throws IOException {
124+
NioServer nioServer = new NioServer();
125+
nioServer.start();
126+
}
55127
}

0 commit comments

Comments
 (0)