zoukankan      html  css  js  c++  java
  • Nio Socket 连接

    首先介绍一下几个辅助类
    辅助类SerializableUtil,这个类用来把java对象序列化成字节数组,或者把字节数组反序列化成java对象。
    [java] view plain copy  
    package com.googlecode.garbagecan.test.socket;  
      
    import java.io.ByteArrayInputStream;  
    import java.io.ByteArrayOutputStream;  
    import java.io.IOException;  
    import java.io.ObjectInputStream;  
    import java.io.ObjectOutputStream;  
      
    public class SerializableUtil {  
          
        public static byte[] toBytes(Object object) {  
            ByteArrayOutputStream baos = new ByteArrayOutputStream();  
            ObjectOutputStream oos = null;  
            try {  
                oos = new ObjectOutputStream(baos);  
                oos.writeObject(object);  
                byte[] bytes = baos.toByteArray();  
                return bytes;  
            } catch(IOException ex) {  
                throw new RuntimeException(ex.getMessage(), ex);  
            } finally {  
                try {  
                    oos.close();  
                } catch (Exception e) {}  
            }  
        }  
          
        public static Object toObject(byte[] bytes) {  
            ByteArrayInputStream bais = new ByteArrayInputStream(bytes);  
            ObjectInputStream ois = null;  
            try {  
                ois = new ObjectInputStream(bais);  
                Object object = ois.readObject();  
                return object;  
            } catch(IOException ex) {  
                throw new RuntimeException(ex.getMessage(), ex);  
            } catch(ClassNotFoundException ex) {  
                throw new RuntimeException(ex.getMessage(), ex);  
            } finally {  
                try {  
                    ois.close();  
                } catch (Exception e) {}  
            }  
        }  
    }  
    辅助类MyRequestObject和MyResponseObject,这两个类是普通的java对象,实现了Serializable接口。MyRequestObject类是Client发出的请求,MyResponseObject是Server端作出的响应。
    [java] view plain copy  
    package com.googlecode.garbagecan.test.socket.nio;  
      
    import java.io.Serializable;  
      
    public class MyRequestObject implements Serializable {  
      
        private static final long serialVersionUID = 1L;  
      
        private String name;  
          
        private String value;  
      
        private byte[] bytes;  
          
        public MyRequestObject(String name, String value) {  
            this.name = name;  
            this.value = value;  
            this.bytes = new byte[1024];  
        }  
          
        public String getName() {  
            return name;  
        }  
      
        public void setName(String name) {  
            this.name = name;  
        }  
      
        public String getValue() {  
            return value;  
        }  
      
        public void setValue(String value) {  
            this.value = value;  
        }  
          
        @Override  
        public String toString() {  
            StringBuffer sb = new StringBuffer();  
            sb.append("Request [name: " + name  + ", value: " + value + ", bytes: " + bytes.length+ "]");  
            return sb.toString();  
        }  
    }  
      
    package com.googlecode.garbagecan.test.socket.nio;  
      
    import java.io.Serializable;  
      
    public class MyResponseObject implements Serializable {  
      
        private static final long serialVersionUID = 1L;  
      
        private String name;  
          
        private String value;  
      
        private byte[] bytes;  
          
        public MyResponseObject(String name, String value) {  
            this.name = name;  
            this.value = value;  
            this.bytes = new byte[1024];  
        }  
          
        public String getName() {  
            return name;  
        }  
      
        public void setName(String name) {  
            this.name = name;  
        }  
      
        public String getValue() {  
            return value;  
        }  
      
        public void setValue(String value) {  
            this.value = value;  
        }  
          
        @Override  
        public String toString() {  
            StringBuffer sb = new StringBuffer();  
            sb.append("Response [name: " + name  + ", value: " + value + ", bytes: " + bytes.length+ "]");  
            return sb.toString();  
        }  
    }  
    
    下面主要看一下Server端的代码,其中有一些英文注释对理解代码很有帮助,注释主要是来源jdk的文档和例子,这里就没有再翻译
    [java] view plain copy  
    package com.googlecode.garbagecan.test.socket.nio;  
      
    import java.io.ByteArrayOutputStream;  
    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.ServerSocketChannel;  
    import java.nio.channels.SocketChannel;  
    import java.util.Iterator;  
    import java.util.logging.Level;  
    import java.util.logging.Logger;  
      
    import com.googlecode.garbagecan.test.socket.SerializableUtil;  
      
    public class MyServer3 {  
      
        private final static Logger logger = Logger.getLogger(MyServer3.class.getName());  
          
        public static void main(String[] args) {  
            Selector selector = null;  
            ServerSocketChannel serverSocketChannel = null;  
              
            try {  
                // Selector for incoming time requests  
                selector = Selector.open();  
      
                // Create a new server socket and set to non blocking mode  
                serverSocketChannel = ServerSocketChannel.open();  
                serverSocketChannel.configureBlocking(false);  
                  
                // Bind the server socket to the local host and port  
                serverSocketChannel.socket().setReuseAddress(true);  
                serverSocketChannel.socket().bind(new InetSocketAddress(10000));  
                  
                // Register accepts on the server socket with the selector. This  
                // step tells the selector that the socket wants to be put on the  
                // ready list when accept operations occur, so allowing multiplexed  
                // non-blocking I/O to take place.  
                serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);  
          
                // Here's where everything happens. The select method will  
                // return when any operations registered above have occurred, the  
                // thread has been interrupted, etc.  
                while (selector.select() > 0) {  
                    // Someone is ready for I/O, get the ready keys  
                    Iterator<SelectionKey> it = selector.selectedKeys().iterator();  
          
                    // Walk through the ready keys collection and process date requests.  
                    while (it.hasNext()) {  
                        SelectionKey readyKey = it.next();  
                        it.remove();  
                          
                        // The key indexes into the selector so you  
                        // can retrieve the socket that's ready for I/O  
                        execute((ServerSocketChannel) readyKey.channel());  
                    }  
                }  
            } catch (ClosedChannelException ex) {  
                logger.log(Level.SEVERE, null, ex);  
            } catch (IOException ex) {  
                logger.log(Level.SEVERE, null, ex);  
            } finally {  
                try {  
                    selector.close();  
                } catch(Exception ex) {}  
                try {  
                    serverSocketChannel.close();  
                } catch(Exception ex) {}  
            }  
        }  
      
        private static void execute(ServerSocketChannel serverSocketChannel) throws IOException {  
            SocketChannel socketChannel = null;  
            try {  
                socketChannel = serverSocketChannel.accept();  
                MyRequestObject myRequestObject = receiveData(socketChannel);  
                logger.log(Level.INFO, myRequestObject.toString());  
                  
                MyResponseObject myResponseObject = new MyResponseObject(  
                        "response for " + myRequestObject.getName(),   
                        "response for " + myRequestObject.getValue());  
                sendData(socketChannel, myResponseObject);  
                logger.log(Level.INFO, myResponseObject.toString());  
            } finally {  
                try {  
                    socketChannel.close();  
                } catch(Exception ex) {}  
            }  
        }  
          
        private static MyRequestObject receiveData(SocketChannel socketChannel) throws IOException {  
            MyRequestObject myRequestObject = null;  
            ByteArrayOutputStream baos = new ByteArrayOutputStream();  
            ByteBuffer buffer = ByteBuffer.allocate(1024);  
              
            try {  
                byte[] bytes;  
                int size = 0;  
                while ((size = socketChannel.read(buffer)) >= 0) {  
                    buffer.flip();  
                    bytes = new byte[size];  
                    buffer.get(bytes);  
                    baos.write(bytes);  
                    buffer.clear();  
                }  
                bytes = baos.toByteArray();  
                Object obj = SerializableUtil.toObject(bytes);  
                myRequestObject = (MyRequestObject)obj;  
            } finally {  
                try {  
                    baos.close();  
                } catch(Exception ex) {}  
            }  
            return myRequestObject;  
        }  
      
        private static void sendData(SocketChannel socketChannel, MyResponseObject myResponseObject) throws IOException {  
            byte[] bytes = SerializableUtil.toBytes(myResponseObject);  
            ByteBuffer buffer = ByteBuffer.wrap(bytes);  
            socketChannel.write(buffer);  
        }  
    }  
    下面是Client的代码,代码比较简单就是启动了100个线程来访问Server
    [java] view plain copy  
    package com.googlecode.garbagecan.test.socket.nio;  
      
    import java.io.ByteArrayOutputStream;  
    import java.io.IOException;  
    import java.net.InetSocketAddress;  
    import java.net.SocketAddress;  
    import java.nio.ByteBuffer;  
    import java.nio.channels.SocketChannel;  
    import java.util.logging.Level;  
    import java.util.logging.Logger;  
      
    import com.googlecode.garbagecan.test.socket.SerializableUtil;  
      
    public class MyClient3 {  
      
        private final static Logger logger = Logger.getLogger(MyClient3.class.getName());  
          
        public static void main(String[] args) throws Exception {  
            for (int i = 0; i < 100; i++) {  
                final int idx = i;  
                new Thread(new MyRunnable(idx)).start();  
            }  
        }  
          
        private static final class MyRunnable implements Runnable {  
              
            private final int idx;  
      
            private MyRunnable(int idx) {  
                this.idx = idx;  
            }  
      
            public void run() {  
                SocketChannel socketChannel = null;  
                try {  
                    socketChannel = SocketChannel.open();  
                    SocketAddress socketAddress = new InetSocketAddress("localhost", 10000);  
                    socketChannel.connect(socketAddress);  
      
                    MyRequestObject myRequestObject = new MyRequestObject("request_" + idx, "request_" + idx);  
                    logger.log(Level.INFO, myRequestObject.toString());  
                    sendData(socketChannel, myRequestObject);  
                      
                    MyResponseObject myResponseObject = receiveData(socketChannel);  
                    logger.log(Level.INFO, myResponseObject.toString());  
                } catch (Exception ex) {  
                    logger.log(Level.SEVERE, null, ex);  
                } finally {  
                    try {  
                        socketChannel.close();  
                    } catch(Exception ex) {}  
                }  
            }  
      
            private void sendData(SocketChannel socketChannel, MyRequestObject myRequestObject) throws IOException {  
                byte[] bytes = SerializableUtil.toBytes(myRequestObject);  
                ByteBuffer buffer = ByteBuffer.wrap(bytes);  
                socketChannel.write(buffer);  
                socketChannel.socket().shutdownOutput();  
            }  
      
            private MyResponseObject receiveData(SocketChannel socketChannel) throws IOException {  
                MyResponseObject myResponseObject = null;  
                ByteArrayOutputStream baos = new ByteArrayOutputStream();  
                  
                try {  
                    ByteBuffer buffer = ByteBuffer.allocateDirect(1024);  
                    byte[] bytes;  
                    int count = 0;  
                    while ((count = socketChannel.read(buffer)) >= 0) {  
                        buffer.flip();  
                        bytes = new byte[count];  
                        buffer.get(bytes);  
                        baos.write(bytes);  
                        buffer.clear();  
                    }  
                    bytes = baos.toByteArray();  
                    Object obj = SerializableUtil.toObject(bytes);  
                    myResponseObject = (MyResponseObject) obj;  
                    socketChannel.socket().shutdownInput();  
                } finally {  
                    try {  
                        baos.close();  
                    } catch(Exception ex) {}  
                }  
                return myResponseObject;  
            }  
        }  
    }  
    
    最后测试上面的代码,首先运行Server类,然后运行Client类,就可以分别在Server端和Client端控制台看到发送或接收到的MyRequestObject或MyResponseObject对象了。
    
    关于NIO和IO的比较,下面的两篇文章对理解很有帮助,可以参考一下。
    http://tutorials.jenkov.com/java-nio/nio-vs-io.html
    https://blogs.oracle.com/slc/entry/javanio_vs_javaio
  • 相关阅读:
    Oracle中常用的to_Char用法详解(有FMT的详细列表)
    js底层ajax
    MD5加密
    "<br />"和 "\r\n" 这两者有什么区别??
    SqlHelper类
    treeview实例
    在标题栏显示新消息提示,很多公司项目中用到这个方法
    SQL一些时间格式的转换
    用SQL语句添加删除修改字段、一些表与字段的基本操作、数据库备份等
    SQL Server触发器创建、删除、修改、查看示例步骤
  • 原文地址:https://www.cnblogs.com/xiaolei2017/p/9619067.html
Copyright © 2011-2022 走看看