niosockt的使用简例


1.niosocket服务端

package com.feng.test.nioSocket;

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.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * nioSocket服务端
 * @author lenovo
 * 
 */
public class NioSocketServer extends Thread {
	private  Selector selector;
	private  ServerSocketChannel serverSocketChannel;
	private  Charset charset = Charset.forName("utf-8");
	private  static final int port = 9092;
	private ExecutorService executorService = Executors.newSingleThreadExecutor();
	/**
	 * 构造,实现等待以及连接客户端
	 */
	public NioSocketServer() {
		try {
			selector = Selector.open();
			serverSocketChannel = ServerSocketChannel.open();
			serverSocketChannel.configureBlocking(false);
			serverSocketChannel.socket().bind(new InetSocketAddress(port));
			serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
			System.out.println("服务端已启动,等待客户端连接 ,端口号: "+port);			
		} catch (IOException e) {
			e.printStackTrace();
		}		
	}
	 	
	public static void main(String[] args) {
		NioSocketServer ns = new NioSocketServer();
		ns.execute();
	}
	
	
	public void run() {
		execute();
	}
	
	public  void execute(){
    	try {
			while(selector.select()>0){// 
//				无论是否有读写事件发生,selector每隔1s被唤醒一次  
//              selector.select(1000);  
//              //阻塞,只有当至少一个注册的事件发生的时候才会继续.  
////            selector.select(); 
				 Set<SelectionKey> selectedKeys =  selector.selectedKeys();
				for(SelectionKey sk : selectedKeys){
					System.out.println("--------------------------------------进来这儿 1 ---------------------------------------------");
					if(sk.isAcceptable()){//Tests whether this key's channel is ready to accept a new socket connection. 
						System.out.println("接受连接请求:"+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
						//通过ServerSocketChannel的accept创建SocketChannel实例  
                        //完成该操作意味着完成TCP三次握手,TCP物理链路正式建立  
						SocketChannel socketChannel =	serverSocketChannel.accept();//Accepts a connection made to this channel's socket. 
						 //设置为非阻塞的  
					    socketChannel.configureBlocking(false);						
						//注册为读  
						socketChannel.register(selector, SelectionKey.OP_READ);					   
					    //将key对应的channel设置成准备接受其他请求
					    sk.interestOps(SelectionKey.OP_ACCEPT);
					}
					System.out.println("--------------------------------------进来这儿 2 ---------------------------------------------");
					//读消息
					if(sk.isReadable()){
						System.out.println("接受客户端请求: "+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
						SocketChannel socketChannel = (SocketChannel) sk.channel();
					    //如果可读状态时读取的数据为空,则判断服务端关闭输出
						executorService.submit(new  ServerThread(sk,socketChannel));
					}					
				}
				selectedKeys.clear();//Removes all of the elements from this set (optional operation). The set will be empty after this call returns.
				try {
					System.out.println("--------------------------------------进来这儿3 ---------------------------------------------");
					Thread.sleep(2000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }
	
	private class  ServerThread implements  Callable<String>{
		private SelectionKey selectionKey;
		private SocketChannel socketChannel;
		private  static final int bufferSize = 4096;
		
		
		public ServerThread(SelectionKey selectionKey,SocketChannel socketChannel) {
			this.selectionKey = selectionKey;
			this.socketChannel = socketChannel;
		}
		
		public String call() throws Exception {
			try{//***没有处理异常,结果在此新起线程里,新线程死掉,主线程接收不到异常信息
				
				String content = "";			
				ByteBuffer byteBuffer = ByteBuffer.allocate(bufferSize);
				while(socketChannel.read(byteBuffer) > 0){
					byteBuffer.flip();//Flips this buffer. The limit is set to the current position and then the position is set to zero. If the mark is defined then it is discarded. 
					content +=charset.decode(byteBuffer); 
				}
				System.out.println("接受的客户端信息:"+content);
				//将sk对应的channel设置成准备下一次的数据读取
				selectionKey.interestOps(SelectionKey.OP_READ);
				//处理数据
				if(!content.equals("")){
				Map<String,String>  map = handleAction(content,socketChannel);//1
					//Map<String,String>  map = handleAction2(content,socketChannel);//2
					
				}
				
			}catch(Exception e){
				e.printStackTrace();
			}
			return null;
		}
		
		/**
		 * 处理业务流程,一次处理完就结束
		 * @param content
		 * @param sc
		 * @return
		 */
		private  Map<String, String>  handleAction(String content,SocketChannel sc){
			Map<String, String>  result = new HashMap<String, String>();
			//处理业务
			if(content!=null&&!"".equals(content)){
				String   resultStr = content+"_"+System.currentTimeMillis()+""+"\r\n"; 
				doWrite(sc,resultStr);
			    try {
					sc.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			    result.put("result", "正常");
			}else{
				result.put("result", "参数错误");
			}			
			return result;			
		}	
		
		/**
		 * 处理业务流程不间断
		 * @param content
		 * @param sc
		 * @return
		 */
		private  Map<String, String>  handleAction2(String content,SocketChannel sc){
			Map<String, String>  result = new HashMap<String, String>();
			//处理业务
			if(content!=null&&!"".equals(content)){	
				new Thread(new chuiliThread(sc,content)).start();
			}else{
				result.put("result", "参数错误");
			}			
			return result;	
		}	
		
		
	
		
		
		/**
		 * 异步发送应答消息
		 * @param sc
		 * @param resultStr
		 */
		private void  doWrite(SocketChannel sc,String resultStr){
			System.out.println("开始往客户端返回数据:"+resultStr);
			//将消息编码为字节数组
			byte[]  bytes= resultStr.getBytes();
			//根据数组容量创建ByteBuffer
			ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length);
			writeBuffer.put(bytes);//This method transfers the bytes remaining in the given source buffer into this buffer
			writeBuffer.flip();			 
			try {
				//发送缓冲区的字节数组
				sc.write(writeBuffer);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}				
	}		





	
	
	/**
	 * 一直保持连接不关闭,服务端不断产生数据往客户端发送
	 * @author Lenovo
	 *
	 */
	private class   chuiliThread  implements  Runnable {
		private  String request ;
		private SocketChannel sc;
		public chuiliThread(SocketChannel sc ,String request) {
			this.sc = sc;
			this.request = request;
		}
		
		public void run() {			
			while(true){
				String result = "nihao_"+request+"_"+(int)(Math.random()*100)+"\r\n";				
				doWrite(sc,result);				
				try {
					Thread.sleep(1000);
				}catch (Exception e) {
					e.printStackTrace();
				}
			}			
		}
		

		/**
		 * 异步发送应答消息
		 * @param sc
		 * @param resultStr
		 * 
		 */
		private void  doWrite(SocketChannel sc,String resultStr){
			System.out.println("开始往客户端返回数据:"+resultStr);
			//将消息编码为字节数组
			byte[]  bytes= resultStr.getBytes();
			//根据数组容量创建ByteBuffer
			ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length);
			writeBuffer.put(bytes);//This method transfers the bytes remaining in the given source buffer into this buffer
			writeBuffer.flip();			 
			try {
				//发送缓冲区的字节数组
				sc.write(writeBuffer);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
}


2.niosocket客户端

package com.feng.test.nioSocket;

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.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * nioSocket贯通整个流程,观察这个特性
 * @author lenovo
 *
 */
public class NioSocketClient  extends Thread{
	private final int bufferSize = 4096 ;//分配缓冲内存大小
	
	private Charset charset;//niocharset,字符编码
	private InetSocketAddress address;
	private Selector selector ;//客户端专用selector
	private SocketChannel socketChannel;//通道
	
	//方法重载,传入参数
	public NioSocketClient(String ip,Integer port,String code) {
		this.address = new InetSocketAddress(ip, port);//构造网络地址
		if(code!=null&&!"".equals(code)){
			charset = Charset.forName(code);
		}else{
			charset = Charset.forName("utf-8");
		}
	}
	
	public static void main(String[] args) {
		NioSocketClient nioSocketClient =  new  NioSocketClient("localhost",9092,"UTF-8");
		nioSocketClient.sendReq("111");
	}
	
	@Override
	public void run() {
		sendReq("111");
	}
	
	
	public String sendReq(String param) {
		String result = "";
		try {
			if(param!=null&&!"".equals(param)){
				//定义检测socketChannel的selector对象
				selector = Selector.open();
				//连接服务器,打开通道
				socketChannel = SocketChannel.open(address);
				//通道设置成非阻塞模式
				socketChannel.configureBlocking(false);
				//向Selector注册通道,此socketChannel注册到selector中
				socketChannel.register(selector, SelectionKey.OP_READ);//SelectionKey.OP_READ
				FutureTask<String> future = new FutureTask<String>(new clientThread(selector));//1
				//FutureTask<String> future = new FutureTask<String>(new clientThread2(selector));//2
				new Thread(future).start();	
				socketChannel.write(charset.encode(param));//Writes a sequence of bytes to this channel from the given buffer. 
				if(future.get() != null){//Waits if necessary for the computation to complete, and then retrieves its result.
					result = future.get();
					System.out.println("客户端打印:"+result);
				}		
			}else{
				result = "传参错误";
			}
		} catch (ClosedChannelException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		}
		return result;		
	}
	
	
	/**
	 * 客户端读取通道中数据处理线程,单条数据处理完就结束,服务端也只响应这一次请求
	 * @author lenovo
	 *
	 */
	private class  clientThread implements Callable<String> {
		
		private Selector selector;
		
		private static final int bufferSize = 4096;
		
		public clientThread(Selector selector) {
			this.selector = selector;
		}	
		
		/**
		 * 
		 */
		public String call()   {		
			String result = "";		
			int flag = 0;
			try {
				while(selector.select() > 0){//	The number of keys, possibly zero, whose ready-operation sets were updated.				
					System.out.println("--------------------------------------进来这儿 1 ---------------------------------------------");					
					for(SelectionKey sk :selector.selectedKeys() ){//A token representing the registration of a SelectableChannel with a Selector.
						System.out.println("--------------------------------------进来这儿 2 ---------------------------------------------");
						selector.selectedKeys().remove(sk);
						if(sk.isReadable()){//Tests whether this key's channel is ready for reading. 
							//从key里面获取可读通道
						    SocketChannel  channel =  (SocketChannel) sk.channel();
						    //数据缓冲区设置
						    ByteBuffer buffer = ByteBuffer.allocate(bufferSize);
						    byte[] data = buffer.array();
						    //channel.read(buffer);//Reads a sequence of bytes from this channel into the given buffer. 
						    //如果可读状态时读取的数据为空,则判断服务端关闭输出
						    if(channel.read(buffer)>-1){//The number of bytes read, possibly zero, or -1 if the channel has reached end-of-stream
						    	System.out.println("服务端关闭输出");						    	
						    	flag = 1;
						    	channel.close();
						    	selector.close();
						    	
						    }
						    result =   new  StringBuffer().append(new String(data).trim()).toString();
						    System.out.println("客户端接收到的结果:"+result);
						    //sk.interestOps(SelectionKey.OP_READ);//Sets this key's interest set to the given value. 
						    Thread.sleep(1000);
						}
					}
				  if(flag==1){						
						break;
				  }
				}
				System.out.println("-----selector.close()---------");
				selector.close();
		    	
			} catch (IOException e) {
				e.printStackTrace();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}			
			return result;
		}
		
	}
	
	/**
	 * 客户端读取通道中数据处理线程,一直保持连接不关闭,服务端不断产生数据往客户端发送
	 * @author lenovo
	 *
	 */
	private class  clientThread2 implements Callable<String> {
		
		private Selector selector;
		
		private static final int bufferSize = 4096;
		
		public clientThread2(Selector selector) {
			this.selector = selector;
		}	
		
		/**
		 * 
		 */
		public String call()   {		
			String result = "";		
			int flag = 0;
			try {
				while(selector.select() > 0){//	The number of keys, possibly zero, whose ready-operation sets were updated.				
					System.out.println("--------------------------------------进来这儿 1 ---------------------------------------------");					
					for(SelectionKey sk :selector.selectedKeys() ){//A token representing the registration of a SelectableChannel with a Selector.
						System.out.println("--------------------------------------进来这儿 2 ---------------------------------------------");
						selector.selectedKeys().remove(sk);
						if(sk.isReadable()){//Tests whether this key's channel is ready for reading. 
							//从key里面获取可读通道
						    SocketChannel  channel =  (SocketChannel) sk.channel();
						    //数据缓冲区设置
						    ByteBuffer buffer = ByteBuffer.allocate(bufferSize);
						    byte[] data = buffer.array();
						    //channel.read(buffer);//Reads a sequence of bytes from this channel into the given buffer. 
						    //如果可读状态时读取的数据为空,则判断服务端关闭输出
						    if(channel.read(buffer)>-1){//The number of bytes read, possibly zero, or -1 if the channel has reached end-of-stream
						    	System.out.println("服务端关闭输出");						    	
						    	flag = 1;
						    	//channel.close();
						    	//selector.close();
						    	
						    }
						    result =   new  StringBuffer().append(new String(data).trim()).toString();
						    System.out.println("客户端接收到的结果:"+result);
						    //sk.interestOps(SelectionKey.OP_READ);//Sets this key's interest set to the given value. 
						    Thread.sleep(1000);
						}
					}
				  /*if(flag==1){
						
						break;
					}*/
				}
				System.out.println("-----selector.close()---------");
				selector.close();
		    	
			} catch (IOException e) {
				e.printStackTrace();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}			
			return result;
		}
		
	}
	
	
	
	
	
	/**
	 * 关闭通道,选择器
	 */
	public void close() {
		try {
			if(socketChannel!=null&&socketChannel.isConnected()){			
				socketChannel.close();			
			}
			if(selector!=null&&selector.isOpen()){
				selector.close();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
}




3.详细请看代码以及注释
阅读更多
文章标签: java niosocket
个人分类: JAVA
上一篇ORA-00001: unique constraint (NETPAY.PAY_OUT_TRADE_NO) violated
下一篇.apt_generated 的自动生成 导致 The type UserInfoSync is already defined
想对作者说点什么? 我来说一句

lottie动画效果使用简例

2017年02月21日 542KB 下载

TabActivity

2015年06月17日 652KB 下载

MFC中Slider Control 使用简例

2012年12月17日 1KB 下载

EntityFramework(EF)用例

2017年08月21日 39KB 下载

类模板的使用简例

2013年08月28日 1KB 下载

dll使用简例

2017年08月09日 11.86MB 下载

没有更多推荐了,返回首页

关闭
关闭