【注意】最后更新于 December 20, 2015,文中内容可能已过时,请谨慎使用。
前某个星期用java的阻塞式io写了一个socket的程序后,感觉用来玩玩还可以,连接量一上来就完了。
然后又看到推荐说nio,就一直想着学学,结果中间这几天考试复习给耽搁了。正好今天没什么考试了,就找时间学了学。
nio网上讲的也挺多的了,我也没必要班门弄斧,就是说说自己的理解吧。
在nio中比较重要的是channel、buffer以及selector这几个东西。
channel跟io的流有点相似,buffer就是缓存区了。selector就是异步用的了。
借用一个人的神总结,
>Channel对应以前的流,Buffer不是什么新东西,Selector是因为nio可以使用异步的非堵塞模式才加入的东西。
以前的流总是堵塞的,一个线程只要对它进行操作,其它操作就会被堵塞,也就相当于水管没有阀门,你伸手接水的时候,不管水到了没有,你就都只能耗在接水(流)上。
nio的Channel的加入,相当于增加了水龙头(有阀门),虽然一个时刻也只能接一个水管的水,但依赖轮换策略,在水量不大的时候,各个水管里流出来的水,都可以得到妥善接纳,这个关键之处就是增加了一个接水工,也就是Selector,他负责协调,也就是看哪根水管有水了的话,在当前水管的水接到一定程度的时候,就切换一下:临时关上当前水龙头,试着打开另一个水龙头(看看有没有水)。
当其他人需要用水的时候,不是直接去接水,而是事前提了一个水桶给接水工,这个水桶就是Buffer。也就是,其他人虽然也可能要等,但不会在现场等,而是回家等,可以做其它事去,水接满了,接水工会通知他们。
这其实也是非常接近当前社会分工细化的现实,也是统分利用现有资源达到并发效果的一种很经济的手段,而不是动不动就来个并行处理,虽然那样是最简单的,但也是最浪费资源的方式。
相对于网上讲其他的复杂的解释这个更容易理解一点。
继续套用那个例子的话,阻塞式io就是相当于如果多个水龙头来水(多个用户加入),就得多请几个节水工(开多个线程),这就导致花销大啦(系统多开资源)。
具体的关于程序的编写也不再多说啦。我也是看的一知半解的。
还是有问题存在。比如
客户端要发送多个数据的话或者是服务器要一直接受的话,就处理不了,只能一接一发。
这个仍然没想到解决方法。或许是逻辑哪出问题了吧。
直接上程序吧.这个是服务器端的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
package top.txiner.nio;
import java.io.*;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
/**
* Created by hundred on 2015/12/20.
*/
public class ServerNIO {
public static final InetSocketAddress ADDRESS = new InetSocketAddress(8080);
public Selector selector = null;
static int BLOCK = 1024;
private ByteBuffer receiveBuffer = ByteBuffer.allocate(BLOCK);
private ByteBuffer sendBuffer = ByteBuffer.allocate(BLOCK);
public ServerNIO() {
try {
ServerSocketChannel channel = null;
channel = ServerSocketChannel.open();
channel.configureBlocking(false);
ServerSocket serverSocket = channel.socket();
serverSocket.bind(ADDRESS);
selector = Selector.open();
channel.register(selector, SelectionKey.OP_ACCEPT);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
ServerNIO serverNIO = new ServerNIO();
serverNIO.listen();
}
private void listen() {
Iterator iter = null;
while (true) {
try {
selector.select();
iter = selector.selectedKeys().iterator();
while (iter.hasNext()) {
SelectionKey key = (SelectionKey) iter.next();
iter.remove();
handle(key);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void handle(SelectionKey key) {
String receiveText;
String sendText;
int count = 0;
SocketChannel channel = null;
if (key.isAcceptable()) {
try {
ServerSocketChannel serverSocketChannel =
(ServerSocketChannel) key.channel();
channel = serverSocketChannel.accept();
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_READ);
} catch (IOException e) {
e.printStackTrace();
}
} else if (key.isReadable()) {
try {
channel = (SocketChannel) key.channel();
receiveBuffer.clear();
count = channel.read(receiveBuffer);
if (count > 0) {
receiveText = new String(receiveBuffer.array(), 0, count);
System.out.println("data from client: " + receiveText);
channel.register(selector, SelectionKey.OP_WRITE);
}
} catch (IOException e) {
e.printStackTrace();
}
} else if (key.isWritable()) {
try {
sendBuffer.clear();
channel = (SocketChannel) key.channel();
BufferedReader br = new BufferedReader(new InputStreamReader
(System.in));
sendText = br.readLine();
sendBuffer.put(sendText.getBytes());
sendBuffer.flip();
channel.write(sendBuffer);
channel.register(selector, SelectionKey.OP_READ);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
|
这个是客户端的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
package top.txiner.nio;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
/**
* Created by hundred on 2015/12/20.
*/
public class ClientNIO {
public Selector selector = null;
static int BLOCK = 1024;
public int ID = 0;
private ByteBuffer receiveBuffer = ByteBuffer.allocate(BLOCK);
private ByteBuffer sendBuffer = ByteBuffer.allocate(BLOCK);
public static final InetSocketAddress ADDRESS = new InetSocketAddress
("localhost", 8080);
public ClientNIO() {
try {
SocketChannel channel = SocketChannel.open();
channel.configureBlocking(false);
channel.connect(ADDRESS);
selector = Selector.open();
channel.register(selector, SelectionKey.OP_CONNECT);
ID = (int) (Math.random() * 10);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
ClientNIO clientNIO = new ClientNIO();
clientNIO.send();
}
private void send() {
int count = 0;
SelectionKey key = null;
SocketChannel channel = null;
String noticeMsg = "connect with you now.I am the " + ID;
String receiveText;
String sendText;
while (true) {
try {
selector.select();
Iterator iter = selector.selectedKeys().iterator();
while (iter.hasNext()) {
key = (SelectionKey) iter.next();
if (key.isConnectable()) {
System.out.println("connect to server");
channel = (SocketChannel) key.channel();
if (channel.isConnectionPending()) {
channel.finishConnect();
sendBuffer.clear();
sendBuffer.put(noticeMsg.getBytes());
sendBuffer.flip();
channel.write(sendBuffer);
}
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) {
channel = (SocketChannel) key.channel();
receiveBuffer.clear();
count = channel.read(receiveBuffer);
if (count > 0) {
receiveText = new String(receiveBuffer.array(),
0, count);
System.out.println("data from server: " +
receiveText);
channel.register(selector, SelectionKey.OP_WRITE);
}
} else if (key.isWritable()) {
channel = (SocketChannel) key.channel();
sendBuffer.clear();
BufferedReader br = new BufferedReader(new
InputStreamReader(System.in));
sendText = br.readLine();
sendBuffer.put(sendText.getBytes());
sendBuffer.flip();
channel.write(sendBuffer);
channel.register(selector, SelectionKey.OP_READ);
}
}
selector.selectedKeys().clear();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
|
在学nio的时候参考太多了,也没记录,就不付具体参考的了。
如果以后能改得了上面那个问题就再改程序。
数字信号处理考试好难,好多都不会做,没心情在往下瞎编了。