package io;
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.Iterator;
public class Server {
ServerSocketChannel serverSocketChannel;
// 通道管理器
private Selector selector;
private void initServer(int port) throws IOException {
serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(port));
serverSocketChannel.configureBlocking(false); // 设置成非阻塞模式
// 获得一个通道管理器
this.selector = Selector.open();
// 将通道管理器和该通道绑定,并为该通道注册SelectionKey.OP_ACCEPT事件,注册该事件后,
// 当该事件到达时,selector.select()会返回,如果该事件没到达selector.select()会一直阻塞。
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("Server初始化成功");
}
private void listen() throws IOException {
System.out.println("服务端启动成功!");
while (true) {
// 如果是阻塞模式,程序会阻塞在这里,直到有连接进来,
// 现在为非阻塞模式,无论有没有连接都会返回,socketChannel可能为null
/*SocketChannel socketChannel = serverSocketChannel.accept();
if (socketChannel != null) {
read(socketChannel);
}*/
selector.select();
Iterator ite = this.selector.selectedKeys().iterator();
while(ite.hasNext()) {
SelectionKey key = (SelectionKey)ite.next();
ite.remove();
if(key.isAcceptable()) {
System.out.println("有新的连接");
ServerSocketChannel server = (ServerSocketChannel)key.channel();
SocketChannel channel = server.accept();
channel.configureBlocking(false);
channel.write(ByteBuffer.wrap(new String("向客户端发送了一条消息").getBytes()));
channel.register(selector, SelectionKey.OP_READ);
}else if(key.isValid()&&key.isReadable()){
read(key);
}
}
}
}
/**
* 处理读取客户端发来的信息 的事件
*
* @param key
* @throws IOException
*/
public void read(SelectionKey key) {
// 服务器可读取消息:得到事件发生的Socket通道
SocketChannel channel = (SocketChannel) key.channel();
try{
// 创建读取的缓冲区
ByteBuffer buffer = ByteBuffer.allocate(100);
if(channel.isConnected()==false) {
System.out.println("连接断开");
return;
}
int read = channel.read(buffer);
//如果是正常断开 read = -1
if(read == -1){
//取消事件
key.cancel();
return;
}
byte[] data = buffer.array();
String msg = new String(data).trim();
System.out.println("服务端收到信息:" + msg);
ByteBuffer outBuffer = ByteBuffer.wrap(msg.getBytes());
channel.write(outBuffer);// 将消息回送给客户端
}catch(Exception e) {
try {
channel.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
System.out.println("客户端断开了连接~~");
}
}
private void read(SocketChannel socketChannel) throws IOException {
ByteBuffer buf = ByteBuffer.allocate(1024);
// 非阻塞模式下,read()方法可能在尚未读取到任何数据时就返回了,所以需要判断
while (true) {
if(socketChannel.read(buf) != -1) {
buf.flip();
System.out.println("收到消息: " + Charset.forName("UTF-8").decode(buf));
buf.clear();
}
}
}
public static void main(String[] args) throws IOException {
Server server = new Server();
server.initServer(8000);
server.listen();
}
}
package io;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
public class Client {
SocketChannel socketChannel;
private void initClient(String ip, int port) throws IOException {
socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
socketChannel.connect(new InetSocketAddress(ip, port));
}
private void sendMsg(String msg) throws IOException {
ByteBuffer buf = ByteBuffer.wrap(msg.getBytes(Charset.forName("UTF-8")));
socketChannel.write(buf);
}
public static void main(String[] args) throws IOException {
Client client = new Client();
client.initClient("127.0.0.1", 8000);
while (!client.socketChannel.finishConnect()) {
System.out.println("等待连接...");
}
InputStream inputStream = System.in;
BufferedReader brin = new BufferedReader(new InputStreamReader(inputStream));
String line = null;
while ((line=brin.readLine()) != null) {
System.out.println("client:" + line);
client.sendMsg(line);
}
/*client.sendMsg("今晚暗号:");
client.sendMsg("天王盖地虎");
client.sendMsg("宝塔镇河妖");*/
}
}
多线程处理
package nio;
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.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.Set;
public class ChatServer {
private ServerSocketChannel serverSocketChannel;
private Selector selector;
//获取客户端连接
public ChatServer() throws IOException {
//获取ServerSocketChannel通道
serverSocketChannel = ServerSocketChannel.open();
//绑定端口号
serverSocketChannel.bind(new InetSocketAddress(9999));
//设置非阻塞方式
serverSocketChannel.configureBlocking(false);
//获取Selector
selector = Selector.open();
//把serverSockerChannel注册到服务器
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
}
//监控客户端连接
public void start() throws IOException {
//干活
while (true) {
if (selector.select(2000) == 0) {//体现了NIO非阻塞的优势
System.out.println("没有客户端连接,我可以做别的");
continue;
}
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while (iterator.hasNext()) {
SelectionKey selectionKey = iterator.next();
if (selectionKey.isAcceptable()) {
//接收请求,得到SocketChannel
SocketChannel socketChannel = serverSocketChannel.accept();
//设置非阻塞方式
socketChannel.configureBlocking(false);
//将socketChannel注册到selector中
socketChannel.register(selector, SelectionKey.OP_READ);
System.out.println(socketChannel.getRemoteAddress().toString().substring(1)+" 上线了...");
}
if (selectionKey.isReadable()) {
//读取客户端发来的数据
readMsg(selectionKey);
}
//一定要把当前key删掉,防止重复处理
iterator.remove();
}
}
}
//读取客户端发送来的数据并且进行广播
private void readMsg(SelectionKey selectionKey) throws IOException {
//获取通道
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
//获取缓冲区
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
try{
//读取客户端发送的数据
int count = socketChannel.read(byteBuffer);
if (count >0) {
String message = new String(byteBuffer.array());
printMsg(message);
//将客户端发来的消息进行广播
broadCast(message,socketChannel);
}
}catch(IOException e) {
try {
socketChannel.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
System.out.println("客户端断开了连接~~");
}
}
private void broadCast(String message,SocketChannel socketChannel) throws IOException {
//得到所有已经就绪的Channel
for (SelectionKey key : selector.keys()) {
Channel channel = key.channel();
if (channel instanceof SocketChannel && channel != socketChannel) {
SocketChannel targetChannel = (SocketChannel) channel;
//获取缓冲区
ByteBuffer byteBuffer = ByteBuffer.wrap(message.getBytes());
targetChannel.write(byteBuffer);
}
}
}
private void printMsg(String msg) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(dateFormat.format(new Date())+" "+msg);
}
public static void main(String[] args) throws IOException {
new ChatServer().start();
}
}
package nio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
public class ChatClient {
private final String IP = "127.0.0.1";
private int port = 9999;
private SocketChannel socketChannel; //网络通道
private String userName;
public ChatClient() throws IOException {
//获取网络通道
socketChannel = SocketChannel.open();
//设置非阻塞方式
socketChannel.configureBlocking(false);
if (!socketChannel.connect(new InetSocketAddress(IP,port))) {
while (!socketChannel.finishConnect()) {//体现了NIO非阻塞的优势
System.out.println("连接服务器的同事还可以做别的事");
}
}
//得到客户端IP作为用户名
userName = socketChannel.getLocalAddress().toString().substring(1);
System.out.println("------------------"+userName+" is ready---------------");
}
//向服务端发送数据
public void sendMsg(String message) throws IOException {
//如果从键盘录入的为“bye”则关闭socketChannel,退出聊天
if (message.equalsIgnoreCase("bye")) {
socketChannel.close();
return;
}
String msg = userName + "说:" + message;
//获取缓冲区
ByteBuffer byteBuffer = ByteBuffer.wrap(msg.getBytes());
socketChannel.write(byteBuffer);
}
//从服务端接收数据
public void receiveMsg() throws IOException {
//获取缓冲区
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
//将接收到的数据写到缓冲区中
int count = socketChannel.read(byteBuffer);
if (count > 0) {
System.out.println(new String(byteBuffer.array()).trim());
}
}
}
package nio;
import java.io.IOException;
import java.util.Scanner;
public class TestChat {
public static void main(String[] args) throws IOException {
final ChatClient client = new ChatClient();
new Thread() {
public void run() {
while (true) {
try {
client.receiveMsg();
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}.start();
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()) {
String msg = scanner.nextLine();
client.sendMsg(msg);
}
}
}