Selector的运行机制是什么,它是如何确定一个通道是可以“写”还是“读”,在“写”状态发生时不可以“读”吗,或者在“读”状态时不可以“写”吗?
这是书上一个例子,可以先运行类,然后在浏览器中输入:http://127.0.0.1:19即可以看到效果,想停止的话,关闭浏览器就行了,它没有自动关闭的功能。程序的作用是向客户端不停地写入一大堆字符串
package test;
import java.nio.*;
import java.nio.channels.*;
import java.net.*;
import java.util.*;
import java.io.IOException;public class ChargenServer {
public static int DEFAULT_PORT = 19;
public static void main(String[] args) {
int port;
try {
port = Integer.parseInt(args[0]);
}
catch (Exception ex) {
port = DEFAULT_PORT;
}
System.out.println("Listening for connections on port " + port); byte[] rotation = new byte[95*2];//建立一个数据数组,空格到“~”正好是95个字符,这个数组存储了2次数据从0--94一次,从95--189一次
for (byte i = ' '; i <= '~'; i++) {
rotation[i-' '] = i;
rotation[i+95-' '] = i;
}
ServerSocketChannel serverChannel;
Selector selector;
try {
serverChannel = ServerSocketChannel.open();
ServerSocket ss = serverChannel.socket();
InetSocketAddress address = new InetSocketAddress(port);
ss.bind(address);
serverChannel.configureBlocking(false);
selector = Selector.open();
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
}
catch (IOException ex) {
ex.printStackTrace();
return;
}
while (true) {
try {
selector.select();
}
catch (IOException ex) {
ex.printStackTrace();
break;
}
Set readyKeys = selector.selectedKeys();
Iterator iterator = readyKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = (SelectionKey) iterator.next();
iterator.remove();
try {
if (key.isAcceptable()) {
ServerSocketChannel server = (ServerSocketChannel) key.channel();
SocketChannel client = server.accept();
System.out.println("Accepted connection from " + client);
client.configureBlocking(false);
SelectionKey key2 = client.register(selector, SelectionKey.OP_WRITE);
ByteBuffer buffer = ByteBuffer.allocate(74);
buffer.put(rotation, 0, 72);
buffer.put((byte) '\r');
buffer.put((byte) '\n');
buffer.flip();
key2.attach(buffer);
}
else if (key.isWritable()) {
SocketChannel client = (SocketChannel) key.channel();
ByteBuffer buffer = (ByteBuffer) key.attachment();
if (!buffer.hasRemaining()) {
// Refill the buffer with the next line
buffer.rewind();
// Get the old first character
int first = buffer.get();
// Get ready to change the data in the buffer
buffer.rewind();
// Find the new first characters position in rotation
int position = first - ' ' + 1;
// copy the data from rotation into the buffer
buffer.put(rotation, position, 72);
// Store a line break at the end of the buffer
buffer.put((byte) '\r');
buffer.put((byte) '\n');
// Prepare the buffer for writing
buffer.flip();
}
client.write(buffer);
}
}
catch (IOException ex) {
key.cancel();
try {
key.channel().close();
}
catch (IOException cex) {}
}
}
}
}
}
针对这个代码,有一些疑问,一是在key.isAcceptable()语句里,不能直接向客户端写入数据吗,非得在key.isWritable()里面做,key.isWritable()意味着什么?向客户端写入?向客户端写入也会成为一个事件?
这是书上一个例子,可以先运行类,然后在浏览器中输入:http://127.0.0.1:19即可以看到效果,想停止的话,关闭浏览器就行了,它没有自动关闭的功能。程序的作用是向客户端不停地写入一大堆字符串
package test;
import java.nio.*;
import java.nio.channels.*;
import java.net.*;
import java.util.*;
import java.io.IOException;public class ChargenServer {
public static int DEFAULT_PORT = 19;
public static void main(String[] args) {
int port;
try {
port = Integer.parseInt(args[0]);
}
catch (Exception ex) {
port = DEFAULT_PORT;
}
System.out.println("Listening for connections on port " + port); byte[] rotation = new byte[95*2];//建立一个数据数组,空格到“~”正好是95个字符,这个数组存储了2次数据从0--94一次,从95--189一次
for (byte i = ' '; i <= '~'; i++) {
rotation[i-' '] = i;
rotation[i+95-' '] = i;
}
ServerSocketChannel serverChannel;
Selector selector;
try {
serverChannel = ServerSocketChannel.open();
ServerSocket ss = serverChannel.socket();
InetSocketAddress address = new InetSocketAddress(port);
ss.bind(address);
serverChannel.configureBlocking(false);
selector = Selector.open();
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
}
catch (IOException ex) {
ex.printStackTrace();
return;
}
while (true) {
try {
selector.select();
}
catch (IOException ex) {
ex.printStackTrace();
break;
}
Set readyKeys = selector.selectedKeys();
Iterator iterator = readyKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = (SelectionKey) iterator.next();
iterator.remove();
try {
if (key.isAcceptable()) {
ServerSocketChannel server = (ServerSocketChannel) key.channel();
SocketChannel client = server.accept();
System.out.println("Accepted connection from " + client);
client.configureBlocking(false);
SelectionKey key2 = client.register(selector, SelectionKey.OP_WRITE);
ByteBuffer buffer = ByteBuffer.allocate(74);
buffer.put(rotation, 0, 72);
buffer.put((byte) '\r');
buffer.put((byte) '\n');
buffer.flip();
key2.attach(buffer);
}
else if (key.isWritable()) {
SocketChannel client = (SocketChannel) key.channel();
ByteBuffer buffer = (ByteBuffer) key.attachment();
if (!buffer.hasRemaining()) {
// Refill the buffer with the next line
buffer.rewind();
// Get the old first character
int first = buffer.get();
// Get ready to change the data in the buffer
buffer.rewind();
// Find the new first characters position in rotation
int position = first - ' ' + 1;
// copy the data from rotation into the buffer
buffer.put(rotation, position, 72);
// Store a line break at the end of the buffer
buffer.put((byte) '\r');
buffer.put((byte) '\n');
// Prepare the buffer for writing
buffer.flip();
}
client.write(buffer);
}
}
catch (IOException ex) {
key.cancel();
try {
key.channel().close();
}
catch (IOException cex) {}
}
}
}
}
}
针对这个代码,有一些疑问,一是在key.isAcceptable()语句里,不能直接向客户端写入数据吗,非得在key.isWritable()里面做,key.isWritable()意味着什么?向客户端写入?向客户端写入也会成为一个事件?
解决方案 »
免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货