package nio;
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.Scanner;
public class Server implements Runnable {
private Selector selector;
private ByteBuffer readBuffer = ByteBuffer.allocate(1024);
private ByteBuffer writeBuffer = ByteBuffer.allocate(2014);
public static void main(String[] args0) {
new Thread(new Server(9999)).start();
}
public Server(int port) {
init(port);
}
private void init(int port) {
try {
System.out.println("server starting at port" + port + "....");
// 开启多路复用器
this.selector = Selector.open();
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.bind(new InetSocketAddress(port));
/*
* register(Selector,int) int - 状态编码 OP_ACCEPT : 连接成功的标记位 OP_READ : 可以读取数据的标记
* OP_WRITE : 可以写入数据的标记
*
*/
serverSocketChannel.register(this.selector, SelectionKey.OP_ACCEPT);
System.out.println("server started");
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void run() {
// TODO Auto-generated method stub
while (true) {
try {
// 阻塞方法,当至少有一个通道被选中,此方法返回,通道是否返回由多路复用器的通道标记决定
this.selector.select();
Iterator<SelectionKey> keys = this.selector.selectedKeys().iterator();
while (keys.hasNext()) {
SelectionKey key = keys.next();
keys.remove();
if (key.isValid()) {
try {
if (key.isAcceptable()) {
accept(key);
}
} catch (Exception e) {
key.cancel(); // disconnect
}
try {
if (key.isReadable()) {
read(key);
}
} catch (Exception e) {
key.cancel(); // disconnect
}
try {
if (key.isWritable()) {
write(key);
}
} catch (Exception e) {
key.cancel(); // disconnect
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void write(SelectionKey key) {
this.writeBuffer.clear();
SocketChannel socketChannel = (SocketChannel)key.channel();
Scanner scanner = new Scanner(System.in);
try {
System.out.println("put message for send to client");
String line = scanner.nextLine();
writeBuffer.put(line.getBytes("UTF-8"));
writeBuffer.flip();
socketChannel.write(writeBuffer);
socketChannel.register(this.selector, SelectionKey.OP_READ);
} catch (Exception e) {
e.printStackTrace();
}
}
private void read(SelectionKey key) {
try {
this.readBuffer.clear();
SocketChannel socketChannel = (SocketChannel)key.channel();
//将通道中的数据读取到缓存中 通道中的数据就是客户端发送给服务器的数据
int readLength = socketChannel.read(readBuffer);
//检查客户端是否写入数据
if(readLength==-1) {
key.channel().close();
key.cancel();
return;
}
/*flip是游标重置 NIO中最复杂的操作 就是buffer的控制
* Buffer中有一个游标 游标信息在操作后不会归零
*/
this.readBuffer.flip();
byte[] data = new byte[readBuffer.remaining()];
readBuffer.get(data);
System.out.println("from " + socketChannel.getRemoteAddress()+ " client: " + new String(data,"UTF-8"));
socketChannel.register(this.selector, SelectionKey.OP_WRITE);
} catch (Exception e) {
e.printStackTrace();
}
}
private void accept( SelectionKey key) {
try {
//此通道是init方法中注册到selector上的serverSocketChannel
ServerSocketChannel serverSocketChannel = (ServerSocketChannel)key.channel();
//阻塞方法 当客户端发起请求后返回 此通道与客户端一一对应
SocketChannel socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false);
//设置对应客户端的通道标记状态 此通道读取数据用
socketChannel.register(this.selector, SelectionKey.OP_READ);
} catch (Exception e) {
e.printStackTrace();
}
}
}
package nio;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.Scanner;
public class Clinet {
public static void main(String[] agrs0) {
InetSocketAddress remoAddress = new InetSocketAddress("localhost",9999);
SocketChannel socketChannel = null;
ByteBuffer buffer = ByteBuffer.allocate(1024);
try {
socketChannel = SocketChannel.open();
socketChannel.connect(remoAddress);
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.println("put message for send to server");
String line = scanner.nextLine();
if(line.equals("exit")) {
break;
}
buffer.put(line.getBytes("UTF-8"));
buffer.flip();
socketChannel.write(buffer);
buffer.clear();
//读取服务器返回的数据
int readLength = socketChannel.read(buffer);
if(readLength == -1) {
break;
}
buffer.flip();
byte[] data = new byte[buffer.remaining()];
buffer.get(data);
System.out.print("from server: "+new String(data,"UTF-8"));
buffer.clear();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}