服务端
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.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Set;
public class NioSocketServer {
private static Selector selector = null;
private static ServerSocketChannel serverSocketChannel = null;
private static ByteBuffer writeBuffer = ByteBuffer.allocateDirect(1024);
private static ByteBuffer readBuffer = ByteBuffer.allocateDirect(1024);
private static StringBuffer message = new StringBuffer();
private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
static {
try {
serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.bind(new InetSocketAddress(8888));
System.out.println("listening on port 8888");
selector = Selector.open();
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
while (selector.select(0L) > 0) {
Set<SelectionKey> selectionKeys = selector.selectedKeys();
System.out.println("\033[31;m"+"selector is activity \033[0m,keySize:" + selectionKeys.size());
for (SelectionKey selectionKey : selectionKeys) {
if (selectionKey.isAcceptable()) {
System.out.println("\033[33;4m"+simpleDateFormat.format(new Date())+"\033[0m \033[31;4misAcceptable"+"\033[0m");
ServerSocketChannel serverChannel = (ServerSocketChannel) selectionKey.channel();
SocketChannel socketChannel = serverChannel.accept();
if (socketChannel == null) {
continue;
}
socketChannel.configureBlocking(false);
SelectionKey newSocketKey = socketChannel.register(selector, SelectionKey.OP_READ);
String ip = socketChannel.socket().getInetAddress().getHostAddress();
int port = socketChannel.socket().getPort();
String format = String.format("hi new client ip:%s,port:%s\n", ip, port);
System.out.println(format);
newSocketKey.attach("hi~,"+format);
newSocketKey.interestOps(newSocketKey.interestOps() | SelectionKey.OP_WRITE);
}
else if (selectionKey.isReadable()) {
System.out.println("\033[33;4m"+simpleDateFormat.format(new Date())+"\033[0m \033[31;4misReadable\033[0m");
handleReceive(selectionKey);
} else if (selectionKey.isWritable()) {
System.out.println("\033[33;4m"+simpleDateFormat.format(new Date())+"\033[0m \033[31;4misWritable"+"\033[0m");
handleSend(selectionKey);
}
}
selectionKeys.clear();
}
}
private static void handleReceive(SelectionKey selectionKey) throws IOException {
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
readBuffer.clear();
int read = 0;
try {
while ((read = socketChannel.read(readBuffer)) > 0) {
readBuffer.flip();
String chunk = Charset.forName("UTF-8").decode(readBuffer).toString();
message.append(chunk);
if (message.indexOf("\n") >= 0) {
System.out.print("receiveData --->" + "\033[36;4m"+message+"\033[0m");
selectionKey.attach("server message echo:" + "已经收到\n");
selectionKey.interestOps(selectionKey.interestOps() | SelectionKey.OP_WRITE);
message.setLength(0);
}
readBuffer.clear();
}
if (read == -1) {
System.out.println("disconnect a client..");
selectionKey.cancel();
socketChannel.close();
}
if (read == 0) {
System.out.println("000,接受缓冲区已经读完了\n");
}
}catch (Exception e){
System.err.println("读取数据发生异常");
selectionKey.cancel();
socketChannel.close();
}
}
private static void handleSend(SelectionKey selectionKey) throws IOException {
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
String message = (String) selectionKey.attachment();
if (message == null) {
return;
}
selectionKey.attach(null);
writeBuffer.clear();
writeBuffer.put(message.getBytes(Charset.forName("UTF-8")));
writeBuffer.flip();
while (writeBuffer.hasRemaining()) {
socketChannel.write(writeBuffer);
}
System.out.println("写出数据 ---> "+message);
selectionKey.interestOps(selectionKey.interestOps() & ~SelectionKey.OP_WRITE);
}
客户端 (支持断线自动重连)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Set;
public class NioSocketClient {
private static final ByteBuffer sendBuffer = ByteBuffer.allocateDirect(8196);
private static final ByteBuffer receiveBuffer = ByteBuffer.allocateDirect(1024);
private static Selector selector = null;
private static SocketChannel socketChannel = null;
private static SelectionKey registerKey = null;
private static Thread reactor = null;
private static boolean isConnected() {
return socketChannel != null && socketChannel.isConnected();
}
public static void main(String[] args) throws IOException {
selector = Selector.open();
initConnect();
reactor = new Thread(NioSocketClient::reactor);
reactor.start();
Thread receiver = new Thread(NioSocketClient::listenUserInput);
receiver.start();
}
private static void initConnect() {
try {
socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
boolean connect = socketChannel.connect(new InetSocketAddress("127.0.0.1", 8888));
if (connect) {
registerKey = socketChannel.register(selector, SelectionKey.OP_READ);
} else {
registerKey = socketChannel.register(selector, SelectionKey.OP_CONNECT);
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static void reconnection() {
try {
registerKey.cancel();
socketChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
reactor.interrupt();
initConnect();
reactor = new Thread(NioSocketClient::reactor);
reactor.start();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private static void reactor() {
try {
while (!Thread.interrupted()) {
int count = -2;
while ((count = selector.select(0L)) > 0) {
Set<SelectionKey> keys = selector.selectedKeys();
System.out.println("selector is activity,keySize:" + keys.size());
for (SelectionKey key : keys) {
if (key.isValid() && key.isConnectable()) {
System.out.println("isConnectable");
SocketChannel socketChannel = (SocketChannel) key.channel();
boolean finishConnect = false;
try {
finishConnect = socketChannel.finishConnect();
} catch (Exception e) {
finishConnect = false;
}
if (finishConnect) {
System.out.println("已经连接到服务器");
socketChannel.register(selector, SelectionKey.OP_READ);
synchronized (sendBuffer){
if(sendBuffer.hasRemaining() && (sendBuffer.remaining()!=sendBuffer.capacity())){
key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);
}
}
} else {
System.out.println("连接失败尝试重连。。。");
key.cancel();
socketChannel.close();
Thread.sleep(2000);
initConnect();
}
}
else if (key.isReadable()) {
System.out.println("isReadable");
receive(key);
}
else if (key.isWritable()) {
System.out.println("isWritable");
send(key);
}
}
keys.clear();
}
}
} catch (InterruptedException e) {
System.out.println("reactor线程被提前中断,正常退出");
} catch (Exception e) {
e.printStackTrace();
}
}
private static void receive(SelectionKey key) throws IOException {
SocketChannel socketChannel = (SocketChannel) key.channel();
int read = socketChannel.read(receiveBuffer);
if (read > 0) {
receiveBuffer.flip();
String receiveData = Charset.forName("UTF-8").decode(receiveBuffer).toString();
System.out.println("receive server message--->" + receiveData);
receiveBuffer.clear();
}
if (read == -1) {
System.out.println("server already close.\n");
key.cancel();
socketChannel.close();
}
}
private static void send(SelectionKey key) throws IOException {
SocketChannel socketChannel = (SocketChannel) key.channel();
boolean sysFull = false;
synchronized (sendBuffer){
sendBuffer.flip();
while (sendBuffer.hasRemaining()) {
int writed = socketChannel.write(sendBuffer);
System.out.println("writed byte is:" + writed);
if(writed<=0){
sysFull = true;
System.out.println("系统发送缓存已经满了");
break;
}
}
sendBuffer.compact();
}
if(!sysFull){
key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
}
}
private static void listenUserInput() {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
try {
String msg;
while ((msg = bufferedReader.readLine()) != null) {
System.out.println("Thread.getAllStackTraces size:" + Thread.getAllStackTraces().keySet().size());
if (!isConnected()) {
System.out.println("发送失败,连接已经断开,尝试重连。。。");
synchronized (sendBuffer) {
sendBuffer.put((msg + "\n").getBytes());
}
if (socketChannel != null && !socketChannel.isConnectionPending()) {
reconnection();
} else {
System.out.println("已经尝试重连,请勿重复触发。。。");
}
continue;
}
synchronized (sendBuffer) {
sendBuffer.put((msg + "\n").getBytes());
}
registerKey.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);
selector.wakeup();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}