一、服务端
package com.nio;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
public class ChatServer {
private ServerSocketChannel listenChannel; //监听通道
private Selector selector; //选择器对象
private static final int PORT = 9999;
public ChatServer() {
try {
// 1得到监听通道
listenChannel = ServerSocketChannel.open();
// 2得到选择器
selector = Selector.open();
// 3绑定端口
listenChannel.bind(new InetSocketAddress(PORT));
// 4设置为非阻塞模式
listenChannel.configureBlocking(false);
// 5将选择器绑定到监听通道并监听accept事件
listenChannel.register(selector, SelectionKey.OP_ACCEPT);
printInfo("server ok ...");
} catch (Exception e) {
e.printStackTrace();
}
}
// 6干活
public void start() {
try {
while (true) {
if (selector.select(3000) == 0) {
continue;
}
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while(iterator.hasNext()) {
SelectionKey key = iterator.next();
if (key.isAcceptable()) { // 连接请求事件
SocketChannel sc = listenChannel.accept();
sc.configureBlocking(false);
sc.register(selector, SelectionKey.OP_READ);
System.out.println(sc.getRemoteAddress().toString().substring(1) + "上线了...");
}
if (key.isReadable()) { // 读取数据事件
readMsg(key);
}
// 把keys删掉,防止重复处理
iterator.remove();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
// 读取到客户端发送过来的消息并广播出去
public void readMsg(SelectionKey key) throws Exception {
SocketChannel sc = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
if (sc.read(buffer) > 0) {
// 打印接收到的消息
String msg = new String(buffer.array());
printInfo(msg.trim());
// 发广播
broadCast(sc, msg);
}
}
public void broadCast(SocketChannel sc, String msg) throws Exception {
printInfo("服务器发送了广播...");
for (SelectionKey key : selector.keys()) {
SelectableChannel channel;
if ((channel = key.channel()) instanceof SocketChannel && key.channel() != sc) {
ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes());
((SocketChannel) channel).write(buffer);
}
}
}
private void printInfo(String str) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("["+sdf.format(new Date()) + "]->" + str);
}
public static void main(String[] args) {
new ChatServer().start();
}
}
二、客户端
package com.nio;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
public class ChatClient {
private final String HOST = "127.0.0.1";
private int PORT = 9999;
private SocketChannel socketChannel;
private String userName;
public ChatClient() {
try {
// 1得到一个网络通道
socketChannel = SocketChannel.open();
// 2设置非阻塞方式
socketChannel.configureBlocking(false);
// 3服务端IP和端口
InetSocketAddress inetSocketAddress = new InetSocketAddress(HOST, PORT);
// 4连接服务器
if (!socketChannel.connect(inetSocketAddress)) {
while (!socketChannel.finishConnect()) {
System.out.println("客户端一直在连接.....");
}
}
// 5得到客户端IP和端口,作为聊天用户名
userName = socketChannel.getLocalAddress().toString().substring(1);
System.out.println("-------------client: " + userName + " is ready-------------");
} catch (Exception e) {
e.printStackTrace();
}
}
// 向服务器发送数据
public void sendMsg(String msg) throws Exception {
if (msg.equalsIgnoreCase("bye")) {
socketChannel.close();
return;
}
msg = userName + "say: " + msg;
ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes());
socketChannel.write(buffer);
}
// 从服务端接收数据
public void receiveMsg() throws Exception {
ByteBuffer buffer = ByteBuffer.allocate(1024);
if (socketChannel.read(buffer) > 0) {
String msg = new String(buffer.array());
System.out.println(msg.trim());
}
}
}
三、测试客户端,启多个线程
package com.nio;
import java.util.Scanner;
public class Test {
public static void main(String[] args) throws Exception {
ChatClient chatClient = new ChatClient();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
chatClient.receiveMsg();
Thread.sleep(3000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}).start();
Scanner scanner = new Scanner(System.in);
while(scanner.hasNextLine()) {
chatClient.sendMsg(scanner.nextLine());
}
}
}