闲来无事写了个基于NIO的聊天室项目,费话不说了,直接贴代码吧。
Server端代码如下:
package com.xz.helloworld.nettyt.nio.im;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.Channel;
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.Set;
/**
* Server端
* @author yuxuan
*
*/
public class GroupChatServer {
private Selector selector;
private ServerSocketChannel lisntenChannel;
private static final Integer PORT = 6667;
public GroupChatServer() {
try {
//获取选择器
selector = Selector.open();
lisntenChannel = ServerSocketChannel.open();
lisntenChannel.socket().bind(new InetSocketAddress(PORT));
lisntenChannel.configureBlocking(false);
lisntenChannel.register(selector, SelectionKey.OP_ACCEPT);
} catch (Exception e) {
e.printStackTrace();
}
}
public void listen() {
try {
for(;;) {
//count > 0 有事件
int count = selector.select();
if(count > 0) {
//遍历得到的selectionKey集合
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> it = selectionKeys.iterator();
while(it.hasNext()) {
SelectionKey key = it.next();
//删除当前的KEY,防止重复处理
it.remove();
//通道发生链接
if(key.isAcceptable()) {
SocketChannel socketChannel = lisntenChannel.accept();
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ);
System.out.println(socketChannel.getRemoteAddress() + " 上线了 ");
}
//通道发生read事件
if(key.isReadable()) {
readData(key);
}
}
}else {
System.out.println("wait...");
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void readData(SelectionKey key) {
SocketChannel channel = null;
try {
channel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int count = channel.read(buffer);
if(count > 0) {
String msg = new String(buffer.array());
System.out.println("from client :" + msg);
//向其他的客户端转发消息
sendMsgToOtherClients(msg,channel);
}
} catch (IOException e) {
try {
System.out.println(channel.getRemoteAddress() + "离线");
//取消Key注册
key.cancel();
//关闭Channel
channel.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
//转发消息给其他通道
private void sendMsgToOtherClients(String msg,SocketChannel self) {
try {
System.out.println("server trans msg......");
for(SelectionKey key :selector.keys()) {
//通过Key取出对应的SocketChannel
Channel transChannel = key.channel();
if( transChannel instanceof SocketChannel && transChannel != self) {
SocketChannel socketChannel = (SocketChannel) transChannel;
socketChannel.write(ByteBuffer.wrap(msg.getBytes()));
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
GroupChatServer group = new GroupChatServer();
group.listen();
}
}
Client端如下:
package com.xz.helloworld.nettyt.nio.im;
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.SocketChannel;
import java.util.Iterator;
import java.util.Scanner;
public class GroupChatClient {
private final String HOST = "127.0.0.1";
private final Integer PORT = 6667;
private Selector selector;
private SocketChannel socketChannel;
private String username;
public GroupChatClient() {
try {
selector = Selector.open();
socketChannel = socketChannel.open(new InetSocketAddress(HOST,PORT));
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ);
username = socketChannel.getLocalAddress().toString().substring(1);
System.out.println(username + " is ok ......");
} catch (IOException e) {
e.printStackTrace();
}
}
public void sendInfo(String info) {
info = username + "说 :" + info;
try {
socketChannel.write(ByteBuffer.wrap(info.getBytes()));
} catch (Exception e) {
e.printStackTrace();
}
}
public void readInfo() {
try {
int readChannels = selector.select();
if(readChannels > 0) {
//说明有可用的通道
Iterator<SelectionKey> it = selector.selectedKeys().iterator();
while(it.hasNext()) {
SelectionKey key = it.next();
it.remove();
if(key.isReadable()) {
SocketChannel channel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
channel.read(buffer);
String msg = new String(buffer.array());
System.out.println(msg.trim());
}
}
}else {
System.out.println("no channel ...");
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
GroupChatClient client = new GroupChatClient();
//启动一个线程
new Thread() {
public void run() {
for(;;) {
client.readInfo();
try {
Thread.currentThread().sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
// e.printStackTrace();
}
}
}
}.start();
//从客户端输入
Scanner sc = new Scanner(System.in);
while(sc.hasNextLine()) {
String s = sc.nextLine();
client.sendInfo(s);
}
}
}
以上就是聊天室的全部代码了,初学NIO的朋友可以参考来学习,先运行Server端,在开启几个Client端就可以看到效果了。
有问题可以在下方评论,技术问题可以私聊。