使用java nio 编写简易聊天室

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_30698633/article/details/79012587

服务器端:相当于是一个接收客户端消息的分发器,为了简单,直接在接收到客户端的消息后,

                 直接发送给所有的客户端

package chatroom.chatserver;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
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.util.Iterator;
import java.util.Set;

public class ChatServer {

	public static void main(String[] args) {
		new ChatServer().serverRun();
	}

	public void serverRun() {

		Selector selector = null;

		try {
			ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
			serverSocketChannel.configureBlocking(false);
			ServerSocket socket = serverSocketChannel.socket();
			socket.bind(new InetSocketAddress(8888));

			selector = Selector.open();

			// 这里只是将该channel的accept设置为了selector感兴趣的,
                        // 此时并没有准备好,只有当客户端有连接请求的时候,这个channel的
                        // 感兴趣事件才会准备好
			SelectionKey register = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

			System.out.println("启动监听:8888端口");
			while (true) {
			// 这里只有存在准备好的事件的时候,才会返回,否则会一直阻塞
                        // 怎么才算准备好的? (当有相应的事件到来的时候,就说这个channel的这个事件准备好了)
                        // accept 当客户端有连接请求时,才会准备好,不过这里要想能获取到,
                        //     必须之前注册了accept事件,即设置为了感兴趣的事件
                        // read  当客户端有消息到来时,才会准备好,前提也是设置了read的感兴趣事件
                        // write 如果设置了write为感兴趣事件,那么每次都能在这里获取到,并执行写事件,
                        //     因为写事件是服务端向客户端写事件,所以如果设置成了write事件,不修改成别的
                        //      事件的话,这里将会一直执行write事件。
				int select = selector.select();
				System.out.println("监听中。。。" + select);
				if (select > 0) {
		       // 这里获取到准备好的SelectionKey的集合
                       // SelectionKey 我理解的就是一个pojo,它里面封装了该channel中selector感兴趣的事件,
                       // 准备好的事件,各种状态,选择器和channel等信息,我们可以通过它获取各种需要的信息
					Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
					while (iterator.hasNext()) {
						SelectionKey key = iterator.next();
						if (key.isValid() && key.isAcceptable()) {
							accept(key);
						} else if (key.isValid() && key.isReadable()) {
							read(key);
						} else if (key.isValid() && key.isWritable()) {
							write(key);
						}
					       // 这里一定要移除,不然会一直存在之前准备好的事件,出现异常
						iterator.remove();
					}
				}
			}

		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private void write(SelectionKey key) {
		// 为了简单,并没有通过SelectionKey.OP_WRITE进行像所有客户端分发消息
	}

	private void read(SelectionKey key) {
		SocketChannel channel = (SocketChannel) key.channel();
		ByteBuffer buffer = ByteBuffer.allocate(1024);
		try {
			int read = channel.read(buffer);
			if (read > 0) {
				System.out.println(read);
				buffer.flip();
				String info = new String(buffer.array(), 0, read);
				System.out.println("服务器接收到消息:" + info);
				// 将收到的信息发给聊天室的所有人
				// 这里获取到的是所有的channel的Keys集合
				Set<SelectionKey> selectedKeys = key.selector().keys();
				if (!selectedKeys.isEmpty()) {
					Iterator<SelectionKey> iterator = selectedKeys.iterator();
					while (iterator.hasNext()) {
						System.out.println("回写数据");
						SocketChannel channel2 = null;
						try {
							SelectionKey key1 = iterator.next();
							if (key1.isValid() && !key1.isReadable()) {
								continue;
							}
							channel2 = (SocketChannel) key1.channel();
							channel2.configureBlocking(false);
							channel2.write(buffer);
							buffer.rewind();
						} catch (IOException e) {
							if (channel2 != null) {
								try {
									channel2.close();
								} catch (IOException e1) {
								}
								System.out.println("关闭连接");
							}
						}
					}
				}
			}
		} catch (IOException e) {
			if (channel != null) {
				try {
					channel.close();
				} catch (IOException e1) {
				}
				System.out.println("关闭连接");
			}
		}

	}

	private void accept(SelectionKey key) {
		ServerSocketChannel ssc = null;
		SocketChannel channel = null;
		try {
			ssc = (ServerSocketChannel) key.channel();
			channel = ssc.accept();
			channel.configureBlocking(false);

			channel.register(key.selector(), SelectionKey.OP_READ);

		} catch (IOException e) {
			if (channel != null) {
				try {
					channel.close();
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
			if (ssc != null) {
				try {
					ssc.close();
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
		}

	}
}

     客户端:

package chatroom.chatserver;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.Scanner;

public class ChatClient {

	public static void main(String[] args) {
		new ChatClient().clientRun();
	}

	public void clientRun() {

		try {
			SocketChannel socketChannel = SocketChannel.open();
			Socket socket = socketChannel.socket();
			socket.connect(new InetSocketAddress("127.0.0.1", 8888));

			socketChannel.configureBlocking(false);
                        // 创建一个新线程进行服务器消息的监听
			new Thread(new receive(socketChannel)).start();

			ByteBuffer buffer = ByteBuffer.allocate(1024);

			Scanner scanner = new Scanner(System.in);

			while (true) {
				System.out.println("请输入:");
				buffer.clear();
				buffer.put(scanner.nextLine().getBytes());

                       // 这里写之前一定要flip,因为上面的put已经把buffer的position等信息修改了,
                       // 将缓存数据写出去的话,要从buffer的0开始
				buffer.flip();
				socketChannel.write(buffer);
			}

		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	class receive implements Runnable {

		private SocketChannel socketChannel;

		public receive(SocketChannel socketChannel) {
			this.socketChannel = socketChannel;
		}

		@Override
		public void run() {

			System.out.println("开始监听数据");

			ByteBuffer buffer = ByteBuffer.allocate(1024);

			while (true) {
				buffer.clear();
				int read;
				try {
					read = socketChannel.read(buffer);
					if (read > 0) {
						buffer.flip();
						System.out.println("接收到数据:" + new String(buffer.array(), 0, read));
					}
				} catch (IOException e) {
					if (socketChannel != null) {
						try {
							socketChannel.close();
						} catch (IOException e1) {
							System.out.println("连接关闭");
						}
					}
				}

			}

		}

	}

}


     

猜你喜欢

转载自blog.csdn.net/qq_30698633/article/details/79012587