Java网络教程 - Java非阻塞套接字
使用非阻塞套接字通道,我们必须改变我们对执行顺序的思考方式。
服务器套接字通道
要创建选择器对象,请调用其open()静态方法。Selector selector = Selector.open();
ServerSocketChannel用于监听来自客户端的新连接请求。
调用其open()静态方法来创建一个ServerSocketChannel。ServerSocketChannel ssChannel = ServerSocketChannel.open();
默认情况下,服务器套接字通道或套接字通道是阻塞通道。要使其成为非阻塞通道,请调用以下方法。ssChannel.configureBlocking(false);
选择器
服务器套接字必须向选择器注册才能执行某些操作。
有四种操作,我们可以用选择器注册一个通道。使用SelectionKey.OP_CONNECT连接操作,可以在客户端为SocketChannel注册。选择器将通知有关连接操作进度。
使用SelectionKey.OP_ACCEPT接受操作,可以在服务器上为ServerSocketChannel注册。当客户端请求新连接到达时,选择器将通知。
使用SelectionKey.OP_READ读取操作,可以在客户端和服务器上为SocketChannel注册。选择器将在通道准备好读取某些数据时通知。
使用SelectionKey.OP_WRITE进行写操作,可以在客户端和服务器上为SocketChannel注册。选择器将在通道准备好写入某些数据时通知。
例子
以下代码显示如何创建非阻塞套接字通道回显服务器程序。import java.net.InetAddress;
import java.net.InetSocketAddress;
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;
import java.util.Set;
public class Main {
public static void main(String[] args) throws Exception {
InetAddress hostIPAddress = InetAddress.getByName("localhost");
int port = 19000;
Selector selector = Selector.open();
ServerSocketChannel ssChannel = ServerSocketChannel.open();
ssChannel.configureBlocking(false);
ssChannel.socket().bind(new InetSocketAddress(hostIPAddress, port));
ssChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
if (selector.select() <= 0) {
continue;
}
processReadySet(selector.selectedKeys());
}
}
public static void processReadySet(Set readySet) throws Exception {
Iterator iterator = readySet.iterator();
while (iterator.hasNext()) {
SelectionKey key = (SelectionKey) iterator.next();
iterator.remove();
if (key.isAcceptable()) {
ServerSocketChannel ssChannel = (ServerSocketChannel) key.channel();
SocketChannel sChannel = (SocketChannel) ssChannel.accept();
sChannel.configureBlocking(false);
sChannel.register(key.selector(), SelectionKey.OP_READ);
}
if (key.isReadable()) {
String msg = processRead(key);
if (msg.length() > 0) {
SocketChannel sChannel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes());
sChannel.write(buffer);
}
}
}
}
public static String processRead(SelectionKey key) throws Exception {
SocketChannel sChannel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int bytesCount = sChannel.read(buffer);
if (bytesCount > 0) {
buffer.flip();
return new String(buffer.array());
}
return "NoMessage";
}
}
例2
非阻塞套接字通道回显客户端程序import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.Iterator;
import java.util.Set;
/*fromwww.w3cschool.cn*/
public class Main {
static BufferedReader userInputReader = null;
public static boolean processReadySet(Set readySet) throws Exception {
Iterator iterator = readySet.iterator();
while (iterator.hasNext()) {
SelectionKey key = (SelectionKey)
iterator.next();
iterator.remove();
if (key.isConnectable()) {
boolean connected = processConnect(key);
if (!connected) {
return true; // Exit }
}
if (key.isReadable()) {
String msg = processRead(key);
System.out.println("[Server]: " + msg);
}
if (key.isWritable()) {
System.out.print("Please enter a message(Bye to quit):");
String msg = userInputReader.readLine();
if (msg.equalsIgnoreCase("bye")) {
return true; // Exit }
SocketChannel sChannel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes());
sChannel.write(buffer);
}
}
return false; // Not done yet }
public static boolean processConnect(SelectionKey key) throws Exception{
SocketChannel channel = (SocketChannel) key.channel();
while (channel.isConnectionPending()) {
channel.finishConnect();
}
return true;
}
public static String processRead(SelectionKey key) throws Exception {
SocketChannel sChannel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
sChannel.read(buffer);
buffer.flip();
Charset charset = Charset.forName("UTF-8");
CharsetDecoder decoder = charset.newDecoder();
CharBuffer charBuffer = decoder.decode(buffer);
String msg = charBuffer.toString();
return msg;
}
public static void main(String[] args) throws Exception {
InetAddress serverIPAddress = InetAddress.getByName("localhost");
int port = 19000;
InetSocketAddress serverAddress = new InetSocketAddress(
serverIPAddress, port);
Selector selector = Selector.open();
SocketChannel channel = SocketChannel.open();
channel.configureBlocking(false);
channel.connect(serverAddress);
int operations = SelectionKey.OP_CONNECT | SelectionKey.OP_READ
| SelectionKey.OP_WRITE;
channel.register(selector, operations);
userInputReader = new BufferedReader(new InputStreamReader(System.in));
while (true) {
if (selector.select() > 0) {
boolean doneStatus = processReadySet(selector.selectedKeys());
if (doneStatus) {
break;
}
}
}
channel.close();
}
}