网络编程 nio 基本聊天室

package cn.com.C;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
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;
import java.util.Set;

public class Client {
	public Selector selector;
	public SocketChannel socketChannel;
	private String name = "";
	private static String USER_EXIST = "system message: user exist, please change a name";
	private static String USER_CONTENT_SPILIT = "#@#";
	
	private Charset charset = Charset.forName("UTF-8");
	public void init(){
		try {
			selector = Selector.open();
			//
			socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9999));
			socketChannel.configureBlocking(false);
			socketChannel.register(selector,SelectionKey.OP_READ);
			new Thread(new ClientThread()).start();
			//在主线程中 从键盘读取数据输入到服务器端
	        Scanner scan = new Scanner(System.in);
	        while(scan.hasNextLine()){
	        	String line = scan.nextLine();
	            if("".equals(line)) {
	            	continue; //不允许发空消息
	            }
	            if("".equals(name)) {
	                name = line;
	                line = name+USER_CONTENT_SPILIT;
	            } else {
	                line = name+USER_CONTENT_SPILIT+line;
	            }
	            socketChannel.write(charset.encode(line));//sc既能写也能读,这边是写
	        }
	        //开辟一个新线程来读取从服务器端的数据
		} catch (ClosedChannelException e) {
			// TODO Auto-generated catch block
			System.out.println("-----");
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	private class ClientThread implements Runnable{
		@Override
		public void run() {
			// TODO Auto-generated method stub
			while(true){
				try {
					int readChannel = selector.select();
					if(readChannel == 0){
						continue;
					}
					Set set = selector.selectedKeys();
					Iterator iterator = set.iterator();
					while(iterator.hasNext()){
						SelectionKey sk = (SelectionKey) iterator.next();
						iterator.remove();
						dealWithSelectionKey(sk);
					}
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}

		private void dealWithSelectionKey(SelectionKey sk) {
			// TODO Auto-generated method stub
			if(sk.isReadable()){
				try {
					SocketChannel sc = (SocketChannel)sk.channel();
					ByteBuffer buffer = ByteBuffer.allocate(1024);
					String content = "";
					while(sc.read(buffer) > 0){
						 buffer.flip();
						 content += charset.decode(buffer);
						//若系统发送通知名字已经存在,则需要换个昵称
			                if(USER_EXIST.equals(content)) {
			                    name = "";
			                }
			                System.out.println(content);
			                sk.interestOps(SelectionKey.OP_READ);
					}
					
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
			}
		}
	}
	public static void main(String[] args) {
		new Client().init();
	}
}
package cn.com.C;

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.nio.charset.Charset;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class Server {
	public Selector selector;
	public ServerSocketChannel serverSocketChannel;
	
	public static final int PORT = 9999;
	
	private static String USER_CONTENT_SPILIT = "#@#";
	
	 private static String USER_EXIST = "system message: user exist, please change a name";
	
	private static HashSet<String> users = new HashSet<String>();
	
	private static Charset charset = Charset.forName("UTF-8");
	public void init(){
		try {
			selector = Selector.open();
			serverSocketChannel = ServerSocketChannel.open();
			serverSocketChannel.bind(new InetSocketAddress(PORT));
			
			//非阻塞模式
			serverSocketChannel.configureBlocking(false);
			//注册到选择器上,设置为监听状态
			serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
			System.out.println("serverSocketChannel 正在监听......");
			while(true){
				//查询轮询里面管道注册数
				
				int count = selector.select();
				if(count == 0){
					continue;
				}
				System.out.println("====" + count);
				Set selectedKeys = selector.selectedKeys();
				Iterator iterator = selectedKeys.iterator();
				while(iterator.hasNext()){
					SelectionKey selectionKey = (SelectionKey) iterator.next();
					iterator.remove();
					dealWithSelectedKey(serverSocketChannel,selectionKey);
				}
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	
	public void dealWithSelectedKey(ServerSocketChannel server,SelectionKey sk){
		if(sk.isAcceptable()){
			try {
				SocketChannel socketChannel = server.accept();
				//非阻塞模式
				socketChannel.configureBlocking(false);
				socketChannel.register(selector,SelectionKey.OP_READ);
				System.out.println("server 正在监听是否有  client  进来...");
				System.out.println(socketChannel.getRemoteAddress());				
				//设置为监听状态
//				sk.interestOps(SelectionKey.OP_ACCEPT);
				socketChannel.write(charset.encode("请输入您的名字..."));
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		//处理客户端
		if(sk.isReadable()){
			//返回客户端的管道,有数据需要读取
			SocketChannel socketChannel =  (SocketChannel) sk.channel();
			ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
			StringBuilder stringBuilder = new StringBuilder();
			try {
				while(socketChannel.read(byteBuffer) > 0){
					byteBuffer.flip();
					stringBuilder.append(charset.decode(byteBuffer));
					System.out.println(stringBuilder.length());
				}
				System.out.println("server 收到的:" +stringBuilder);
				sk.interestOps(SelectionKey.OP_READ);
			} catch (IOException e) {
				System.out.println("错误!!");
				sk.cancel();
			}finally {
				
			}
			//开始注册身份
			if(stringBuilder.length() > 0){
				String[] content = stringBuilder.toString().split(USER_CONTENT_SPILIT);
				 if(content != null && content.length ==1) {
	                    String name = content[0];
	                    if(users.contains(name)) {
	                    	try {
	                    		//名字重复
	                    		System.out.println("------+++++++");
								socketChannel.write(charset.encode(USER_EXIST));
							} catch (IOException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							} 
	                    } else {
	                        users.add(name);
	                       //统计在线人数
	                       int mans = OnlineNum(selector);
	                       System.out.println("------********" + mans);
	                       String message = "欢迎进入聊天室,当前在线人数为:"+mans;
	                       BroadCast(selector, null, message);
	                    }
				 } else if(content != null && content.length >1){
	                    String name = content[0];
	                    String message = content[1];
	                    message = name + " say " + message;
	                    if(users.contains(name)) {
	                        //不回发给发送此内容的客户端
	                        BroadCast(selector, socketChannel, message);
	                    }
				 		}  
			}
		}
	}
	
	public static int OnlineNum(Selector select){
		int count = 0;
		for(SelectionKey key:select.keys()){
			Channel targetChannel =  key.channel();
			if(targetChannel instanceof SocketChannel){
				count++;
			}
		}
		return count;
	}
	
	public static void BroadCast(Selector selector, SocketChannel except, String message){
		
		//广播到所有SocketChannel中
		for(SelectionKey key:selector.keys()){
			Channel targetChannel = key.channel();
			 if(targetChannel instanceof SocketChannel && targetChannel!=except)
	            {
	                SocketChannel dest = (SocketChannel)targetChannel;
	                try {
	                	//广播
						dest.write(charset.encode(message));
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
	            }
		}
	}
	public static void main(String[] args) {
		new Server().init();
	}
	
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值