JAVA NIO 服务器与客户端实现示例(代码1)

公共类:

[java] view plain copy print ?
  1. package com.stevex.app.nio;  
  2.    
  3. import java.nio.ByteBuffer;  
  4. import java.nio.CharBuffer;  
  5. import java.nio.charset.CharacterCodingException;  
  6. import java.nio.charset.Charset;  
  7. import java.nio.charset.CharsetDecoder;  
  8. import java.nio.charset.CharsetEncoder;  
  9.    
  10. public class CharsetHelper {  
  11.     private static final String UTF_8 = "UTF-8";  
  12.     private static CharsetEncoder encoder = Charset.forName(UTF_8).newEncoder();  
  13.     private static CharsetDecoder decoder = Charset.forName(UTF_8).newDecoder();  
  14.        
  15.     public static ByteBuffer encode(CharBuffer in) throws CharacterCodingException{  
  16.         return encoder.encode(in);  
  17.     }  
  18.    
  19.     public static CharBuffer decode(ByteBuffer in) throws CharacterCodingException{  
  20.         return decoder.decode(in);  
  21.     }  
  22. }  
package com.stevex.app.nio;
 
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
 
public class CharsetHelper {
    private static final String UTF_8 = "UTF-8";
    private static CharsetEncoder encoder = Charset.forName(UTF_8).newEncoder();
    private static CharsetDecoder decoder = Charset.forName(UTF_8).newDecoder();
     
    public static ByteBuffer encode(CharBuffer in) throws CharacterCodingException{
        return encoder.encode(in);
    }
 
    public static CharBuffer decode(ByteBuffer in) throws CharacterCodingException{
        return decoder.decode(in);
    }
}

服务器代码:

[java] view plain copy print ?
  1. package com.stevex.app.nio;  
  2.    
  3. import java.io.IOException;  
  4. import java.net.InetSocketAddress;  
  5. import java.nio.ByteBuffer;  
  6. import java.nio.CharBuffer;  
  7. import java.nio.channels.ClosedChannelException;  
  8. import java.nio.channels.SelectionKey;  
  9. import java.nio.channels.Selector;  
  10. import java.nio.channels.ServerSocketChannel;  
  11. import java.nio.channels.SocketChannel;  
  12. import java.util.Iterator;  
  13.    
  14. public class XiaoNa {  
  15.     private ByteBuffer readBuffer;  
  16.     private Selector selector;  
  17.        
  18.     public static void main(String[] args){  
  19.         XiaoNa xiaona = new XiaoNa();  
  20.         xiaona.init();  
  21.         xiaona.listen();  
  22.     }  
  23.        
  24.     private void init(){  
  25.         readBuffer = ByteBuffer.allocate(1024);  
  26.         ServerSocketChannel servSocketChannel;  
  27.            
  28.         try {  
  29.             servSocketChannel = ServerSocketChannel.open();  
  30.             servSocketChannel.configureBlocking(false);  
  31.             //绑定端口  
  32.             servSocketChannel.socket().bind(new InetSocketAddress(8383));  
  33.                
  34.             selector = Selector.open();  
  35.             servSocketChannel.register(selector, SelectionKey.OP_ACCEPT);  
  36.         } catch (IOException e) {  
  37.             e.printStackTrace();  
  38.         }        
  39.     }  
  40.    
  41.     private void listen() {  
  42.         while(true){  
  43.             try{  
  44.                 selector.select();               
  45.                 Iterator ite = selector.selectedKeys().iterator();  
  46.                    
  47.                 while(ite.hasNext()){  
  48.                     SelectionKey key = (SelectionKey) ite.next();                    
  49.                     ite.remove();//确保不重复处理  
  50.                        
  51.                     handleKey(key);  
  52.                 }  
  53.             }  
  54.             catch(Throwable t){  
  55.                 t.printStackTrace();  
  56.             }                            
  57.         }                
  58.     }  
  59.    
  60.     private void handleKey(SelectionKey key)  
  61.             throws IOException, ClosedChannelException {  
  62.         SocketChannel channel = null;  
  63.            
  64.         try{  
  65.             if(key.isAcceptable()){  
  66.                 ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();  
  67.                 channel = serverChannel.accept();//接受连接请求  
  68.                 channel.configureBlocking(false);  
  69.                 channel.register(selector, SelectionKey.OP_READ);  
  70.             }  
  71.             else if(key.isReadable()){  
  72.                 channel = (SocketChannel) key.channel();  
  73.                 readBuffer.clear();  
  74.                 /*当客户端channel关闭后,会不断收到read事件,但没有消息,即read方法返回-1 
  75.                  * 所以这时服务器端也需要关闭channel,避免无限无效的处理*/                
  76.                 int count = channel.read(readBuffer);  
  77.                    
  78.                 if(count > 0){  
  79.                     //一定需要调用flip函数,否则读取错误数据  
  80.                     readBuffer.flip();  
  81.                     /*使用CharBuffer配合取出正确的数据 
  82.                     String question = new String(readBuffer.array());   
  83.                     可能会出错,因为前面readBuffer.clear();并未真正清理数据 
  84.                     只是重置缓冲区的position, limit, mark, 
  85.                     而readBuffer.array()会返回整个缓冲区的内容。 
  86.                     decode方法只取readBuffer的position到limit数据。 
  87.                     例如,上一次读取到缓冲区的是"where", clear后position为0,limit为 1024, 
  88.                     再次读取“bye"到缓冲区后,position为3,limit不变, 
  89.                     flip后position为0,limit为3,前三个字符被覆盖了,但"re"还存在缓冲区中, 
  90.                     所以 new String(readBuffer.array()) 返回 "byere", 
  91.                     而decode(readBuffer)返回"bye"。             
  92.                     */  
  93.                     CharBuffer charBuffer = CharsetHelper.decode(readBuffer);   
  94.                     String question = charBuffer.toString();   
  95.                     String answer = getAnswer(question);  
  96.                     channel.write(CharsetHelper.encode(CharBuffer.wrap(answer)));  
  97.                 }  
  98.                 else{  
  99.                     //这里关闭channel,因为客户端已经关闭channel或者异常了  
  100.                     channel.close();                 
  101.                 }                        
  102.             }  
  103.         }  
  104.         catch(Throwable t){  
  105.             t.printStackTrace();  
  106.             if(channel != null){  
  107.                 channel.close();  
  108.             }  
  109.         }        
  110.     }  
  111.        
  112.     private String getAnswer(String question){  
  113.         String answer = null;  
  114.            
  115.         switch(question){  
  116.         case "who":  
  117.             answer = "我是小娜\n";  
  118.             break;  
  119.         case "what":  
  120.             answer = "我是来帮你解闷的\n";  
  121.             break;  
  122.         case "where":  
  123.             answer = "我来自外太空\n";  
  124.             break;  
  125.         case "hi":  
  126.             answer = "hello\n";  
  127.             break;  
  128.         case "bye":  
  129.             answer = "88\n";  
  130.             break;  
  131.         default:  
  132.                 answer = "请输入 who, 或者what, 或者where";  
  133.         }  
  134.            
  135.         return answer;  
  136.     }  
  137. }  
package com.stevex.app.nio;
 
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.ClosedChannelException;
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 XiaoNa {
    private ByteBuffer readBuffer;
    private Selector selector;
     
    public static void main(String[] args){
        XiaoNa xiaona = new XiaoNa();
        xiaona.init();
        xiaona.listen();
    }
     
    private void init(){
        readBuffer = ByteBuffer.allocate(1024);
        ServerSocketChannel servSocketChannel;
         
        try {
            servSocketChannel = ServerSocketChannel.open();
            servSocketChannel.configureBlocking(false);
            //绑定端口
            servSocketChannel.socket().bind(new InetSocketAddress(8383));
             
            selector = Selector.open();
            servSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        } catch (IOException e) {
            e.printStackTrace();
        }      
    }
 
    private void listen() {
        while(true){
            try{
                selector.select();             
                Iterator ite = selector.selectedKeys().iterator();
                 
                while(ite.hasNext()){
                    SelectionKey key = (SelectionKey) ite.next();                  
                    ite.remove();//确保不重复处理
                     
                    handleKey(key);
                }
            }
            catch(Throwable t){
                t.printStackTrace();
            }                          
        }              
    }
 
    private void handleKey(SelectionKey key)
            throws IOException, ClosedChannelException {
        SocketChannel channel = null;
         
        try{
            if(key.isAcceptable()){
                ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
                channel = serverChannel.accept();//接受连接请求
                channel.configureBlocking(false);
                channel.register(selector, SelectionKey.OP_READ);
            }
            else if(key.isReadable()){
                channel = (SocketChannel) key.channel();
                readBuffer.clear();
                /*当客户端channel关闭后,会不断收到read事件,但没有消息,即read方法返回-1
                 * 所以这时服务器端也需要关闭channel,避免无限无效的处理*/              
                int count = channel.read(readBuffer);
                 
                if(count > 0){
                    //一定需要调用flip函数,否则读取错误数据
                    readBuffer.flip();
                    /*使用CharBuffer配合取出正确的数据
                    String question = new String(readBuffer.array());  
                    可能会出错,因为前面readBuffer.clear();并未真正清理数据
                    只是重置缓冲区的position, limit, mark,
                    而readBuffer.array()会返回整个缓冲区的内容。
                    decode方法只取readBuffer的position到limit数据。
                    例如,上一次读取到缓冲区的是"where", clear后position为0,limit为 1024,
                    再次读取“bye"到缓冲区后,position为3,limit不变,
                    flip后position为0,limit为3,前三个字符被覆盖了,但"re"还存在缓冲区中,
                    所以 new String(readBuffer.array()) 返回 "byere",
                    而decode(readBuffer)返回"bye"。            
                    */
                    CharBuffer charBuffer = CharsetHelper.decode(readBuffer); 
                    String question = charBuffer.toString(); 
                    String answer = getAnswer(question);
                    channel.write(CharsetHelper.encode(CharBuffer.wrap(answer)));
                }
                else{
                    //这里关闭channel,因为客户端已经关闭channel或者异常了
                    channel.close();               
                }                      
            }
        }
        catch(Throwable t){
            t.printStackTrace();
            if(channel != null){
                channel.close();
            }
        }      
    }
     
    private String getAnswer(String question){
        String answer = null;
         
        switch(question){
        case "who":
            answer = "我是小娜\n";
            break;
        case "what":
            answer = "我是来帮你解闷的\n";
            break;
        case "where":
            answer = "我来自外太空\n";
            break;
        case "hi":
            answer = "hello\n";
            break;
        case "bye":
            answer = "88\n";
            break;
        default:
                answer = "请输入 who, 或者what, 或者where";
        }
         
        return answer;
    }
}

客户端代码:

[java] view plain copy print ?
  1. package com.stevex.app.nio;  
  2.    
  3. import java.io.IOException;  
  4. import java.net.InetSocketAddress;  
  5. import java.nio.ByteBuffer;  
  6. import java.nio.CharBuffer;  
  7. import java.nio.channels.SelectionKey;  
  8. import java.nio.channels.Selector;  
  9. import java.nio.channels.SocketChannel;  
  10. import java.util.Iterator;  
  11. import java.util.Random;  
  12. import java.util.concurrent.ArrayBlockingQueue;  
  13. import java.util.concurrent.BlockingQueue;  
  14. import java.util.concurrent.TimeUnit;  
  15.    
  16.    
  17. public class Client implements Runnable{  
  18.     private BlockingQueue words;  
  19.     private Random random;  
  20.        
  21.     public static void main(String[] args) {        
  22.         //种多个线程发起Socket客户端连接请求  
  23.         for(int i=0; i<10; i++){  
  24.             Client c = new Client();  
  25.             c.init();  
  26.             new Thread(c).start();  
  27.         }        
  28.     }  
  29.    
  30.     @Override  
  31.     public void run() {       
  32.         SocketChannel channel = null;  
  33.         Selector selector = null;  
  34.         try {  
  35.             channel = SocketChannel.open();  
  36.             channel.configureBlocking(false);  
  37.             //请求连接  
  38.             channel.connect(new InetSocketAddress("localhost"8383));  
  39.             selector = Selector.open();  
  40.             channel.register(selector, SelectionKey.OP_CONNECT);  
  41.             boolean isOver = false;  
  42.                
  43.             while(! isOver){  
  44.                 selector.select();  
  45.                 Iterator ite = selector.selectedKeys().iterator();  
  46.                 while(ite.hasNext()){  
  47.                     SelectionKey key = (SelectionKey) ite.next();  
  48.                     ite.remove();  
  49.                        
  50.                     if(key.isConnectable()){  
  51.                         if(channel.isConnectionPending()){  
  52.                             if(channel.finishConnect()){  
  53.                                 //只有当连接成功后才能注册OP_READ事件  
  54.                                 key.interestOps(SelectionKey.OP_READ);  
  55.                                    
  56.                                 channel.write(CharsetHelper.encode(CharBuffer.wrap(getWord())));  
  57.                                 sleep();  
  58.                             }  
  59.                             else{  
  60.                                 key.cancel();  
  61.                             }  
  62.                         }                                                
  63.                     }  
  64.                     else if(key.isReadable()){  
  65.                         ByteBuffer byteBuffer = ByteBuffer.allocate(128);                         
  66.                         channel.read(byteBuffer);  
  67.                         byteBuffer.flip();  
  68.                         CharBuffer charBuffer = CharsetHelper.decode(byteBuffer);  
  69.                         String answer = charBuffer.toString();   
  70.                         System.out.println(Thread.currentThread().getId() + "---" + answer);  
  71.                            
  72.                         String word = getWord();  
  73.                         if(word != null){  
  74.                             channel.write(CharsetHelper.encode(CharBuffer.wrap(word)));  
  75.                         }  
  76.                         else{  
  77.                             isOver = true;  
  78.                         }  
  79.                         sleep();                         
  80.                     }  
  81.                 }  
  82.             }                            
  83.         } catch (IOException e) {  
  84.             e.printStackTrace();  
  85.         }  
  86.         finally{  
  87.             if(channel != null){  
  88.                 try {  
  89.                     channel.close();  
  90.                 } catch (IOException e) {                        
  91.                     e.printStackTrace();  
  92.                 }                    
  93.             }  
  94.                
  95.             if(selector != null){  
  96.                 try {  
  97.                     selector.close();  
  98.                 } catch (IOException e) {  
  99.                     e.printStackTrace();  
  100.                 }  
  101.             }  
  102.         }  
  103.     }  
  104.    
  105.     private void init() {  
  106.         words = new ArrayBlockingQueue(5);  
  107.         try {  
  108.             words.put("hi");  
  109.             words.put("who");  
  110.             words.put("what");  
  111.             words.put("where");  
  112.             words.put("bye");  
  113.         } catch (InterruptedException e) {  
  114.             e.printStackTrace();  
  115.         }    
  116.            
  117.         random = new Random();  
  118.     }  
  119.        
  120.     private String getWord(){  
  121.         return words.poll();  
  122.     }  
  123.    
  124.     private void sleep() {  
  125.         try {  
  126.             TimeUnit.SECONDS.sleep(random.nextInt(3));  
  127.         } catch (InterruptedException e) {  
  128.             e.printStackTrace();  
  129.         }  
  130.     }    
  131.        
  132.     private void sleep(long l) {  
  133.         try {  
  134.             TimeUnit.SECONDS.sleep(l);  
  135.         } catch (InterruptedException e) {  
  136.             e.printStackTrace();  
  137.         }  
  138.     }  
  139. }  
package com.stevex.app.nio;
 
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
 
 
public class Client implements Runnable{
    private BlockingQueue words;
    private Random random;
     
    public static void main(String[] args) {      
        //种多个线程发起Socket客户端连接请求
        for(int i=0; i<10; i++){
            Client c = new Client();
            c.init();
            new Thread(c).start();
        }      
    }
 
    @Override
    public void run() {     
        SocketChannel channel = null;
        Selector selector = null;
        try {
            channel = SocketChannel.open();
            channel.configureBlocking(false);
            //请求连接
            channel.connect(new InetSocketAddress("localhost", 8383));
            selector = Selector.open();
            channel.register(selector, SelectionKey.OP_CONNECT);
            boolean isOver = false;
             
            while(! isOver){
                selector.select();
                Iterator ite = selector.selectedKeys().iterator();
                while(ite.hasNext()){
                    SelectionKey key = (SelectionKey) ite.next();
                    ite.remove();
                     
                    if(key.isConnectable()){
                        if(channel.isConnectionPending()){
                            if(channel.finishConnect()){
                                //只有当连接成功后才能注册OP_READ事件
                                key.interestOps(SelectionKey.OP_READ);
                                 
                                channel.write(CharsetHelper.encode(CharBuffer.wrap(getWord())));
                                sleep();
                            }
                            else{
                                key.cancel();
                            }
                        }                                              
                    }
                    else if(key.isReadable()){
                        ByteBuffer byteBuffer = ByteBuffer.allocate(128);                       
                        channel.read(byteBuffer);
                        byteBuffer.flip();
                        CharBuffer charBuffer = CharsetHelper.decode(byteBuffer);
                        String answer = charBuffer.toString(); 
                        System.out.println(Thread.currentThread().getId() + "---" + answer);
                         
                        String word = getWord();
                        if(word != null){
                            channel.write(CharsetHelper.encode(CharBuffer.wrap(word)));
                        }
                        else{
                            isOver = true;
                        }
                        sleep();                       
                    }
                }
            }                          
        } catch (IOException e) {
            e.printStackTrace();
        }
        finally{
            if(channel != null){
                try {
                    channel.close();
                } catch (IOException e) {                      
                    e.printStackTrace();
                }                  
            }
             
            if(selector != null){
                try {
                    selector.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
 
    private void init() {
        words = new ArrayBlockingQueue(5);
        try {
            words.put("hi");
            words.put("who");
            words.put("what");
            words.put("where");
            words.put("bye");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }  
         
        random = new Random();
    }
     
    private String getWord(){
        return words.poll();
    }
 
    private void sleep() {
        try {
            TimeUnit.SECONDS.sleep(random.nextInt(3));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }  
     
    private void sleep(long l) {
        try {
            TimeUnit.SECONDS.sleep(l);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

你可能感兴趣的:(JavaIO,BIO/NIO/AIO)