【学习笔记】Socket NIO demo

来源:互联网 发布:安装 SQL 2014 编辑:程序博客网 时间:2024/05/17 01:04
模拟场景
客户端请求连接服务端,并发送消息,服务端收到消息后返回信息给客户端,当客户端关闭时,服务端停止socketChannel,
当服务端关闭时,客户端也相应关闭
服务端
package nio;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.util.Iterator;import java.util.Set;/** * Created by zansha on 17/10/19. */public class TCPServer {    // 缓冲区大小    private static final int BufferSize = 1024;    // 超时时间,单位毫秒    private static final int TimeOut = 3000;    // 本地监听端口    private static final int ListenPort = 1978;    public static void main(String[] args) throws IOException, InterruptedException {        Selector selector = Selector.open();        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();        serverSocketChannel.socket().bind(new InetSocketAddress(ListenPort));        serverSocketChannel.configureBlocking(false);        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);        TCPProtocol protocol = new TCPProtocolImpl(BufferSize);        while (true){            int keys = selector.select(TimeOut);            if (keys==0){                continue;            }            Set<SelectionKey> selectionKeySet = selector.selectedKeys();            Iterator<SelectionKey> selectionKeys = selectionKeySet.iterator();            while (selectionKeys.hasNext()){                SelectionKey selectionKey = selectionKeys.next();                selectionKeys.remove();                try {                    if (selectionKey.isAcceptable()){                        System.out.println("acceptable op....");                        protocol.handleAccept(selectionKey);                    }                    // 从客户端读取数据                    if (selectionKey.isReadable()){                        protocol.handleRead(selectionKey);                    }                }catch (Exception e){                    if (selectionKey!=null){                        selectionKey.cancel();                        if (selectionKey.channel()!=null){                            selectionKey.channel().close();                        }                    }                }            }        }    }}

package nio;import java.io.IOException;import java.nio.channels.SelectionKey;/** * Created by zansha on 17/10/19. */public interface TCPProtocol {    /**     * 接收一个SocketChannel的处理     *     * @param key     * @throws IOException     */    void handleAccept(SelectionKey key) throws IOException;    /**     * 从一个SocketChannel读取信息的处理     *     * @param key     * @throws IOException     */    void handleRead(SelectionKey key) throws IOException;    /**     * 向一个SocketChannel写入信息的处理     *     * @param key     * @throws IOException     */    void handleWrite(SelectionKey key) throws IOException;}

package nio;import java.io.IOException;import java.nio.ByteBuffer;import java.nio.channels.SelectionKey;import java.nio.channels.ServerSocketChannel;import java.nio.channels.SocketChannel;import java.nio.charset.Charset;import java.text.SimpleDateFormat;import java.util.Date;import java.util.LinkedHashMap;/** * Created by zansha on 17/10/19. */public class TCPProtocolImpl implements TCPProtocol {    private int bufferSize;    public TCPProtocolImpl(int bufferSize) {        this.bufferSize = bufferSize;    }    /**     * 将可连接 调整为 可读取     */    public void handleAccept(SelectionKey key) throws IOException {        SocketChannel clientChannel = ((ServerSocketChannel) key.channel()).accept();        clientChannel.configureBlocking(false);        clientChannel.register(key.selector(), SelectionKey.OP_READ, ByteBuffer.allocate(bufferSize));    }    public void handleRead(SelectionKey key) throws IOException {        // 获得与客户端通信的信道        SocketChannel clientChannel = (SocketChannel) key.channel();        // 得到并清空缓冲区        ByteBuffer buffer = (ByteBuffer) key.attachment();        buffer.clear();        // 读取信息获得读取的字节数        long bytesRead = clientChannel.read(buffer);        if (bytesRead == -1) {            // 没有读取到内容的情况            clientChannel.close();        } else {            // 将缓冲区准备为数据传出状态            buffer.flip();            // 将字节转化为为UTF-16的字符串            String receivedString = Charset.forName("UTF-16").newDecoder().decode(buffer).toString();            // 控制台打印出来            System.out.println("客户端信息:" + receivedString);            // 准备发送的文本            String sendString = "服务端消息:已收到消息"+receivedString;            buffer = ByteBuffer.wrap(sendString.getBytes("UTF-16"));            clientChannel.write(buffer);            // 设置为下一次读取或是写入做准备            key.interestOps(SelectionKey.OP_READ);        }    }    public void handleWrite(SelectionKey key) throws IOException {    }}

客户端
package nio;import java.io.IOException;import java.io.UnsupportedEncodingException;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;/** * Created by zansha on 17/10/19. */public class TCPClient {    //信道选择器    private Selector selector;    // 与服务器通信的信道    SocketChannel socketChannel;    // 要连接的服务器Ip地址    private String hostIp;    // 要连接的远程服务器在监听的端口    private int hostListenningPort;    /**     * 构造函数     *     * @param HostIp     * @param HostListenningPort     * @throws IOException     */    public TCPClient(String HostIp, int HostListenningPort) throws IOException {        this.hostIp = HostIp;        this.hostListenningPort = HostListenningPort;        initialize();    }    /**     * 初始化     *     * @throws IOException     */    private void initialize() throws IOException {        // 打开监听信道并设置为非阻塞模式        socketChannel = SocketChannel.open(new InetSocketAddress(hostIp, hostListenningPort));        socketChannel.configureBlocking(false);        // 打开并注册选择器到信道        selector = Selector.open();        socketChannel.register(selector,SelectionKey.OP_READ);        // 启动读取线程        TCPClientReadThread tcpClientReadThread = new TCPClientReadThread(selector);        new Thread(tcpClientReadThread).start();    }    /**     * 发送字符串到服务器     *     * @param message     * @throws IOException     */    public void sendMsg(String message) throws IOException{        ByteBuffer writeBuffer;        try {            Thread.sleep(2000);            writeBuffer = ByteBuffer.wrap(message.getBytes("UTF-16"));            socketChannel.write(writeBuffer);            socketChannel.register(selector,SelectionKey.OP_READ);        } catch (InterruptedException e) {            e.printStackTrace();        }catch (UnsupportedEncodingException e) {            e.printStackTrace();        }    }    public static void main(String[] args) throws IOException {        TCPClient client = new TCPClient("localhost", 1978);        for(int i=0; i<50; i++){            try {                client.sendMsg("Nio" + i);            } catch (IOException e) {                break;            }        }        System.out.println("客户端发信息结束");        TCPClientReadThread.run=false;    }}

package nio;import java.io.IOException;import java.nio.ByteBuffer;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.SocketChannel;import java.nio.charset.Charset;import java.util.Iterator;import java.util.Set;import java.util.concurrent.atomic.AtomicBoolean;/** * Created by zansha on 17/10/19. */public class TCPClientReadThread implements Runnable {    private Selector selector;    public static boolean run = true;    public TCPClientReadThread(Selector selector) {        this.selector = selector;    }    @Override    public void run() {        while (run){            try {                int keys = selector.select(3000);                if (keys==0){                    continue;                }                Set<SelectionKey> selectionKeySet = selector.selectedKeys();                Iterator<SelectionKey> selectionKeys = selectionKeySet.iterator();                while (selectionKeys.hasNext()) {                    SelectionKey selectionKey = selectionKeys.next();                        selector.selectedKeys().remove(selectionKey);                        if (selectionKey.isReadable()) {                            SocketChannel socketChannel = (SocketChannel) selectionKey.channel();                            ByteBuffer buffer = ByteBuffer.allocate(1024);                            long bytesRead = socketChannel.read(buffer);                            if (bytesRead==-1){                                socketChannel.close();                            }else {                                buffer.flip();                                // 将字节转化为为UTF-16的字符串                                String receivedString = Charset.forName("UTF-16").newDecoder().decode(buffer).toString();                                // 控制台打印出来                                System.out.println(receivedString);                                // 为下一次读取作准备                                selectionKey.interestOps(SelectionKey.OP_READ);                            }                        }                }            } catch (IOException ex) {                try {                    selector.close();                    break;                } catch (IOException e) {                    e.printStackTrace();                }            }        }        System.out.println("客户端关闭");    }}

原创粉丝点击