NIO我一生之敌
Server
package io;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;
public class ServerNIO {
public static void main(String[] args) throws IOException {
ServerSocketChannel serverChannel = ServerSocketChannel.open();
InetSocketAddress serverAddress = new InetSocketAddress(8080);
serverChannel.bind(serverAddress);
serverChannel.configureBlocking(false);
Selector selector = Selector.open();
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("【log】服务器启动成功");
while(true) {
selector.select();
Set<SelectionKey> selectionKey = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKey.iterator();
while(iterator.hasNext()) {
SelectionKey key = iterator.next();
if(key.isAcceptable()) {
//连接事件
acceptHandle(serverChannel, selector);
} else if(key.isReadable()) {
//读事件
readHandle(serverChannel, selector, key);
}
iterator.remove();
}
}
}
public static void acceptHandle(ServerSocketChannel serverChannel, Selector selector) throws IOException {
SocketChannel socketChannel = serverChannel.accept();
socketChannel.configureBlocking(false);
ByteBuffer buffer = ByteBuffer.allocate(1024);
//让每个事件携带一个buffer,以后就不用了allocate啦
socketChannel.register(selector, SelectionKey.OP_READ, buffer);
System.out.println("【log】" + socketChannel.getRemoteAddress() + "建立连接");
//给socketChannel发送消息:欢迎来到群聊系统
sendToSelf("欢迎来到XXX交流群", socketChannel, buffer);
//给其余socketChannel发送消息:xxx加入群聊系统
sendToOther("初次见面大家多多关照", selector, serverChannel, socketChannel);
}
public static void readHandle(ServerSocketChannel serverChannel, Selector selector, SelectionKey key) throws IOException {
SocketChannel socketChannel = (SocketChannel) key.channel();
ByteBuffer buffer = (ByteBuffer) key.attachment();
buffer.clear();
try {
//将buffer中的消息读取出来发送给其余人
int f = socketChannel.read(buffer);
while (f > 0) {
buffer.flip();
String msg = new String(buffer.array(), 0, f);
System.out.println("【log】" + socketChannel.getRemoteAddress() + "发送消息:" + msg);
sendToOther(msg, selector, serverChannel, socketChannel);
buffer.clear();
f = socketChannel.read(buffer);
}
} catch (IOException e){
//当一个通道关闭时会触发该通道的读事件
System.out.println("【log】" + socketChannel.getRemoteAddress() + "用户下线了");
sendToOther("你们先聊,我溜了", selector, serverChannel, socketChannel);
key.cancel();
socketChannel.close();
}
}
public static void sendToOther(String msg, Selector selector, ServerSocketChannel server, SocketChannel self) throws IOException {
Set<SelectionKey> selectionKeys = selector.keys();
for(SelectionKey selectionKey : selectionKeys) {
Channel channel = selectionKey.channel();
if(server == channel) continue;
if(self == channel) continue;
ByteBuffer buffer = (ByteBuffer) selectionKey.attachment();
sendToSelf(self.getRemoteAddress() + ": " + msg, (SocketChannel) channel, buffer);
}
}
public static void sendToSelf(String msg, SocketChannel socketChannel, ByteBuffer buffer) throws IOException {
buffer.clear();
buffer.put(msg.getBytes());
buffer.flip();
socketChannel.write(buffer);
}
}
Client
package io;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.Scanner;
public class ClientNIO {
public static void main(String[] args) throws IOException, InterruptedException {
SocketChannel channel = SocketChannel.open();
SocketAddress address = new InetSocketAddress("localhost", 8080);
channel.connect(address);
new Thread(() -> {
ByteBuffer buffer = ByteBuffer.allocate(1024);
Scanner scanner = new Scanner(System.in);
while(true) {
String msg = scanner.nextLine();
buffer.put(msg.getBytes());
buffer.flip();
try {
channel.write(buffer);
} catch (IOException e) {
e.printStackTrace();
}
buffer.clear();
}
}).start();
ByteBuffer buffer = ByteBuffer.allocate(1024);
while(true) {
int f = channel.read(buffer);
buffer.flip();
while(f > 0) {
String msg = new String(buffer.array(), 0, f);
buffer.clear();
System.out.println(msg);
f = channel.read(buffer);
}
}
}
}