Java NIO 非阻塞式 C/S结构简易 多人聊天室

使用JAVA 的 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.nio.charset.Charset;


public class NServer {

	private Selector selector = null;
	static final int port = 30001;
	private Charset charset = Charset.forName("UTF-8");
	public void init() throws IOException
	{
		selector = Selector.open();
		ServerSocketChannel server = ServerSocketChannel.open();
		server.bind(new InetSocketAddress(port));
		//非阻塞的方式
		server.configureBlocking(false);
		//注册到选择器上,设置为监听状态
		server.register(selector, SelectionKey.OP_ACCEPT);
		
		System.out.println("Server is listening now...");
		
		//此处阻塞监听
		while(selector.select() > 0)
		{
			
			for(SelectionKey sk : selector.selectedKeys())
			{
				selector.selectedKeys().remove(sk);
				//处理来自客户端的连接请求
				if(sk.isAcceptable())
				{
					SocketChannel sc = server.accept();
					//非阻塞模式
					sc.configureBlocking(false);
					//注册选择器,并设置为读取模式
					sc.register(selector, SelectionKey.OP_READ);
					//将此对应的channel设置为准备接受其他客户端请求
					sk.interestOps(SelectionKey.OP_ACCEPT);
					System.out.println("Server is listening from client :" + sc.getRemoteAddress());
				}
				//处理来自客户端的数据读取请求
				if(sk.isReadable())
				{
					//返回该SelectionKey对应的 Channel,其中有数据需要读取
					SocketChannel sc = (SocketChannel)sk.channel();
					ByteBuffer buff = ByteBuffer.allocate(1024);
					StringBuilder content = new StringBuilder();
					try
					{
						while(sc.read(buff) > 0)
						{
							buff.flip();
							content.append(charset.decode(buff));
							
						}
						System.out.println("Server is listening from client " + sc.getRemoteAddress() + " data rev is: " + content);
						//将此对应的channel设置为准备下一次接受数据
						sk.interestOps(SelectionKey.OP_READ);
					}
					catch (IOException io)
					{
						sk.cancel();
						if(sk.channel() != null)
						{
							sk.channel().close();
						}
					}
					if(content.length() > 0)
					{
						//广播数据到所有的SocketChannel中
						for(SelectionKey key : selector.keys())
						{
							Channel targetchannel = key.channel();
							if(targetchannel instanceof SocketChannel)
							{
								SocketChannel dest = (SocketChannel)targetchannel;
								dest.write(charset.encode(content.toString()));
							}
						}
					}
					
				}
			}
		}
	}
	
	public static void main(String[] args) throws IOException 
	{
		new NServer().init();
	}
}

客户端:

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.Scanner;


public class NClient {

	private Selector selector = null;
	static final int port = 3330;
	private Charset charset = Charset.forName("UTF-8");
	private SocketChannel sc = null;
	public void init() throws IOException
	{
		selector = Selector.open();
		//连接远程主机的IP和端口
		sc = SocketChannel.open(new InetSocketAddress("127.0.0.1",port));
		sc.configureBlocking(false);
		sc.register(selector, SelectionKey.OP_READ);
		//开辟一个新线程来读取从服务器端的数据
		new Thread(new ClientThread()).start();
		//在主线程中 从键盘读取数据输入到服务器端
		Scanner scan = new Scanner(System.in);
		while(scan.hasNextLine())
		{
			String line = scan.nextLine();
			sc.write(charset.encode(line));
		}
		
	}
	private class ClientThread implements Runnable
	{
		public void run()
		{
			try
			{
				while(selector.select() > 0)
				{
					for(SelectionKey sk : selector.selectedKeys())
					{
						selector.selectedKeys().remove(sk);
						if(sk.isReadable())
						{
							//使用 NIO 读取 Channel中的数据
							SocketChannel sc = (SocketChannel)sk.channel();
							ByteBuffer buff = ByteBuffer.allocate(1024);
							String content = "";
							while(sc.read(buff) > 0)
							{
								buff.flip();
								content += charset.decode(buff);
							}
							System.out.println("聊天信息: " + content);
							sk.interestOps(SelectionKey.OP_READ);
						}
					}
				}
			}
			catch (IOException io)
			{}
		}
	}
	
	
	
	public static void main(String[] args) throws IOException
	{
		new NClient().init();
	}
}

可以输入中文字符,采用UTF-8来进行编码。

你可能感兴趣的:(java,线程,服务器,聊天,cs)