package com.liu.server;
import java.io.IOException;
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 NIOServer {
private static int SERVER_PORT = 9000;
private static String SERVER_URI = "127.0.0.1";
private final static int BLOCK = 4096;
private static ByteBuffer receiveBuffer = ByteBuffer.allocate(BLOCK);
private static ByteBuffer sendBuffer = ByteBuffer.allocate(BLOCK);
private ServerSocketChannel serverSocketChannel = null;
private Selector selector = null;
public static void main(String[] args) {
NIOServer server = new NIOServer();
server.start();
}
private void start(){
try {
this.initServer();
this.initService();
} catch (IOException e) {
e.printStackTrace();
}
}
private void initServer(){
try {
serverSocketChannel = ServerSocketChannel.open();
//静态方法 实例化selector
selector = Selector.open();
//设置为非阻塞方式,如果为true 那么就为传统的阻塞方式
serverSocketChannel.configureBlocking(false);
/*
* 通过这个选项,可以使多个Socket对象绑定在同一个端口上。其实这样做并没有多大意义,但当使用close方法关闭Socket连接后,
* Socket对象所绑定的端口并不一定马上释放;系统有时在Socket连接关闭才会再确认一下是否有因为延迟面未到达的数据包,
* 这完全是在底层处理的,也就是说对用户是透明的;因此,在使用Socket类时完全不会感觉到。
* 这种处理机制对于随机绑定端口的Socket对象没有什么影响,
* 但对于绑定在固定端口的Socket对象就可能会抛出“Address already in use: JVM_Bind”例外。
* 因此,使用这个选项可以避免个例外的发生。
*/
serverSocketChannel.socket().setReuseAddress(true);
//绑定端口
serverSocketChannel.socket().bind(new InetSocketAddress(SERVER_URI,SERVER_PORT));
/*
* 设置服务处于可接受信息的状态,即在服务中注册KEY,告诉服务 现在以经处于属于接受状态
*/
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("NIOServer is starting at " + SERVER_PORT + "......");
} catch (IOException e) {
e.printStackTrace();
}
}
private void initService() throws IOException{
while(selector.select()>0){
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> it = selectionKeys.iterator();
System.out.println("目前已经接受的key的 size : " + selectionKeys.size());
while(it.hasNext()){
SelectionKey selectionKey = it.next();
it.remove();
//处理传过来的数据
handleData(selectionKey);
}
}
}
private void handleData(SelectionKey key) throws IOException{
if(key.isAcceptable()){
System.out.println("Accepting......");
SocketChannel channel = ((ServerSocketChannel)key.channel()).accept();
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_READ);
}else if(key.isReadable()){
System.out.println("Reading......");
SocketChannel channel = (SocketChannel) key.channel();
receiveBuffer.clear();
int count = channel.read(receiveBuffer);
if(count>0){
String receiveText = new String(receiveBuffer.array(),0,count);
System.out.println("客户端传递的内容:"+receiveText);
channel.register(selector, SelectionKey.OP_WRITE);
}
}else if(key.isWritable()){
System.out.println("Writting......");
SocketChannel channel = (SocketChannel) key.channel();
sendBuffer.clear();
sendBuffer.put(new String("这是测试数据").getBytes());
//将缓冲区各标志复位,因为向里面put了数据,标志被改变,复位到起始位置
sendBuffer.flip();
channel.write(sendBuffer);
channel.close();
}
}
import java.io.IOException;
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 NIOServer {
private static int SERVER_PORT = 9000;
private static String SERVER_URI = "127.0.0.1";
private final static int BLOCK = 4096;
private static ByteBuffer receiveBuffer = ByteBuffer.allocate(BLOCK);
private static ByteBuffer sendBuffer = ByteBuffer.allocate(BLOCK);
private ServerSocketChannel serverSocketChannel = null;
private Selector selector = null;
public static void main(String[] args) {
NIOServer server = new NIOServer();
server.start();
}
private void start(){
try {
this.initServer();
this.initService();
} catch (IOException e) {
e.printStackTrace();
}
}
private void initServer(){
try {
serverSocketChannel = ServerSocketChannel.open();
//静态方法 实例化selector
selector = Selector.open();
//设置为非阻塞方式,如果为true 那么就为传统的阻塞方式
serverSocketChannel.configureBlocking(false);
/*
* 通过这个选项,可以使多个Socket对象绑定在同一个端口上。其实这样做并没有多大意义,但当使用close方法关闭Socket连接后,
* Socket对象所绑定的端口并不一定马上释放;系统有时在Socket连接关闭才会再确认一下是否有因为延迟面未到达的数据包,
* 这完全是在底层处理的,也就是说对用户是透明的;因此,在使用Socket类时完全不会感觉到。
* 这种处理机制对于随机绑定端口的Socket对象没有什么影响,
* 但对于绑定在固定端口的Socket对象就可能会抛出“Address already in use: JVM_Bind”例外。
* 因此,使用这个选项可以避免个例外的发生。
*/
serverSocketChannel.socket().setReuseAddress(true);
//绑定端口
serverSocketChannel.socket().bind(new InetSocketAddress(SERVER_URI,SERVER_PORT));
/*
* 设置服务处于可接受信息的状态,即在服务中注册KEY,告诉服务 现在以经处于属于接受状态
*/
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("NIOServer is starting at " + SERVER_PORT + "......");
} catch (IOException e) {
e.printStackTrace();
}
}
private void initService() throws IOException{
while(selector.select()>0){
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> it = selectionKeys.iterator();
System.out.println("目前已经接受的key的 size : " + selectionKeys.size());
while(it.hasNext()){
SelectionKey selectionKey = it.next();
it.remove();
//处理传过来的数据
handleData(selectionKey);
}
}
}
private void handleData(SelectionKey key) throws IOException{
if(key.isAcceptable()){
System.out.println("Accepting......");
SocketChannel channel = ((ServerSocketChannel)key.channel()).accept();
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_READ);
}else if(key.isReadable()){
System.out.println("Reading......");
SocketChannel channel = (SocketChannel) key.channel();
receiveBuffer.clear();
int count = channel.read(receiveBuffer);
if(count>0){
String receiveText = new String(receiveBuffer.array(),0,count);
System.out.println("客户端传递的内容:"+receiveText);
channel.register(selector, SelectionKey.OP_WRITE);
}
}else if(key.isWritable()){
System.out.println("Writting......");
SocketChannel channel = (SocketChannel) key.channel();
sendBuffer.clear();
sendBuffer.put(new String("这是测试数据").getBytes());
//将缓冲区各标志复位,因为向里面put了数据,标志被改变,复位到起始位置
sendBuffer.flip();
channel.write(sendBuffer);
channel.close();
}
}
}
测试结果如下: