基于java底层api实现的nio

服务器端

package nio;

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.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

public class Server {
	
	private static ByteBuffer recvBuf = ByteBuffer.allocate(1024);
	
	private static ByteBuffer respBuf = ByteBuffer.allocate(1024);

	private static Map<SelectionKey,Object> sessionMessage = new ConcurrentHashMap<SelectionKey,Object>();
	public static void main(String[] args) throws IOException {
		//多路复用器
		Selector selector = Selector.open();
		
		//创建server
		ServerSocketChannel server = ServerSocketChannel.open();
		server.socket().bind(new InetSocketAddress(9999));//绑定端口
		server.configureBlocking(false);//设置非阻塞
		
		//server上注册一个多路复用器  事件标签OP_ACCEPT接收客户端连接 这样多路复用器将不断轮询server,当有客户端连接过来,就会被轮询出来  
		server.register(selector, SelectionKey.OP_ACCEPT);
		System.out.println("服务器已经启动");
		//启动监听
		listener(server, selector);
		
	}
	
	
	public static void listener(ServerSocketChannel server, Selector selector ) throws IOException{
		while (true) {
			int eventCount = selector.select();//如果有客户端连接过来,就会被轮询出来
			if (eventCount <= 0) {//小于等于0,说明没有客户端接入
				continue;
			}
			Set<SelectionKey> keys = selector.selectedKeys();//获取有事件触发的selectkey
			Iterator<SelectionKey> iter = keys.iterator();
			while (iter.hasNext()) {
				SelectionKey key = iter.next();
				//处理事件
				try {
					process(server,selector,key);
				} catch (IOException e) {//客户端异常关闭
					close(key);
				}
				iter.remove();//处理完移除这个事件
			}
		}
	}
	
	public static void process(ServerSocketChannel server,  Selector selector ,SelectionKey key) throws IOException{
		SocketChannel client = null;
		if (key.isValid() && key.isAcceptable() ) {//事件是否是有效的
			client = server.accept();//有客户端接入,把客户端连接通道也注册到多路复用器上
			
			client.configureBlocking(false);//非阻塞的
			client.register(selector, SelectionKey.OP_READ);//客户端连接过来,注册读事件
		}else if(key.isValid() && key.isReadable()){//可读的,说明注册在多路复用上的客户端有数据发过来了
			recvBuf.clear();//清空缓冲区
			client = (SocketChannel) key.channel();//通过key获取到客户端,这个客户端是在Acceptable时连接过来的客户端
			int length = client.read(recvBuf);//将数据读到缓冲区
			if (length > 0) {//读取到内容的时候
				String message = new String(recvBuf.array(),0,length);
				sessionMessage.put(key, message);//将数据放到sessionmessage中
				key.interestOps(SelectionKey.OP_WRITE);//读完数据后,这个客户端在多路复用器上的事件由read变为write,可以写了
			}else{
				if (client.isConnected()) {
					System.out.println("客户端关闭");
					close(key);
				}
			}
		}else if(key.isValid() && key.isWritable()){//可写的,说明注册在多路复用上的客户端数据已经接收完了,可以往客户端写数据了
			if (!sessionMessage.containsKey(key)) {
				return;
			}
			//获取到客户端发送过来的数据
			client = (SocketChannel) key.channel();
			Object resp = handler(sessionMessage.get(key));//将读取到的数据暴露给用户处理,得到响应数据
			respBuf.clear();
			respBuf.put((ByteBuffer)resp);
			respBuf.flip();
			client.write(respBuf);//响应客户端
			key.interestOps(SelectionKey.OP_READ);//写完数据后,这个客户端在多路复用器上的事件又由write变为read,可以读了
		}else{
			client = server.accept();//有客户端接入,把客户端连接通道也注册到多路复用器上
			System.out.println("连接状态::"+client.isConnected());
		}
	}
	
	public static ByteBuffer handler(Object message){
		System.out.println("来自客户端的消息:"+message);
		return ByteBuffer.wrap((message+"这是响应").getBytes());
		
	}
	
	public static void close(SelectionKey key){
		key.cancel();//取消注册
		SocketChannel client = (SocketChannel) key.channel();
		try {
			if (client != null) {
				client.socket().close();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

客户端

package nio;

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.util.Iterator;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

public class Client {
	private static ByteBuffer sendBuf = ByteBuffer.allocate(1024);
	
	private static ByteBuffer respBuf = ByteBuffer.allocate(1024);
	
	private static Map<SelectionKey,Object> sessionMessage = new ConcurrentHashMap<SelectionKey,Object>();
	public static void main(String[] args) throws IOException {
		//多路复用器
	    Selector selector = Selector.open();
		
		//客户端
		SocketChannel client = SocketChannel.open();
		client.configureBlocking(false);
		client.register(selector, SelectionKey.OP_CONNECT);//注册连接事件
		client.connect(new InetSocketAddress("localhost", 9999));//连接服务器,触发connect事件
		//监听客户端事件
		listener(client,selector);
	}

	private static void listener(SocketChannel client, Selector selector) throws IOException {
		while (true) {
				int eventCount = selector.select();//如果有客户端连接过来,就会被轮询出来
				if (eventCount <= 0) {//小于等于0,说明没有事件触发
					continue;
				}
				Set<SelectionKey> keys = selector.selectedKeys();//获取有事件触发的selectkey
				Iterator<SelectionKey> iter = keys.iterator();
				while (iter.hasNext()) {
					SelectionKey key = iter.next();
					//处理事件
					try {
						process(client,selector,key);
					} catch (IOException e) {//客户端异常关闭
						//close(key);
					}
					iter.remove();//处理完移除这个事件
				}
			
		}
	}

	private static void process(SocketChannel client, Selector selector,
			SelectionKey key) throws IOException{
		Scanner scan = new Scanner(System.in);
		SocketChannel channel = null;
		if (key.isValid() && key.isConnectable() ) {//事件是否是有效的
			channel = (SocketChannel) key.channel();
			if (channel.isConnectionPending()) {//如果正在连接,完成连接
				channel.configureBlocking(false);
				channel.finishConnect();
				System.out.println("客户端连接成功");
			}
			client.register(selector, SelectionKey.OP_WRITE);//客户端连接上了,可以写了
		}else if(key.isValid() && key.isWritable()){//可写了,向服务器端发送消息
			System.out.println("可以写了-----");
			String line = scan.next();
			if (line.equals("finsh")) {
				System.out.println("关闭了...");
				key.cancel();
				client.close();
				System.exit(1);
			}else{
				sendBuf.clear();
				sendBuf.put(line.getBytes());
				sendBuf.flip();
				client.write(sendBuf);//响应客户端
				key.interestOps(SelectionKey.OP_READ);//写完数据后,这个客户端在多路复用器上的事件又由write变为read,可以读了
			}
		}else if(key.isValid() && key.isReadable()){//可读,获取服务器端响应
			System.out.println("可以读了-----");
			respBuf.clear();//清空缓冲区
			int length = client.read(respBuf);//将数据读到缓冲区
			if (length > 0) {//读取到内容的时候
				String message = new String(respBuf.array(),0,length);
				System.out.println("client-响应信息::::"+message);
				key.interestOps(SelectionKey.OP_WRITE);//读完数据后,这个客户端在多路复用器上的事件由read变为write,可以写了
			}
		}		
	}
}

 

转载于:https://my.oschina.net/yibuliushen/blog/874958

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值