下面是用java nio写的一个聊天室,有两个类,一个是服务器ChatServer,一个是客户端ChatClient。他们各自都有一个main方法,运行服务器的main方法启动服务器,这就算是建立了一个聊天室了;然后运行客户端的main方法启动一个客户端进入聊天室,可以多启动几个客户端模拟不同的用户进入聊天室。一个客户进入后,就让他输入昵称,相当于一个登陆过程。输入完昵称后,就可以发言了。发言有两种方式:1.对聊天室除自己外所有人说话,相当于群聊。2.对聊天室中某个人说话,相当于私聊。
ChatServer:
package com.syz.chat3;
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.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
public class ChatServer {
private Selector selector;
private Charset charset = Charset.forName("UTF-8");
private static String SPLIT_CHAR = ":";
private static String AT_CHAR = "@";
private static String USER_EXIST = "昵称已经存在,请重新输入昵称!";
private Map<SocketChannel, String> allChannel = new HashMap<>();
public ChatServer(int port) {
init(port);
}
private void init(int port) {
try {
ServerSocketChannel serverSocketChannel = ServerSocketChannel
.open();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.bind(new InetSocketAddress(port));
selector = Selector.open();
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
}
catch (IOException e) {
e.printStackTrace();
}
}
public void start() {
while (true) {
try {
selector.select();
Iterator<SelectionKey> ite = selector.selectedKeys().iterator();
while (ite.hasNext()) {
SelectionKey key = ite.next();
ite.remove();
dealWithSelectionKey(key);
}
}
catch (IOException e) {
e.printStackTrace();
}
}
}
private void dealWithSelectionKey(SelectionKey key) {
if (key.isAcceptable()) {
ServerSocketChannel server = (ServerSocketChannel) key.channel();
try {
SocketChannel channel = server.accept();
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_READ);
key.interestOps(SelectionKey.OP_ACCEPT);
channel.write(charset.encode("请输入您的昵称:"));
}
catch (IOException e) {
e.printStackTrace();
}
}
if (key.isReadable()) {
SocketChannel channel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024 * 1024);
StringBuilder sb = new StringBuilder();
try {
while (channel.read(buffer) > 0) {
buffer.flip();
sb.append(charset.decode(buffer));
buffer.clear();
}
String content = sb.toString();
System.out.println(channel.getRemoteAddress() + "\t" + content);
if (content.length() > 0) {
String name = allChannel.get(channel);
if (name == null) {
if (allChannel.containsValue(content)) {
channel.write(charset.encode(USER_EXIST));
}
else {
allChannel.put(channel, content);
channel.write(charset
.encode("昵称设置完毕!现在您可以聊天了。群聊直接输入要说的内容即可,私聊的话,先输入"
+ AT_CHAR + ",然后输入对方的昵称,再输入"
+ SPLIT_CHAR + ",最后输入所要说的内容即可。如:"
+ AT_CHAR + "robin" + SPLIT_CHAR
+ "Hi robin,I'm James."));
channel.write(charset
.encode("现在共有在线人数为:" + allChannel.size()));
sendMessageToAll(content, content + "上线了,现在共有在线人数为:"
+ allChannel.size());
}
}
else {
boolean isAt = content.indexOf(AT_CHAR) > -1;
if (isAt) {
String from = name;
String header = content.split(SPLIT_CHAR)[0];
String to = header
.substring(header.indexOf(AT_CHAR) + 1);
String msg = content
.substring(content.indexOf(SPLIT_CHAR) + 1);
msg = from + "对你说:" + msg;
sendMessageToPrivate(from, to, msg);
}
else {
String from = name;
String msg = from + "说:" + content;
sendMessageToAll(from, msg);
}
}
}
key.interestOps(SelectionKey.OP_READ);
}
catch (IOException e) {
String name = allChannel.get(channel);
try {
if (name == null) {
System.out.println(
channel.getRemoteAddress() + "\t还没输入昵称就强行关闭了。");
}
else {
allChannel.remove(channel);
sendMessageToAll(name,
name + "下线了,现在共有在线人数为:" + allChannel.size());
}
channel.close();
}
catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
private void sendMessageToAll(String from, String msg) {
for (Entry<SocketChannel, String> entry : allChannel.entrySet()) {
SocketChannel channel = entry.getKey();
String name = entry.getValue();
if (!name.equals(from)) {
try {
channel.write(charset.encode(msg));
}
catch (IOException e) {
e.printStackTrace();
}
}
}
}
private void sendMessageToPrivate(String from, String to, String msg) {
for (Entry<SocketChannel, String> entry : allChannel.entrySet()) {
SocketChannel channel = entry.getKey();
String name = entry.getValue();
if (name.equals(to)) {
try {
channel.write(charset.encode(msg));
}
catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
new ChatServer(9999).start();
}
}
ChatClient:
package com.syz.chat3;下面看看测试:
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.nio.charset.Charset;
import java.util.Iterator;
import java.util.Scanner;
public class ChatClient {
private Selector selector;
private SocketChannel socketChannel;
private Charset charset = Charset.forName("UTF-8");
public ChatClient(String serverIp, int port) {
init(serverIp, port);
}
private void init(String serverIp, int port) {
try {
socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
socketChannel.connect(new InetSocketAddress(serverIp, port));
selector = Selector.open();
socketChannel.register(selector, SelectionKey.OP_CONNECT);
}
catch (IOException e) {
e.printStackTrace();
}
}
public void start() {
new Thread(new ClientThread()).start();
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
String line = scanner.nextLine();
if (line.equals("")) {
continue;
}
try {
socketChannel.write(charset.encode(line));
}
catch (IOException e) {
e.printStackTrace();
}
}
scanner.close();
}
private class ClientThread implements Runnable {
public void run() {
while (true) {
try {
selector.select();
Iterator<SelectionKey> ite = selector.selectedKeys()
.iterator();
while (ite.hasNext()) {
SelectionKey key = ite.next();
ite.remove();
dealWithSelectionKey(key);
}
}
catch (IOException e) {
e.printStackTrace();
}
}
}
private void dealWithSelectionKey(SelectionKey key) {
if (key.isConnectable()) {
SocketChannel channel = (SocketChannel) key.channel();
try {
if (channel.isConnectionPending()) {
channel.finishConnect();
}
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_READ);
}
catch (IOException e) {
e.printStackTrace();
}
}
if (key.isReadable()) {
SocketChannel channel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024 * 1024);
StringBuilder sb = new StringBuilder();
try {
while (channel.read(buffer) > 0) {
buffer.flip();
sb.append(charset.decode(buffer));
buffer.clear();
}
String content = sb.toString();
System.out.println(content);
key.interestOps(SelectionKey.OP_READ);
}
catch (IOException e) {
key.cancel();
if (key.channel() != null) {
try {
key.channel().close();
}
catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
}
}
public static void main(String[] args) {
new ChatClient("localhost", 9999).start();
}
}
/127.0.0.1:65271robin
/127.0.0.1:65274a
/127.0.0.1:65277b
/127.0.0.1:65280c
/127.0.0.1:65271不错,我就是叶良辰
/127.0.0.1:65274在下龙傲天
/127.0.0.1:65277在下赵日天
/127.0.0.1:65280我是个路过的酱油
/127.0.0.1:65280@robin:大神,你好啊
/127.0.0.1:65271@c:过来,我带你飞
请输入您的昵称:
robin
昵称设置完毕!现在您可以聊天了。群聊直接输入要说的内容即可,私聊的话,先输入@,然后输入对方的昵称,再输入:,最后输入所要说的内容即可。如:@robin:Hi robin,I'm James.现在共有在线人数为:1
a上线了,现在共有在线人数为:2
b上线了,现在共有在线人数为:3
c上线了,现在共有在线人数为:4
不错,我就是叶良辰
a说:在下龙傲天
b说:在下赵日天
c说:我是个路过的酱油
c对你说:大神,你好啊
@c:过来,我带你飞
请输入您的昵称:
a
昵称设置完毕!现在您可以聊天了。群聊直接输入要说的内容即可,私聊的话,先输入@,然后输入对方的昵称,再输入:,最后输入所要说的内容即可。如:@robin:Hi robin,I'm James.现在共有在线人数为:2
b上线了,现在共有在线人数为:3
c上线了,现在共有在线人数为:4
robin说:不错,我就是叶良辰
在下龙傲天
b说:在下赵日天
c说:我是个路过的酱油
请输入您的昵称:
b
昵称设置完毕!现在您可以聊天了。群聊直接输入要说的内容即可,私聊的话,先输入@,然后输入对方的昵称,再输入:,最后输入所要说的内容即可。如:@robin:Hi robin,I'm James.现在共有在线人数为:3
c上线了,现在共有在线人数为:4
robin说:不错,我就是叶良辰
a说:在下龙傲天
在下赵日天
c说:我是个路过的酱油
请输入您的昵称:
c
昵称设置完毕!现在您可以聊天了。群聊直接输入要说的内容即可,私聊的话,先输入@,然后输入对方的昵称,再输入:,最后输入所要说的内容即可。如:@robin:Hi robin,I'm James.现在共有在线人数为:4
robin说:不错,我就是叶良辰
a说:在下龙傲天
b说:在下赵日天
我是个路过的酱油
@robin:大神,你好啊
robin对你说:过来,我带你飞