![051_입출력 스트림과 통신의 기본](https://inblog.ai/_next/image?url=https%3A%2F%2Finblog.ai%2Fapi%2Fog%3Ftitle%3D051_%25EC%259E%2585%25EC%25B6%259C%25EB%25A0%25A5%2520%25EC%258A%25A4%25ED%258A%25B8%25EB%25A6%25BC%25EA%25B3%25BC%2520%25ED%2586%25B5%25EC%258B%25A0%25EC%259D%2598%2520%25EA%25B8%25B0%25EB%25B3%25B8%26logoUrl%3Dhttps%253A%252F%252Finblog.ai%252Finblog_logo.png%26blogTitle%3Dchodong&w=1920&q=75)
Contents
스트림(Stream) : 끝이 없는 바이트 저장 공간 → 물이 흐르는 개울
그렇다면 어떤 스트림으로 통신의 입출력(Application → OS)을 수행 할까? 정답은 바이트 스트림(Byte Stream, 8비트의 바이트 단위로 입출력하는 스트림) 이다!
일단 입출력 스트림을 알기 위해서는 통신의 기본을 아는 것이 중요하다!
통신의 기본
통신을 하게 되면 기본적으로 “애플리케이션(Application) → OS → H/W“ 순서로 진행이 된다.
그렇다면, 애플리케이션에서 입력한 정보를 어떻게 OS와 H/W 순서로 넘길까?
일단 애플리케이션에서 OS로 넘길 때는 “파일(소켓)”을 이용한다!
그렇다면 “파일(소켓)”은 무엇인가?
소켓은 애플리케이션과 OS의 관계에서 데이터의 흐름을 제어하는 역할을 한다!
→ 이때 데이터를 받거나 보내는 역할도 한다!
큰 의미에선 “파일”(내부) 이라 부르고, 통신할 땐 “소켓”(외부) 이라 부른다.
이제부터는 소켓이라 언급하겠다!
“애플리케이션 → 소켓 → OS” 순으로 결국에는 데이터가 넘어간다.
이때 서로에게 가기 위해 지나가는 통로를 “스트림(Stream)” 이라 한다.
애플리케이션과 소켓이 연결 될 때의 과정의 스트림은 “바이트 스트림”이다!
스트림을 통해 지나가는데 만약 “A, B, C”를 보내면 위의 경로에서 소켓에 “A, B, C” 모두가 저장 되는 것이 아닌 소켓의 크기에 따라 저장이 된다.
이로 인해 “A”가 소켓에 있을 시 “B, C”가 저장될 공간이 없어 “B, C”는 소멸하게 되는데,
결국에는 마지막에 보내지는 데이터는 “A”만 남게 된다.
위의 문제를 해결하기 위해 애플리케이션에서 소켓으로 넘어가기 전 데이터가 대기 하는 공간을 만들어야 하는데 (넘어가기 전 데이터를 저장할 공간) 이를! “보조 스트림(버퍼)”라고 한다!
버퍼
→ 버퍼는 소비가 공급보다 많을 때 또는 적을 때 필요하다.
또한, 버퍼는 임의로 사이즈를 지정이 가능하며, 입출력에서는 2가지를 알고 있으면 된다!
2 가지는 바로! 쓰기 버퍼(Writer Bffer), 읽기 버퍼(Read Bffer) 이다!
쓰기 버퍼는 “애플리케이션”에서, 읽기 버퍼는 “OS”에서 사용 된다.
→ 이런 버퍼를 통해 입력한 모든 정보를 읽는 것 또는 보내는 것이 가능해진다!
OS는 프로세스(애플리케이션, 프로그램)마다 보조 스트림을 가진다!
이로 인해 OS는 소켓에서 데이터를 받기 전 보조 스트림을 거쳐 받는다!
하지만 버퍼의 데이터를 넘길 때 버퍼의 할당한 공간이 꽉 차지 않는다면?
→ 이런 경우 OS는 데이터를 가져가지 않는다!
쉽게 말해, 소켓이 소비되지 않는다!
이걸 해결 하기 위해서는 강제로 흘러가게 만들어야 하는데!
→ 이를 “flush(플러쉬)”로 해결한다!
플러쉬를 하면 모든 스트림이 열린다고 보면 된다!
이러한 정보를 알고 통신의 형태를 다시 보자!
이렇게 통신의 흐름을 알게 되었는데 실제로 통신을 할 때는 서로 어떻게 응답을 해야할까?
위의 물음은 통신을 하기 위해서는 서로 주고 받아 졌는지 확인하는 “응답”에 대해서 말하고 있다.
A와 B가 통신을 할 때, A가 데이터를 보내면, B는 받은 걸 확인 하고 확인을 알려주고, A는 다시 B에게 확인 했다는걸 확인 했다는 정보를 주고 받아야 한다. A → B (데이터 전달) / B → A (데이터 확인) / A → B (확인 정보 확인)
위의 A와 B는 기본적인 통신의 형태인데 이를 “3 Way HandShake” 라고 한다.
→ 프로그램에선 “TCP 통신”이 속한다.
위의 예시와는 반대로 A만 B에게 일방적으로 통신하는 것을 프로그램에선 “UDP 통신”이라 한다.
그럼 “TCP 통신”과 “UDP 통신”은 어떤 경우에 사용할까?
UDP 통신은 동영상 스트리밍, 전화 등 실시간이며 속도가 중요한 경우 많이 사용한다
→ 사용이 가능한 이유는?
→ 인간에게 보낼 때만 가능하다고 볼 수 있는데
이는 인간은 추측해서 알아 듣는 것이 가능해서 이다!
그럼 TCP통신은?
→ UDP 통신이 아닌 대부분의 모든 통신에 가능하다! (실시간이 아닌 경우)
이로 인해 UDP 통신은 신뢰성 없는 통신, TCP 통신은 신뢰성 있는 통신이라 할 수 있다.
위의 통신은 1대1의 경우인데 많은 인원들이 통신 하는 경우에는 어떻게 될까?
→ 일단! 용어부터 알아보면 “서킷 스위칭(circuit switching)”이다!
많은 인원이 통신 하기 전! 통신을 하기 위해서는 컴퓨터들 끼리 묶여 있는데 서로 다이렉트가 아닌 사이사이의 많은 “라우터 (router)” 들이 존재한다!
→ 라우터는 역할 패킷 포워드 장치 (패킷 전송 장치 → 패킷을 받아서 전송) 이다.
→ 라우터는 H/W이며 서로의 데이터를 주고 받는 중간 역할을 한다!
라우터에 대해 알았으니 이제 간단히 A → B 컴퓨터가 통신을 할 때 중간에 라우터가 낀 예시를 보자!
→ ex) A → 라우터 → 라우터 → B 의 형태이다!
만약 A 컴퓨터에서 “abcd”라는 문자열을 전송하고 싶다면?
일단 소켓에서 “abcd”는 “a”, “b”, “c”, “d” 로 나눠 진다!
→ 이 과정을 “세그먼트(segment)” 라고 한다.
→ 세그먼트를 하면 쪼개진 데이터들 마다 고유번호가 생기는데
이를 “헤더(header)”라 하고 쪼개진 데이터를 “바디(body)” 라 한다!
소켓에서 데이터가 나눠진다 했는데 나누지 않으면 여러 컴퓨터에서 데이터를 전송 시
많은 데이터를 보내는 곳에서 오랜 시간을 소비 하기 때문에 나누는 것이다.
→ 나눌 때는 1Byte 보다 잘게 나눈다!
세그먼트 과정을 마친 후! OS로 데이터가 넘어가면 “패킷(Packet)”에 저장이 된다.
→ 패킷이 되는 것을 “캡슐레이션(Capsulation)”의 과정이다.
그렇다면 패킷을 하는 이유는?
패킷을 하면 데이터가 이동할 목적지와 데이터가 전송된 출발지가 저장이 같이 된다!
→ 이때 목적지는 SourceIP, 출발지는 DestinyIP가 저장 된다.
목적지 주소가 저장되는 이유는?
데이터를 보내기 위한 목적지를 알아야 하는데 이를 보내는 과정을
”포워딩(forwarding)” 이라 한다!
출발지 주소가 저장되는 이유는?
데이터가 성공적으로 전송 되었다는 것을 서로 알려주기 위해서 인데!
이를 “액크(ACK)”라 한다!
패킷 과정을 거친 후 H/W에서 “프레임(frame)”을 씌운 후 데이터를 이동 시키고 받는 곳에선 H/W부터 역과정을 거쳐 데이터를 받는다!
→ 프레임은 데이터를 옮기기 위한 이동 수단 같은 것이라 알면 된다! (패킷을 포장하는 역할!)
→ 여기에는 목적지 주소가 포함 되어 있다!
→ 프레임은 H/W(라우터 등)을 지나갈 때마다 프레임을 벗고 다시 입고 를 반복한다!
목적지에서 데이터를 받을 시 “디캡슐레이션(Decapsulation)” 을 진행해야한다.
→ 디캡슐레이션을 했을 때 “3 way handshake”가 성립하지 않을 시 버려 버린다.
마지막 과정까지 끝내면 목적지에서 출발지 영역(OS의 버퍼)을 만들어 데이터를 재조립하면 통신이 완료가 된다.
만약 “액크놀러지”가 안날아오는 경우가 있다면 이유는?
1. 데이터의 유실!
2. 라우터의 문제 (고장, 용량 초과, 경로의 트래픽 발생 등)
응답이 안되는 경우에는 재전송을 한다!
통신의 데이터 경로는 라우터가 찾는 최적의 경로로 설정이 된다.
마지막 TIP으로 전송하는 데이터의 끝에는 “\n”이 들어가야지만 제대로 읽어 들인다.
통신은 기본적으로 이러한 흐름으로 진행이 된다고 인지하면 될 듯 하다!
통신의 종류
Simplex, 단방향 → 단방향 통신
Half Duplex, 반이중 → 서로 번갈아가며 통신 (요청에 따른 반응-트리거가 있다) (웹은 무조건!, http)
→ 요청 시에 응답 한다! (요청에 응답 후 반응 할 필요가 없다)
→ 요청 응답 후 그 반응에 대한 결과를 기억하지는 않고 지워서 부화가 적다.
→ 동기적으로 실행된다!
→ 무전기!
Full Duplex, 전이중(양방향) → 양방향이라 서로 필요한 타이밍에 통신 (선택적 반응-트리거가 없다)
→ 최소한 스레드가 2개 이상 필요하다.
→ 과부화가 심하다
→ 전화기!
전이중을 “state full (스테이트 풀)” 이라 한다.
반이중을 “state listener (스테이트 리스너)” 이라 한다.
Share article