📄 selectdemo.java
字号:
/*
* Created on 2005-3-14
*
* TODO To change the template for this generated file go to
* Window - Preferences - Java - Code Style - Code Templates
*/
package package1;
import java.io.*;
import java.net.*;
import java.util.*;
import java.nio.*;
import java.nio.channels.*;
public final class SelectDemo {
//定义服务器类EchoSerer
public static class EchoServer {
private int port; //服务器使用的端口号
private ServerSocketChannel channel;
private LinkedList clients;
private Selector readSelector;
private ByteBuffer buffer;
public EchoServer(int port) throws IOException
{
this.port = port;
clients = new LinkedList();
channel = null;
readSelector = Selector.open(); // 打开一个选择器
buffer = ByteBuffer.allocate(1024);
}
// 服务器程序在服务循环中调用sericeClients()方法为已接受的客户服务
public void serviceClients() throws IOException
{
Set keys;
Iterator it;
SelectionKey key;
SocketChannel client;
// 在readSelector上调用select()方法,参数1代表如果调用select的时候
// 那么阻塞最多1秒钟等待可用的客户端连接
if(readSelector.select(1) > 0) {
keys = readSelector.selectedKeys(); // 取得代表端通道的键集合
it = keys.iterator();
// 遍历,为每一个客户服务
while(it.hasNext()) {
key = (SelectionKey)it.next();
if(key.isReadable()) { // 如果通道可读,那么读此通道到buffer中
int bytes;
client = (SocketChannel)key.channel(); 取得键对应的通道
buffer.clear(); // 清空缓冲区中的内容,设置好position,limit,准备接受数据
bytes = client.read(buffer); // 从通道中读数据到缓冲中,返回读取得字节数
if(bytes >= 0) {
buffer.flip(); // 准备将缓冲中的数据写回到通道中
client.write(buffer); // 数据写回到通道中
}
else if(bytes < 0) { // 如果返回小于零的值代表读到了流的末尾
clients.remove(client);
// 通道关闭时,选择键也被取消
client.close();
}
}
}
}
}
// 配置和注册代表客户连接的通道对象
public void registerClient(SocketChannel client) throws IOException
{
client.configureBlocking(false); // 设置此通道使用非阻塞模式
client.register(readSelector, SelectionKey.OP_READ); // 将这个通道注册到选择器上
clients.add(client); //保存这个通道对象
}
//调用这个方法,开始监听并接收客户端请求
public void listen() throws IOException {
ServerSocket socket;
SocketChannel client;
channel = ServerSocketChannel.open(); // 打开通道
socket = channel.socket(); //得到与通到相关的socket对象
socket.bind(new InetSocketAddress(port), 10); //将scoket榜定在制定的端口上
//配置通到使用非阻塞模式,在非阻塞模式下,
//可以编写多道程序同时避免使用复杂的多线程
channel.configureBlocking(false);
try {
while(true) {
// 与通常的程序不同,这里使用channel.accpet()接受客户端连接请求,
// 而不是在socket对象上调用accept()
// 这里在调用accept()方法时如果通道配置为非阻塞模式,,
// 那么accept()方法立即返回null,并不阻塞
client = channel.accept();
if(client != null)
registerClient(client); // 注册客户信息
serviceClients(); // 为以连接的客户服务
}
} finally {
socket.close(); // 关闭socket,关闭socket会同时关闭与此socket关联的通道
}
}
}
// 主程序类
public static class Main {
//打印使用帮助信息的方法
public static void usage(String prog) {
System.err.println("usage: " + prog + " port");
}
//方法run,程序代码的主体
public void run(String args[])
throws IllegalArgumentException, NumberFormatException
{
EchoServer server;
if(args.length < 1)
throw new IllegalArgumentException();
try {
//创建服务器类,将程序的命令行参数中的第一个参数解释为整数,
//这个数作为服务器提供服务的端口号
server = new EchoServer(Integer.parseInt(args[0]));
//服务器开始监听端口,提供服务
server.listen();
} catch(IOException ioe) {
ioe.printStackTrace();
return;
}
}
}
public static final void main(String args[]) {
try {
new Main().run(args);
} catch(Exception e) {
Main.usage("SelectDemo");
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -