• 笔记:Java Socket


    1.阻塞式


    服务器端:
       
        ServerSocketserverSocket = new ServerSocket(8888,10);
        while(true)
        {
           Socket socket= serverSocket.accept();
           Inpustream inpustream =socket.getInpustream();
          Outpustream outpustream = socket.getOutpustream();
           。。。。。
           socket.close();
       } 

    客户端:
        Sockt socket = newSocket("10.1.2.11",8888);
        Inpustream inpustream =socket.getInpustream();
       Outpustream outpustream = socket.getOutpustream();
       。。。。。
       socket.close();

    发生阻塞的地方:
    客户端:
    (1)请求与服务器建立连接时,执行connect方法,进入阻塞状态,直到连接成功
    (2)从输入流读入数据,若无足够数据,进入阻塞,直到读到足够数据或到达末尾
    (3)向输出流写数据,直到写完
    (4)设置了关闭延迟时间,关闭后阻塞

    服务器端:
    (1)执行accept方法,等待客户端连接,进入阻塞,直到收到连接
    (2)输入流读取数据,若没有足够数据,阻塞
    (3)输出流写数据,进入阻塞,直到写完

    多线程处理阻塞的局限
    (1)线程多,开销大,增加JVM调度线程的负担,增加死锁可能性
    (2)线程许多时间浪费在I/O上

    2.非阻塞

    服务器端:

    Selector selector = Selector.open();
    ServerSocketChannel serverSocketChannel =ServerSocketChannel.open();
    serverSocketChannel.socket().setReuseAddress(true);
    serverSocketChannel.configureBlocking(false);
    serverSocketChannel.socket().bind(newInetSocketAddress(8888));
    serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);

    while (selector.select() > 0) {
        Set<<b>SelectionKey>selectedKeys = selector.selectedKeys();
        Iterator iterator =selectedKeys.iterator();
         while(iterator.hasNext()) {
             SelectionKey key =null;
             try {
                key = iterator.next();
                if (key.isAcceptable()) {
                   accept(key, selector);
                } else if (key.isReadable()) {
                   receive(key);
                } else if (key.isWritable()) {
                   send(key);
                }
                iterator.remove();
              } catch(Exception ex) {
                 if (key != null) {
                    try{
                       key.cancel();
                       key.channel().close();
                    } catch (Exception ex2) {}
                   }
               }
             }
           }

      protected void accept(SelectionKeykey, Selector selector) throws IOException {
          ServerSocketChannel serverSocketChannel =(ServerSocketChannel) key.channel();
          SocketChannel socketChannel =serverSocketChannel.accept();
          socketChannel.configureBlocking(false);
          ByteBuffer buffer =ByteBuffer.allocate(1024);
          socketChannel.register(selector,SelectionKey.OP_READ | SelectionKey.OP_WRITE,buffer);
        }

       protected voidreceive(SelectionKey key) throws IOException {
           ByteBuffer buffer = (ByteBuffer)key.attachment();
           SocketChannel channel = (SocketChannel)key.channel();
           ByteBuffer readBuffer =ByteBuffer.allocate(32);
           channel.read(readBuffer);
           readBuffer.flip();
           buffer.limit(buffer.capacity());
           buffer.put(readBuffer);//
          System.out.println(Charset.forName("UTF-8").decode(readBuffer).toString());

        }

    protected void send(SelectionKey key) throws IOException{
           ByteBuffer buffer = (ByteBuffer)key.attachment();
           SocketChannel channel = (SocketChannel)key.channel();
           buffer.flip();
           String data =Charset.forName("UTF-8").decode(buffer).toString();
           if (data.indexOf(" ") == -1) {
              return;
           }
           String str = data.substring(0,data.indexOf(" ") + 1);
           ByteBuffer outBuffer =Charset.forName("UTF-8").encode(" encode: " + str);
           while (outBuffer.hasRemaining()) {
              channel.write(outBuffer);
           }
          buffer.position(Charset.forName("UTF-8").encode(str).limit());
           buffer.compact();
           if ("bye ".equals(str)) {
              key.cancel();
              key.channel().close();
              System.out.println(" close connection ");
           }

        }


    客户端:
    Selector selector= Selector.open();
    SocketChannel socketChannel= SocketChannel.open();
    InetSocketAddress address = newInetSocketAddress(InetAddress.getLocalHost(), 8888);
    socketChannel.connect(address);
    socketChannel.configureBlocking(false);
    socketChannel.register(selector, SelectionKey.OP_READ |SelectionKey.OP_WRITE);

    while (selector.select() > 0) {
        Set<<b>SelectionKey>selectedKeys = selector.selectedKeys();
        Iterator iterator =selectedKeys.iterator();
         while(iterator.hasNext()) {
             SelectionKey key =null;
             try {
                key = iterator.next();
                if (key.isReadable()) {
                   receive(key);
                } else if (key.isWritable()) {
                   send(key);
                }
                iterator.remove();
              } catch(Exception ex) {
                 if (key != null) {
                    try{
                       key.cancel();
                       key.channel().close();
                    } catch (Exception ex2) {}
                   }
               }
             }
           }

    3.非阻塞方式提升性能方式

    java.nio.Buffer 缓冲区提升I/O
    (1)减少实际物理读写次数
    (2)缓冲区内存复用,减少动态分配与回收次数
    主要方法:
    clear()  将极限设置为容量,位置置0
    flip()   将极限设置为位置,位置置0
    rewind() 极限不变,位置置0
    (也就是说,改变的都是极限,位置都置0)

    Selector 轮询方式:
    (1)线程接收客户连接时,若无连接,则立即返回
    (2)线程从输入流读取数据时,若无足够数据,读取现有数据,立即返回
    (3)输出类似

    混用非阻塞和多线程:一个线程用于接收连接,另一个线程用于读取数据和发送数据


  • 相关阅读:
    初识C++
    Linux下死锁的调研
    C语言实现单链表面试题(进阶篇)
    C语言实现单链表面试题(基础篇)
    IPC之—共享内存
    IPC之—信号量
    IPC之—消息队列
    初识多线程
    Mysql5.7安装
    RabbitMQ单节点安装/使用!
  • 原文地址:https://www.cnblogs.com/leeeee/p/7276574.html
Copyright © 2020-2023  润新知