티스토리 뷰

Skill/Programming - Network

2. 스트림 (Stream)

gyulee0220 2019. 3. 3. 15:28

  네트워크 프로그래밍에서 제일 중요한 요소 중 하나가 바로 입출력(I/O)이다. 우리가 사용하는 네트워크는 앞서 본대로 총 7개의 계층 사이에서 데이터의 송수신을 의미한다. 그렇기 때문에 네트워크 프로그래밍을 하기 위해선 해당 프로그램의 입출력에 대해 완벽하게 알고 있어야 한다. 이전에도 한번 소개를 한 적이 있었지만, 다시 한번 Java의 입출력에 대해서 알아 볼 것이고. 대표적인 입출력 방식인 스트림을 기반으로 알아 볼 것이다. 만약 Java가 아닌 다른 언어로 네트워킹 프로그램을 만들어야 하는 사람들에게 이번 글을 그리 중요하지 않을 것이다.



  





  1. 출력 스트림

  자바에서 사용하는 최상위 스트림 클래스는 java.io.OutputStream이다. 그리고 이 클래스는 위에 보이는 서브클래스들을 갖고 있다. 이름만 보아도 직관적으로 알 수 있듯이 FileOutputStream은 파일을 받을 수 있는 출력스트림이고, ObjectOutputStream은 객체를 뱉어내는 출력스트림이다. 그리고 OutputStream은 3가지 method를 지닌다.

- write() : int형 혹은 byte[] 형으로 데이터를 읽는 메소드
- flush() : Java 버퍼 내에 존재하는 데이터를 강제로 전송하는 메소드
- close() :  스트림을 종료시키는 메소드

  다른 두 메소드는 이미 java문법에 대해 공부한 사람이라면 쉽게 이해할 수 있겠지만 flush 메소드의 사용은 다소 의문이 들 수 있다. Java는 친절하게도 자체적으로 버퍼를 제공한다. 즉, 우리가 스트림을 통해 데이터를 보내게 된다면, 효율적인 전송을 위해 버퍼에 데이터가 모두 쌓일때까지 기다렸다가 전송하게 된다. 하지만, 전송하려는 데이터의 크기가 버퍼의 크기보다 작은 경우가 발생한다면 JVM은 전송하기에 데이터가 충분히 크지 않아 다음 데이터가 올때까지 계속 기다리게 된다. 이 현상을 방지하도록 버퍼의 데이터를 강제로 보내는 작업을 하는 것이 flush 메소드이다. 

  Java 콘솔을 통해 입력한 정보를 텍스트 파일로 만드는 작업을 해보자. 네트워크를 통해 들어온 데이터를 보기 위한 마지막 단계가 될 것이다. 콘솔로 입력하는 정보를 텍스트 파일로 만드는 코드는 아래와 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Scanner;
 
public class Soiution {
 
    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
 
        Scanner sc = new Scanner(System.in);
        String input = sc.nextLine();
        char[] CharInput = input.toCharArray();
        
        try {
            OutputStream out = new FileOutputStream("output.txt");
            getCharacters(out,CharInput);
            out.close();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }
    
    public static void getCharacters(OutputStream outchar[] input) throws IOException{
        
        byte[] line = new byte[100]; // size 100
        
        for(int i=0; i<input.length; i++){
                
            line[i]=(byte) input[i];
            
        }
        
        out.write(line);
        System.out.print(line);
 
    }
 
}
cs



2. 입력 스트림

  이제 네트워크를 통해 파일을 보내는 첫 단계를 살펴보자. 내가 만든파일을 네트워크에 보내기 위해서 응용계층의 첫 단계 프로그램으로 데이터를 올리는 것이다. Java에서 기본 입력 클래스는 InputStream이다. 그리고 이 클래스는 아래와 같은 메소드를 가지고 있다.

- read() : 입력 파일을 읽어내는 메소드
- skip() : 일부 데이터를 읽지 않고 건너 뛰는 메소드
- available() : 데이터를 모두 읽을 때까지 기다리지 않고, 바로 읽을 수 있는 바이트 수를 반환하는 메소드

- close() : InputStream을 종료시키는 메소드


  앞에서 Java가 버퍼로 동작한다는 것을 이해했다면 위의 메소드들을 쉽게 이해가 될 것이다. skip의 경우 프로그램 상에서 일부 데이터 전송을 원하지 않는다면 오버라이딩 작업을 통해 쉽게 누락 시킬 데이터와 보낼 데이터를 구성할 수 있다. 또한, Available()을 사용하면 입력스트림이 기다림 없이 바로 읽을 수 있는 최소 바이트수를 얻어 데이터 손실이 적은 프로그램을 만들 수 있다. 두 메소드 모두 네트워크 프로그래밍에서 크게 쓸 일은 없는 작업이다.


  이번엔 파일을 읽어 Java 콘솔로 출력되는 프로그램을 만들어보자.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import java.io.FileNotFoundException;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;
 
public class Soiution {
 
    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        
        try {
            InputStream in = new FileInputStream("output.txt");
            getCharacters(in);
            in.close();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }
    
    public static void getCharacters(InputStream inthrows IOException{
        
        byte line; // size 100
        int i = 0;
        
        while(in.read()!=-1){
            int a = in.read();
            line = (byte) a;
            System.out.print(line);
            i++;
        }
        
    }
 
}
 

cs


  이 프로그램을 실행시킨다면 출력 값이 아스키 코드로 나오는 것을 확인 할 수 있다. 우리는 네트워크 프로그램을 통해 아스키 코드로 작성된 데이터를 네트워크 환경으로 올리게 된다.


3. Reader, Writer 클래스

  앞서 살펴본바와 같이 Java의 스트림 입출력 클래스는 기본적으로 아스키 코드 기반의 바이트 형식을 따른다. 결국 이 두 클래스의 기능을 간단히 표현하자면 우리가 사용하는 일반 언어를 네트워크에서 전송할 수 있는 아스키 코드로 변환하는 작업이다. 이 역할을 하는 메소드가 read와 write이다. 우리는 변수의 타입만 잘 지정해준다면 쉽게 데이터를 전송할 수 있게된다.

  그러나 Java는 놀랍게도 이것보다도 더 간편한 클래스를 통해 우리가 데이터 변환에 대해 전혀 상관하지 않고도 자연어를 전송 가능한 언어로 바꿔주는 클래스가 존재한다. 우리가 앞서 스트림에서 사용한 데이터 변환 작업 조차 수행하지 않고도 자동적으로 데이터를 읽고, 쓸 수 있게 되었다. 이 기능을 하는 두 클래스가 바로 Reader, Writer이다. 아마 Java를 한번이라도 배웠던 사람이라면, Println() 메소드를 사용해 본적이 있을 것이다, 이 메소드가 바로 Writer 클래스에서 작동하는 메소드이다. 


  Reader와 Writer를 사용한다면 아래와 같이 더욱 쉽게 입출력을 구현 할 수 있다.  



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
 
public class Soiution {
 
    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        
        Reader w = new FileReader("input.txt");
        StringBuilder sb = new StringBuilder();
        int c;
        while((c = w.read())!= -1){
            sb.append((char) c);
        }
        System.out.println(sb);
        w.close();
    }
 
}
 
cs




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
 
public class Soiution {
 
    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        
        Writer w = new FileWriter("output.txt");
        w.write("Network");
        w.close();
    }
 
}
 
cs


'Skill > Programming - Network' 카테고리의 다른 글

6. 스레드 폴링, 콜백  (0) 2019.05.07
5. 스레드(Thread)  (0) 2019.04.27
4. 프로세스 관리 (Process Control)  (1) 2019.04.07
3. 프로세스(Process)  (0) 2019.03.27
1. OSI 7계층  (1) 2019.02.17
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함