JAVA NIO Selector構建簡單伺服器
阿新 • • 發佈:2018-11-09
JAVA NIO Selector構建簡單伺服器
ServerSocketChannel + Selector
NIOServer.java
public class NIOServer implements Runnable{
private int clientNum = 0;
private int bufferSize = 12;
@Override
public void run() {
try {
// 建立通道和選擇器
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
Selector selector = Selector.open();
InetSocketAddress inetSocketAddress = new InetSocketAddress("127.0.0.1", 5500);
serverSocketChannel. socket().bind(inetSocketAddress);
// 設定通道非阻塞 繫結選擇器
serverSocketChannel.configureBlocking(false);
/*
* ServerSocketChannel只有accept
*/
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT).attach("server");
System. out.println("Server started .... port:5500");
while(true) {
int readyChannels = selector.select();
if(readyChannels == 0) continue;
Set selectedKeys = selector.selectedKeys();
Iterator keyIterator = selectedKeys.iterator();
while(keyIterator.hasNext()) {
SelectionKey key = (SelectionKey)keyIterator.next();
// 判斷是哪個事件
if(key.isAcceptable()) {// 客戶請求連線
System.out.println(key.attachment()+ " - 接受請求事件");
++clientNum;
// 獲取通道 接受連線,
// 設定非阻塞模式(必須),同時需要註冊 讀寫資料的事件,這樣有訊息觸發時才能捕獲
SocketChannel socketChannel = ((ServerSocketChannel) key.channel()).accept();
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ).attach("accept"+clientNum);
System.out.println(key.attachment() + " - 已連線");
} else if (key.isConnectable()) {
System.out.println(key.attachment()+ " - 連線事件");
} else if (key.isReadable()) {
System.out.println(key.attachment()+ " - 讀資料事件");
SocketChannel clientChannel=(SocketChannel)key.channel();
ByteBuffer receiveBuf = ByteBuffer.allocate(bufferSize);
clientChannel.read(receiveBuf);
System.out.println(key.attachment()+ " - 讀取資料:" + getString(receiveBuf));
} else if (key.isWritable()) {
System.out.println(key.attachment()+ " - 寫資料事件");
SocketChannel clientChannel = (SocketChannel) key.channel();
ByteBuffer sendBuf = ByteBuffer.allocate(bufferSize);
String sendText = "helloc";
sendBuf.put(sendText.getBytes());
sendBuf.flip(); //寫完資料後呼叫此方法
clientChannel.write(sendBuf);
}
keyIterator.remove();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public String getString(ByteBuffer buffer){
StringBuffer builder = new StringBuffer("");
try{
for(int i = 0; i<buffer.position();i++){
builder.append((char)buffer.get(i));
}
return builder.toString();
}catch (Exception ex){
ex.printStackTrace();
return builder.toString();
}
}
}
SocketChannel
NIOClient.java
public class NIOClient implements Runnable {
private String tag = "client";
private ByteBuffer readBuffer;
private ByteBuffer writeBuffer;
private boolean isConnected = false;
private int bufferSize = 12;
public NIOClient(String tag){
this.tag = tag;
readBuffer = ByteBuffer.allocate(bufferSize);
writeBuffer = ByteBuffer.allocate(bufferSize);
}
@Override
public void run() {
try {
Selector selector = Selector.open();
SocketChannel socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
socketChannel.connect(new InetSocketAddress("127.0.0.1", 5500));
socketChannel.register(selector, SelectionKey.OP_CONNECT | SelectionKey.OP_READ|SelectionKey.OP_WRITE).attach(tag);
System.out.println(tag+" connect .... port:5500");
while(true) {
int readyChannels = selector.select();
if(readyChannels == 0) continue;
Set selectedKeys = selector.selectedKeys();
Iterator keyIterator = selectedKeys.iterator();
while(keyIterator.hasNext()) {
SelectionKey key = (SelectionKey)keyIterator.next();
// 判斷是哪個事件
if(key.isAcceptable()) {// 客戶請求連線
System.out.println(key.attachment()+ "is accepted by server");
} else if (key.isConnectable()) {
System.out.println(key.attachment()+ " connect ");
SocketChannel channel = (SocketChannel) key.channel();
if (channel.isConnectionPending()) {
try {
/*
* 人為將程式中止,等待連線建立完成,否則會報如下錯誤
* java.nio.channels.NotYetConnectedException at sun.nio.ch.SocketChannelImpl.ensureWriteOpen(SocketChannelImpl.java:274)
*/
if (channel.finishConnect()) {
System.out.println(key.attachment()+" connect server succ");
isConnected = true;
}
} catch (IOException e) {
e.printStackTrace();
}
}
} else if (key.isReadable()) {
System.out.println(key.attachment()+ " read ");
SocketChannel clientChannel = (SocketChannel) key.channel();
try {
int len = clientChannel.read(readBuffer);
if (len == -1) {
System.out.println(key.attachment()+" read : len=-1");
// 說明連線已經斷開
selector.close();
socketChannel.close();
} else {
readBuffer.flip();
byte[] buffer = new byte[len];
readBuffer.get(buffer);
readBuffer.clear();
System.out.println(key.attachment()+" read : len=" + len + ", str=" + new String(buffer));
}
} catch (IOException e) {
e.printStackTrace();
}
} else if (key.isWritable()) {
System.out.println(key.attachment()+ " write ");
SocketChannel clientChannel = (SocketChannel) key.channel();
String str = "hellos";
byte[] buffer = str.getBytes();
writeBuffer.put(buffer);
writeBuffer.flip();
try {
System.out.println(key.attachment()+ " write : len=" + buffer.length + ", str=" + str);
clientChannel.write(writeBuffer);
try {
Thread.sleep(100);
}catch (Exception e){
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
writeBuffer.clear();
}
keyIterator.remove();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
UnitTest
@Test
public void server(){
Thread server = new Thread(new NIOServer());
server.start();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread client1 = new Thread(new NIOClient("client1"));
client1.start();
Thread client2 = new Thread(new NIOClient("client2"));
client2.start();
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
client1.stop();
client2.stop();
server.stop();
}