使用Java NIO实现异步的socket通信

原创 2014年03月01日 22:46:50

关于NIO的介绍,可以参考这一组文章,http://tutorials.jenkov.com/java-nio/index.html,这组教程写得比较好。

关于用旧IO实现的Socket通信,可以参考这一组文章:http://blog.csdn.net/kongxx/article/category/1077912


最近在学习NIO与Socket的时候,发现网上鲜见真正实现异步的socket的例子,大都仅仅使用Selector来管理服务端的ServerSocketChannel,事实上没有做到真正的异步,还是按部就班地接受连接,收发信息,然后释放连接。

更常规的方法是服务端使用两个线程,一个线程采用阻塞的方法来accept客户端,另一个线程用selector来异步地处理所有连接。

     

这里使用Selector来实现异步IO的一个简单实例。服务端在主线程中通过无限循环阻塞线程来监听将传入的连接、再启动另一个线程通过Selector来异步地处理已连接的通道。客户端启动100个线程来模拟100个用户同时连入服务端,从输出的结果可以看出客户端与服务端的通信是异步地完成的。

先贴出一个工具类,里面有收发消息的两个方法。



import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;

public class SendAndReceiveUtil {
	public static String receiveData(SocketChannel channel) {
		// TODO Auto-generated method stub
		// TODO Auto-generated method stub
		ByteBuffer bb = ByteBuffer.allocate(1024);
		StringBuilder msg = new StringBuilder();
		Charset charset = Charset.forName("UTF-8");  
		CharsetDecoder decoder = charset.newDecoder();
		try {
			while( (channel.read(bb) ) > 0 ){
				bb.flip();		
				msg.append(decoder.decode(bb).toString());
				//System.out.println(msg.toString());
	
				bb.clear();
			}
			return msg.toString();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}
	public static  void sendData(SocketChannel socketChannel, String msg) {
		// TODO Auto-generated method stub
		try {
			socketChannel.write(ByteBuffer.wrap(msg.getBytes()));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
然后贴出服务端的代码。



import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

public class ChatServer {

	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
		final Selector selector = Selector.open();;
		
		ServerSocketChannel ssc = ServerSocketChannel.open();
		
		try{
			// Bind the server socket to the local host and port 
			ssc.socket().bind(new InetSocketAddress("localhost", 8080));
			
			//start a thread to handle the wirte and read
			startWRThread(selector);
			//block the main thread to accept client
			while(true){  // will block the thread
				
				SocketChannel sc = ssc.accept();
				//Get the server socket and set to non blocking mode  
				sc.configureBlocking(false);
				sc.register(selector, SelectionKey.OP_READ);
			}
		}finally{
			selector.close();
			ssc.close();
		}
	}

	private static void startWRThread(final Selector selector) {
		// TODO Auto-generated method stub
		new Thread(new Runnable() {
			@Override
			public void run() {
				// TODO Auto-generated method stub			
				try {
					while(true){
						while(selector.selectNow() > 0){
							
							Iterator<SelectionKey> it = selector.selectedKeys().iterator();
							//// Walk through the ready keys collection and process date requests.
							while(it.hasNext()){
								SelectionKey readyKey = it.next();
								if(readyKey.isReadable()){
									SocketChannel sc = (SocketChannel) readyKey.channel();
									 String msg = SendAndReceiveUtil.receiveData(sc);  
							         if(msg != null && !msg.equals("")) {
							        	 if(msg.equals("bye")){
							        		 System.out.println("Get a msg : " + msg);
							        		 sc.close();
							        	 }else{
							        		 System.out.println("Get a msg : " + msg);
							        		 SendAndReceiveUtil.sendData(sc,"Server have got you msg:"+ msg);
							        		 sc.shutdownOutput();
							        	 }	        	
							         }
							         
									 it.remove(); 
								}

								//execute((ServerSocketChannel) readyKey.channel());
							}
						}
					}
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}).start();
	}

}

最后贴出客户端代码,客户端启动100个线程模拟100个client来连接服务端,并发送线程id到服务端,随后发送”bye“来结束连接。



import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.channels.SocketChannel;




public class ChatClient {
	

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		for (int i = 1; i < 100; i++) {  
            final int idx = i;  
            new Thread(new MyRunnable(idx)).start();  
        }  
	}
	private static class MyRunnable implements Runnable {

		private final int idx;  
  	  
        private MyRunnable(int idx) {  
            this.idx = idx;  
        }  
		@Override
		public void run() {
			// TODO Auto-generated method stub
			SocketChannel socketChannel = null;  
            try {  
                socketChannel = SocketChannel.open();  
                SocketAddress socketAddress = new InetSocketAddress("localhost", 8080);  
                
                socketChannel.connect(socketAddress);  
                
                SendAndReceiveUtil.sendData(socketChannel, "My id is " + idx);  
                  
                String msg = SendAndReceiveUtil.receiveData(socketChannel);  
                if(msg != null) System.out.println("The server reply:"+msg);
                
                SendAndReceiveUtil.sendData(socketChannel,"bye");
          
            } catch (Exception ex) {  
                ex.printStackTrace();
            } finally {  
                try {          
                    socketChannel.close();  
                } catch(Exception ex) {
               	 	ex.printStackTrace();
                }  
            }  
		}
		
		
	}
}



Java Socket收发异步长连接

最近做SSO的项目,其中用到了socket长连接.一直都是看代码的,但是要求socket做成SSL的,不得不动手写写代码了.下面我给出一个简单的socket长连接. Java代码 ...
  • liuzesoft
  • liuzesoft
  • 2014年06月12日 14:33
  • 18952

Java NIO(异步IO)Socket通信例子

简要说明下:使用java nio开发网络通讯 是比较快速和方面的。因为他可以不用阻塞的方式侦听客户端的连接 ,在java nio中可以使用基于事件的机制进行非阻塞通讯,当有新的事 件进行注册时 我们...
  • wq7570875
  • wq7570875
  • 2012年01月31日 16:08
  • 11551

java写的异步socket服务端源代码

  • 2015年01月07日 12:54
  • 6KB
  • 下载

Aio--Java异步IO的 Socket Demo

package com.vdebug.aio.socket; import java.io.IOException; import java.net.InetSocketAddress; impor...
  • xxb2008
  • xxb2008
  • 2015年01月05日 17:09
  • 7809

Java7 nio2 异步Socket实践

1.Tcp服务器端应该怎么设计
  • arofree
  • arofree
  • 2014年08月27日 15:38
  • 1137

Java Socket 通信(同步阻塞式I/O)

java实现socket通信比较简单,因为它提供了ServerSocket 和Socket类。如下为一个简单的实例:TimeServer与TimeClient1 TimeServerpublic cl...
  • ouyang111222
  • ouyang111222
  • 2016年04月06日 18:23
  • 2942

java server 多client异步socket通信demo

本demo打包下载,请点击这里 本demo主要用java实现了服务器监听多客户端登录,并实现了客户端与服务器的异步socket通信,通信过程采用了消息队列缓冲机制(生产者消费者模式)。 登录过程是...
  • kingodcool
  • kingodcool
  • 2015年05月28日 10:52
  • 1326

Java Socket实战之六 使用NIO包实现Socket通信

本文地址:http://blog.csdn.net/kongxx/article/details/7288896 Java Socket实战之一 单线程通信 Java Socket实战之二 多线程...
  • kongxx
  • kongxx
  • 2012年02月23日 22:32
  • 71966

java nio 传统标准io socket 和nio socket比较与学习

在计算机系统中,最不可靠的就是网络请求,我们通过服务器端给客户端echo信息(客户端请求什么信息服务端就返回给客户端什么信息)。比较两种socket io的优劣。 一.标准io socket:    ...
  • sean417
  • sean417
  • 2017年04月09日 16:33
  • 1949

Java NIO Socket通信

一 套接字通道 1. 阻塞式套接字通道     与Socket和ServerSocket对应,NIO提供了SocketChannel和ServerSocketChannel对应,这两种通道...
  • hj7jay
  • hj7jay
  • 2016年05月05日 13:47
  • 2247
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:使用Java NIO实现异步的socket通信
举报原因:
原因补充:

(最多只允许输入30个字)