직접 사용 BIO, NIO, AIO 서버

1.BIO

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class BIOServer {

    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(8080);
            while (true){
                Socket socket = serverSocket.accept();
                ReadThread readThread = new ReadThread(socket);
                readThread.start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (serverSocket != null){
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private static class ReadThread extends Thread{
        private Socket socket;

        public ReadThread(Socket socket) {
            this.socket = socket;
        }

        @Override
        public void run() {
            try {
                InputStream in = socket.getInputStream();
                BufferedReader reader = new BufferedReader(new InputStreamReader(in));
                String mes;
                while ((mes = reader.readLine()) != null) {
                    System.out.println(mes);
                }
                socket.close();
            }catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
  • 여기서 볼 수 있듯이 BIO의 서버는 모든 요청에 대한 라인을 만들어야 한다. 만약 요청이 동시에 발생하면 서버 자원이 소모될 수 있다
  • 그런데 왜 스레드 탱크를 사용하지 않습니까?만약 스레드 탱크의 스레드 수량이 유한하다면, 클라이언트가 데이터를 늦게 보내지 않으면, 스레드의 스레드가 모두 막혀서 서버가 마비될 수 있다.따라서 모든 socket에 시간을 제한하는 것이 좋습니다. 시간이 초과되면 socket을 닫는 것이 좋습니다
  • public class BIOServer {
    
        public static void main(String[] args) {
            ServerSocket serverSocket = null;
            try {
                serverSocket = new ServerSocket(8080);
                while (true){
                    Socket socket = serverSocket.accept();
                    socket.setSoTimeout(5000); // 
                    ReadThread readThread = new ReadThread(socket);
                    readThread.start();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                if (serverSocket != null){
                    try {
                        serverSocket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
        private static class ReadThread extends Thread{
            private Socket socket;
    
            public ReadThread(Socket socket) {
                this.socket = socket;
            }
    
            @Override
            public void run() {
                try {
                    InputStream in = socket.getInputStream();
                    BufferedReader reader = new BufferedReader(new InputStreamReader(in));
                    String mes;
                    while ((mes = reader.readLine()) != null) {
                        System.out.println(mes);
                    }
                    System.out.println("xxx");
                    socket.close();
                }catch (SocketTimeoutException e) {
                    System.out.println(" , ....");
                    try {
                        socket.close();
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
        }
    }
    
  • 그러나 더 좋은 해결 방안은 클라이언트가 상응하는 사건이 발생한 후에야 이를 위해 스레드(또는 스레드 탱크에 맡기기)를 만들어 처리하는 것이다. 이렇게 하면 스레드의 수량을 크게 줄이고 자원 소모와 상하문 전환의 비용을 줄일 수 있다
  • 그래서 NIO 기술을 이용해야 한다

  • 2.NIO


    여러 가지 형식이 있습니다. 다음은 Reactor 단일 스레드 모드입니다. 하나의 스레드로 요청을 받고 하나의 스레드로 IO 작업을 수행합니다.
    import java.io.IOException;
    import java.net.InetSocketAddress;
    import java.nio.ByteBuffer;
    import java.nio.channels.*;
    import java.nio.charset.Charset;
    import java.util.Iterator;
    import java.util.Set;
    
    public class NIOServer {
    
        private static final Charset charset = Charset.forName("utf-8");
    
        private static Selector selector ;
    
        static {
            try {
                selector = Selector.open();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        public static void main(String[] args) {
            try {
                ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
                InetSocketAddress address = new InetSocketAddress(8080);
                serverSocketChannel.configureBlocking(false);
                serverSocketChannel.bind(address);
                serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);
                new Reactor().start();
            } catch (IOException e) {
                e.printStackTrace();
            }
    
        }
    
        private static class Reactor extends Thread{
    
            @Override
            public void run() {
                try {
                    select();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
    
            private void select() throws IOException{
                while (selector.select()>0){  // , , CPU 
                    Set selectionKeys = selector.selectedKeys();
                    Iterator iterator = selectionKeys.iterator();
                    while (iterator.hasNext()){
                        SelectionKey key = iterator.next();
                        if (key.isAcceptable()){
                            accept(key);
                        }else if (key.isReadable()){
                            read(key);
                        }
                        iterator.remove();  // ! 
                    }
                }
            }
    
            private void read(SelectionKey key) throws IOException {
                SocketChannel channel = (SocketChannel) key.channel();
                ByteBuffer byteBuffer = ByteBuffer.allocate(100);
                int num = channel.read(byteBuffer);
                if (num > 0) {
                    byteBuffer.flip();
                    String data = charset.decode(byteBuffer).toString();
                    System.out.println(data);
                }else if (num == -1){
                    // num=-1 
                    channel.close();
                }
            }
    
            private void accept(SelectionKey key) throws IOException {
    
                ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
                SocketChannel channel = serverChannel.accept();
                if (channel != null) {
                    InetSocketAddress localAddress = (InetSocketAddress) channel.getLocalAddress();
                    String hostName = localAddress.getHostName();
                    System.out.println(" " + hostName + " ");
    
                    channel.configureBlocking(false);
                    // socket
                    channel.register(selector, SelectionKey.OP_READ);
                }
            }
        }
    }
    
  • 여기서 발생하는 모든 사건을 단일 라인에 맡기고 성능이 부족하면 라인을 열어 사건을 처리할 수 있습니다..

  • 3.AIO

    import java.io.IOException;
    import java.net.InetSocketAddress;
    import java.nio.ByteBuffer;
    import java.nio.channels.AsynchronousServerSocketChannel;
    import java.nio.channels.AsynchronousSocketChannel;
    import java.nio.channels.CompletionHandler;
    
    public class AIOServer {
    
        public void startListen(int port) throws InterruptedException {
            try {
                AsynchronousServerSocketChannel serverSocketChannel = AsynchronousServerSocketChannel.open();
                serverSocketChannel.bind(new InetSocketAddress(port));
                serverSocketChannel.accept(null,new CompletionHandler() {
                    @Override
                    public void completed(AsynchronousSocketChannel socketChannel, Void attachment) {
                        serverSocketChannel.accept(null,this); // , accept 
                        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                        socketChannel.read(byteBuffer,byteBuffer, new CompletionHandler() {
                            @Override
                            public void completed(Integer num, ByteBuffer attachment) {
                                if (num > 0){
                                    attachment.flip();
                                    System.out.println(new String(attachment.array()).trim());
                                }else {
                                    try {
                                        socketChannel.close();
                                    } catch (IOException e) {
                                        e.printStackTrace();
                                    }
                                }
                            }
    
                            @Override
                            public void failed(Throwable exc, ByteBuffer attachment) {
                                System.out.println("read error");
                                exc.printStackTrace();
                            }
                        });
                    }
    
                    @Override
                    public void failed(Throwable exc, Void attachment) {
                        System.out.println("accept error");
                        exc.printStackTrace();
                    }
                });
            } catch (IOException e) {
                e.printStackTrace();
            }
    
    		// 
            while (true){
                Thread.sleep(1000);
            }
        }
    
        public static void main(String[] args) throws InterruptedException {
            AIOServer aioServer = new AIOServer();
            aioServer.startListen(8080);
        }
    }
    

    좋은 웹페이지 즐겨찾기