NIO实现群聊

NIO实现群聊

NIO实现服务端

/**
 * 
 * @author wqzhong
 * 
 * 客户端主动关闭连接,服务端会一直出现可读事件,read一直返回-1
 * 	   - 解决的方案是服务端主动关闭通道SocketChannel,当关闭后,select就不会再继续关注该通道
 * 			
 *
 */
public class NIOServer {

	private static final int PORT = 6666;
	private Selector selector;
	private ServerSocketChannel serverSocketChannel;
	
	public static void main(String[] args) throws IOException {
		new NIOServer().listen();
	}
	
	public NIOServer() {
		try {
			selector = Selector.open();
			serverSocketChannel = ServerSocketChannel.open();
			serverSocketChannel.socket().bind(new InetSocketAddress(PORT));
			serverSocketChannel.configureBlocking(false);
			serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void listen() {
		try {
			while(true) {
				if(selector.select()>0) {
					Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
					while(iterator.hasNext()) {
						//System.out.println("ddd");
						SelectionKey selectionKey = iterator.next();
						if(selectionKey.isAcceptable()) {
							SocketChannel socketChannel = serverSocketChannel.accept();
							socketChannel.configureBlocking(false);
							socketChannel.register(selector, SelectionKey.OP_READ);
							String clientName = socketChannel.getRemoteAddress().toString().substring(1);
							System.out.println("clent:"+clientName+"上线");
						}
						if(selectionKey.isReadable()) {
							recvData(selectionKey);
						}
						iterator.remove();
					}
					//iterator.remove();//telnet 127.0.0.1 6666
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	    *      接受数据
	 * @param selectionKey
	 * @throws IOException
	 */
	public void recvData(SelectionKey selectionKey) throws IOException {
		SocketChannel socketChannel = (SocketChannel)selectionKey.channel();
		ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
		int read = socketChannel.read(byteBuffer);
		if(read == -1) {
            System.out.println("read:"+read);
            socketChannel.close();
        }
		String msg = new String(byteBuffer.array());
		sendToClient(socketChannel, msg);
	}
	
	/**
	 * x 向其他客户端转发信息
	 * @param self
	 * @param msg
	 * @throws IOException
	 */
	public void sendToClient(SocketChannel self,String msg) throws IOException {
		String clientName = self.getRemoteAddress().toString().substring(1);
		msg = clientName+" :"+msg;
		Iterator<SelectionKey> iterator = selector.keys().iterator();
		while(iterator.hasNext()) {
			SelectableChannel channel = iterator.next().channel();
			if(channel instanceof SocketChannel && self != channel) {
				((SocketChannel)(channel)).write(ByteBuffer.wrap(msg.getBytes()));
			}
		}
	}
	
}

NIO实现客户端

public class NIOClient {

	private static final String HOSTNAME = "127.0.0.1";
	private static final int PORT = 6666;
	private Selector selector;
	private SocketChannel socketChannel;
	
	public static void main(String[] args) {
		new NIOClient().recvData();
	}
	
	public NIOClient() {
		try {
			selector = Selector.open();
			socketChannel = SocketChannel.open();
			socketChannel.socket().connect(new InetSocketAddress(HOSTNAME, PORT));
			socketChannel.configureBlocking(false);
			socketChannel.register(selector, SelectionKey.OP_READ);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public void recvData() {
		try {
			String client = socketChannel.getLocalAddress().toString().substring(1);
			System.out.println(client);
			SendData data = new SendData();
			new Thread(data).start();
			while(true) {
				if(selector.select()>0) {
					Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
					while(iterator.hasNext()) {
						SelectionKey selectionKey = iterator.next();
						if(selectionKey.isReadable()) {
							SocketChannel channel = (SocketChannel)selectionKey.channel();
							ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
							channel.read(byteBuffer);
							String msg = new String(byteBuffer.array());
							System.out.println(msg);
						}
						iterator.remove();
					}
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	class SendData implements Runnable{
		private Scanner scanner = new Scanner(System.in);
		
		@Override
		public void run() {
			sendMsg();
		}
		
		public void sendMsg() {
			try {
				while(true) {
					String msg = scanner.nextLine();
					System.out.println("我:"+msg);
					socketChannel.write(ByteBuffer.wrap(msg.getBytes()));
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

}

注意事项

  1. socketChannel.configureBlocking(false); 需要设置成false
  2. iterator.remove(); 需要移除,不然重复执行
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值