ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 소켓 통신 I/O Stream
    Java 2020. 5. 7. 14:48

     

    I/O Stream

    Stream : 연속적으로 단방향으로 흘러가는 것을 의미하며, 데이터는 출발지에서 나와 도착지로 흘러간다는 개념이다.

    스트림 통신은 단방향 통신을 하기에 하나의 스트림으로 입출력 동시에 할 수가없다...

    그렇기에 데이터를 보낼때에는 OutputStream 을 사용한다.

    그렇기에 데이터를 받을때에는 InputStream 을 사용한다.

     

    java.io 패키지

    파일 시스템의 정보를 얻기 위한 File클래스와 데이터 입출력을 하기위한 I/O Stream 클래스가 제공된다.

    바이트 단위 입출력 스트림 : 그림, 멀티미디어, 문자등 모든 종류의 데이터들을 주고 받을 수 있다.

    문자 단위 입출력 스트림 : 오로지 문자만 주고받을 수 있게 특화 되어있다.

    Java.io 패키지의 주요 클래스 설명
    File 파일 시스템의 파일 정보를 얻기 위한 클래스
    Console 콘솔로부터 문자를 입출력하기 위한 클래스
    InputStream / OutputStream 바이트 단위 입출력을 위한 최상위 입출력 스트림 클래스
    FileInputStream / FileOutputStream 바이트 단위 입출력을 위한 하위 스트림 클래스
    DataInputStream / DataOutputStream
    ObjectInputStream / ObjectOutputStream
    PrintStream
    BufferedInputStream / BufferedOutputStream
    Reader / Writer 문자 단위 입출력을 위한 최상위 입출력 스트림 클래스
    FileReader / FileWriter 문자 단위 입출력을 위한 하위 스트림 클래스
    InputStreamReader / OutputStreamWriter
    PrinterWriter
    BufferedReader / BufferedWriter

     

    InputStream

    바이트 기반 입력 스트림의 최상위 클래스이다. ( 추상클래스 )

    모든 바이트 기반 입력 스트림은 이 클래스를 상속받아서 만들어진다.

     

    InputStream 클래스에는 바이트 기반 입력 스트림이 기본적으로 가져야 할 메소드

    메소드 설명
    int available() 현재 읽을 수 있는 바이트 수를 반환한다.
    void close() 현재 열려있는 InputStream을 닫는다
    void mark(int readlimit) InputStream에서 현재의 위치를 표시해준다
    boolean markSupported() 해당 InputStream에서 mark()로 지정된 지점이 있는지에 대한 여부를 확인한다
    abstract int read() InputStream에서 한 바이트를 읽어서 int값으로 반환한다
    int read(byte[] b) byte[] b 만큼의 데이터를 읽어서 b에 저장하고 읽은 바이트 수를 반환한다
    int read(byte[] b, int off, int len) len만큼 읽어서 byte[] b의 off위치에 저장하고 읽은 바이트 수를 반환한다
    void reset() mark()를 마지막으로 호출한 위치로 이동
    long skip(long n) InputStream에서 n바이트만큼 데이터를 스킵하고 바이트 수를 반환한다

     

    OutputStream

    바이트 기반 출력 스트림의 최상위 클래스이다. ( 추상클래스 )

    모든 바이트 기반 출력 스트림 클래스는 이 클래스를 상속받아서 만들어져있다.

    flush() 는 출력 스트림과 버퍼된 출력 바이트를 강제로 쓰게하여 데드락 현상을 방지시켜준다.

     

    OutputStream 클래스에서 모든 바이트 기반 출력 스트림이 기본적으로 가져야할 메소드

    메소드 설명
    void close() OutputStream을 닫는다
    void flush() 버퍼에 남아있는 출력 스트림을 출력한다
    void write(byte[] b) 버퍼의 내용을 출력한다
    void write(byte[] b, int off, int len) b배열 안에 있는 시작 off부터 len만큼 출력한다
    abstract void write(int b) 정수 b의 하위 1바이트를 출력한다

     

    짱좋은 참고 블로그 : https://develop-im.tistory.com/54


    1. Server

    server코드 같은경우는 평범한 Thread 환경으로 Client가 접속하길 기다리며 접속시 byte 배열을 받는 과정

     

    public class TCPServerSocket {
        public static void main(String[] args) {
            try {
                ServerSocket serverSocket = new ServerSocket(8000);
                while(true) {
                    System.out.println("waiting for connect...");
                    Socket socket = serverSocket.accept();
                    System.out.println("client info " + socket.getInetAddress() + ", port: " + socket.getPort());
                    new ServerThread(socket).start();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        static class ServerThread extends Thread {
    
            private Socket socket;
    
            public ServerThread(Socket socket) {
                this.socket = socket;
            }
    
            @Override
            public void run() {
                try {
                        OutputStream outputStream = socket.getOutputStream();
                        InputStream inputStream = socket.getInputStream();                    
    
                        byte[] buffer = new byte[4];
                        inputStream.read(buffer);
                        ByteBuffer data = ByteBuffer.wrap(buffer);
                        data.order(ByteOrder.LITTLE_ENDIAN);
                        int size = data.getInt();
                        byte[] bytes = new byte[size];
                        inputStream.read(bytes);
                        
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    2. Client

    Client 코드에서는 동작을 시키면 서버로 연결하여 byte 배열을 보내는과정

    public class ClientSocket {
        public static void main(String[] args) {
    
            String message ;
            InetAddress inetAddress;
    
            try {
                InetSocketAddress socketAddress = new InetSocketAddress("127.0.0.1", 8000);
    
                Socket socket = new Socket();
                socket.connect(socketAddress);
    
                OutputStream outputStream = socket.getOutputStream();
                InputStream inputStream = socket.getInputStream();
    
                byte[] test = new byte[4];
                byte[] abc = new byte[52];
                
                test[3] = (byte)(52 >> 24);
                test[2] = (byte)(52 >> 16);
                test[1] = (byte)(52 >> 8);
                test[0] = (byte)(52);
    
                outputStream.write(test);
                outputStream.write(abc);
                outputStream.flush();
    
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    Client 코드에서 정보를 전송을 할때 데이터 정보의 크기의 정보를 BIG_ENDIAN으로 바이트 오더링 후 전송한다

      -> 네트워크 통신은 데이터를 BIG_ENDIAN으로 오더링 후 전송한다.

    Server 코드에서 정보를 수신할때 데이터 정보의 크기를 LITTLE_ENDIAN으로 오더링 후 읽는다.

      -> CPU의 따라 오더링 방식이 다르다.

     

    ENDIAN 특징 및 정리

    바이트 오더는 데이터가 바이트 단위로 메모리에 저장되는 순서를 의미하며, 각 CPU 벤더 의존적은 특징을 지니고 있다.

    크게 BIG_ENDIAN을 사용하는 AMD CPU, LITTLE_ENDIAN을 사용하는 Intel CPU 가 존재한다. 이기종 간 톡신을 하는 네트워크 프로그래밍에는 두종간 올바른 통신을 하기 위해서는 통일된 방식이 필요한데 네트워크 바이트 오더링 표준은 BIG_ENDIAN 방식이다. 그렇기에 데이터를 전송할때에는 원칙으로는 BIG_ENDIAN으로 전송하고 각자 CPU에 맞는 ENDIAN으로 변환 후 읽어들이면 된다.

    * 바이트 오더는 2바이트 이상의 프리미티브 타입에 적용되는 내용이다. 1바이트 단위의 문자열 데이터는 바이트 오더의 변경이 불필요함

    * 프리미티브타입 ( 기본형 ) : 총 8가지 기본형 타입을 미리 정의하여 제공되며 기본값이 있어 Null이 존재하지 않는다. 만약 기본 타입에 Null 을 넣고 싶으면 래퍼 클래스를 활용하면 된다. 추가로 실제 값을 저장하는 공간으로 스택 메모리에 저장된다.

    프리미티브 타입 참고 블로그 : https://gbsb.tistory.com/6

    ENDIAN 참고 블로그 : https://hiddenviewer.tistory.com/78

     


    BIG_ENDIAN <--> LITTLE_ENDIAN 변환 관련 예제 : https://zion830.tistory.com/39

     

     

    'Java' 카테고리의 다른 글

    메서드 메모리관리  (0) 2020.06.17
    jMeter 사용하기 (with MQTT)  (2) 2020.05.12
    JNI 사용하여 Native Method를 가동시켜 HelloWorld를 찍기  (0) 2020.04.24
    JNI란?  (0) 2020.04.23
    JVM 이란?  (0) 2020.04.22

    댓글

Designed by Tistory.