1. Protocol

1) 개념

- 원활한 통신을 위한 규칙

- 정보의 송수신측 또는 네트워크 내에서 사전에 약속된 규약 또는 규범

- 연결과정, 통신회선에서 접속방식, 통신회선을 통해 전달되는 정보의 형태, 오류발생에 대한 제어, 송수신측 간의 동기 방식 등에 대한 약속

 

2) 주요요소

- 구문(Syntax) : 데이터의 형식, 부호화, 신호레벨 등이 어떠한 구조와 순서로 표현되어있는지

- 의미(Semantics) : 각 비트가 갖는 의미로 패턴에 대한 해석과 해석에 따른 전송제어, 오류수정 등에 관한 제어정보를 규정

- 타이밍(Timing) : 두 개체 간의 통신속도를 조정하거나 메시지의 전송시간 및 순서 등에 대한 특성

 

 

2. OSI 7계층

1) 개념

- ISO에서는 개방형 시스템 간 상호접속을 위해 표준화된 네트워크 구조를 제공하는 기본 참조모델을 제정

- 다른 기종 간의 상호 접속을 위한 가이드라인 제시

- 상위 계층 : 사용자가 통신을 쉽게 이용할 수 있도록 도와주는 역할

- 하위 계층 : 효율적이고 정확한 전송과 관계된 일을 담당

 

2) 계층구조

OSI 7 Layers

- 7계층 구조는 비슷한 기능을 갖는 모듈을 동일 계층으로 분할

- 각 계층 간의 독립성 유지

- 한 모듈에 대한 변경이 다른 전체 모듈에 미치는 영향 최소화

- 2개의 그룹으로 분리 → 상위 3계층 : 이용자가 메시지를 교환할 때 사용, 하위 4계층 : 메시지가 호스트에서 사용

계층 특징 데이터 종류
7 응용계층 - 각종 응용서비스 제공
- 네트워크 관리
메시지
6 표현계층 - 네트워크 보안(암/복호화)
- 압축/압축해제, 포맷 변환 수행
5 세션계층 - 소켓 프로그램
- 동기화
- 세션 연결/관리/종료
4 전송계층 - 데이터 전송보장
- 흐름 제어
- Quality Of Services(QOS)
세그먼트
3 네트워크계층 - 통신경로 설정, 중계기능 담당
- 라우팅, 혼잡제어
- 데이터그램, 가상회선 방식
- IPv4, IPv6
패킷
2 데이터링크계층 - 오류제어, Frame화
- 매체제어(MAC)
- 에러검출, 에러정정, 흐름제어
프레임
1 물리계층 - 물리적 연결설정, 해제
- 전송방식, 전송매체
비트 스트림

 

① 물리 계층

- 데이터를 물리 매체 상으로 전송하는 역할을 담당

- 물리적 링크의 설정/유지/해제 담당

- 상용자 장비와 네트워크 종단장비 사이의 물리적, 전기적 인터페이스 규정에 초점

- 전송 선로의 종류에 따른 전송 방식과 인코딩 방식 결정

- 송신 측 물리 계층은 데이터링크 계층으로부터 받은 데이터를 비트단위로 변환

- 수신 측 물리 계층은 전송 받은 비트를 데이터링크 계층의 데이터로 올림

 

② 데이터링크 계층

- 물리 계층에서 전송하는 비트들의 동기 및 식별 기능, 원활한 데이터 전송을 위한 흐름제어 기능, 안전한 데이터 전송을 위한 오류제어 기능

- 헤더 : 데이터의 시작을 나타내는 표시와 목적지 주소 포함

- 트레일러 : 데이터에 발생한 전송 오류를 검출하기 위한 오류 검출 코드 포함

- 두 sub 계층으로 구성 

→ LLC(Logical Link Control sublayer) : 논리적 연결제어

MAC(Media Access Control) : 장비와 장비 간의 물리적인 접속

 

③ 네트워크 계층

- 송신 측에서 수신 측까지 데이터를 안전하게 전달하기 위해 논리적 링크 설정

- 상위 계층 데이터를 작은 크기의 패킷으로 분할하여 전송

- 개방형 시스템 사이에서 네트워크의 연결을 관리하고 유지하며 해제

- 스위칭 : 패킷의 수신 주소를 보고 정해진 방향으로 전송, 동작속도 빠름

- 라우터 : 라우팅 테이블을 찾아 알고리즘으로 최단 경로 계산 계산을 통해 전송경로를 결정 후 전송하여 스위치보다 동작 속도 느림

- 네트워크 주소는 발신지로부터 목적지까지 동일 (물리주소는 패킷이 이동될 때마다 변경)

 

④ 전송 계층

- 하위 계층의 첫 단계

- 세션을 맺고 있는 두 사용자 사이의 데이터 전송을 위한 종단간 제어

- 송신 컴퓨터의 응용프로그램(프로세스)에서 최종 수신 응용프로그램(프로세스)으로 전달

 

⑤ 세션 계층

- 세션이라 불리는 연결 확립 및 유지

- 효율적인 세션 관리를 위해 짧은 데이터 단위로 나눈 후 전송계층으로 내림

 

⑥ 표현 계층

- 송수신자가 공통으로 정보를 이해할 수 있도록 데이터 표현방식을 바꾸는 기능

- 데이터의 보안과 효율적인 전송을 위해 암호화와 압축을 수행하여 세션 계층으로 내림

 

⑦ 응용 계층

- 최상위 계층으로 응용 프로세스 네트워크 환경에 접근하는 수단을 제공

- 응용 프로세스들이 상호 간에 유용한 정보교환을 할 수 있도록 하는 창구 역할을 담당

 

3) 피어-투-피어(Peer-to-Peer) 간의 통신

- OSI 참조모델의 i번째 계층에서 다른 시스템의 i번째 계층과 통신하기 위해서는 상위계층의 메시지와 더불어 프로토콜 - 제어정보(PCI)를 이용

- 피어-투-피어 프로세스 : 임의의 계층에서 상대편 동일 계층의 모듈과 통신하는 프로세스

 

4) 캡슐화와 역캡슐화

① 캡슐화

- 어떤 것을 다른 것에 포함시킴으로써 포함된 것이 외부에서 보이지 않도록 함

- 프로토콜 데이터 단위를 다른 프로토콜 데이터 단위의 데이터 필드 부분에 위치시키는 기술

 

② 역캡슐화

- 캡슐화 이전으로 복원시키거나 제거 

- 캡슐화의 반대 동작

- 프로토콜 데이터 필드에 위치하고 있는 데이터 단위를 추출

※ 각 레벨의 데이터 PDU(Protocol Data Unit)

PDU 이름 계층
데이터(data) 응용 계층 PDU
세그먼트(segment) 전송 계층 PDU
패킷(packet) 인터페이스 계층 PDU
프레임(frame) 네트워크 접근 계층 PDU
비트(bit) 매체를 통해 이진 데이터로 물리적 전송을 위해 사용되는 PDU

 

→ 송신 단에서는 7계층에서 1계층으로 각각의 PDU를 추가하여 데이터를 캡슐화하고, 수신 단에서는 1계층에서 7계층으로 각각의 PDU를 제거하여 데이터를 얻는 비캡슐화 과정을 겪게 된다.

 

 

3. TCP/IP 4계층

1) 개념

- 미국 국방부 고등 연구 계획국에서 만든 연구 네트워크의 일부로 설계 (ARPAnet)

- 현재는 TCP와 IP가 공식 표준

- 다양한 기종의 컴퓨터가 하나로 묶이는 인터네트워킹 구조를 만듦

- 여러가지 프로토콜의 조합을 의미

- 4계층으로 구성 : 데이터링크, 네트워크, 전송, 응용계층

 

2) 계층구조

TCP/IP 4 Layers

① 네트워크 연결 계층

- 데이터를 송수신하는 역할

 

② 인터넷 계층

- 주소 관리, 포장, 라우팅하는 역할

- IP(Internet Protocol) : 호스트들과 네트워크에서 주소 관리, 패킷 라우팅

- ARP(Address Resolution Protocol) : 같은 네트워크에 위치한 호스트들의 하드웨어 주소를 얻는 데 사용

- ICMP(Internet Control Message Protocol) : 패킷 전송에 관한 에러 메시지 처리

 

③ 전송 계층

- 호스트들 간의 통신 제공, 2개의 프로토콜 존재

TCP(Transmission Control Protocol)

- 연결지향

- 데이터의 확실한 전송을 위해 수신 측으로 받았다는 확인 메시지 요구

UDP(User Datagram Protocol)

- 비연결지향

- 실시간으로 패킷을 전송하여 빠르나 패킷의 정확한 전달을 보장하지 않음

※ TCP와 UDP의 차이점

서비스 TCP UDP
신뢰성   - 패킷이 목적지까지 도달했는지 확인
  - 패킷이 도달할 때마다 ACK를 수신
  - 신뢰성 있는 프로토콜
  - ACK를 사용하지 않음
  - 패킷이 그들의 목적지에 도달되는 것을 보장하지 않음
  - 신뢰성 없는 프로토콜
연결   - 연결 지향적
  - 핸드쉐이킹 과정 수행
  - 비연결지향적
패킷 순서   - 패킷 내에 순서 번호 사용 X
혼잡 제어 O X
용도   - 신뢰성 있는 전송   - 스트리밍 비디오와 브로드캐스트 등 실시간 전송
속도의 오버헤드   - 상당한 양의 자원을 사용하며 UDP보다 느림   - 더 적은 자원을 사용하고 TCP보다 빠름

 

④ 응용 계층 

- 어플리케이션이 네트워크에 접근 가능하도록 함

 

 

4. Port, well known port

1) 포트 주소의 의미와 할당 원칙

① 포트

- 일종의 논리적인 접속 장소

- 포트 번호는 인터넷이나 기타 다른 네트워크 메시지가 서버에 도착했을 때 전달돼야 할 특정 프로세스를 인식하기 위한 방법

- TCP와 UDP에서 포트번호는 15비트 정수의 형태

 

② 포트번호와 소켓

- 통신을 위해 TCP 헤더에 송수신자 포트 정보를 삽입하여 패킷 생성

- 패킷을 서버로 전달하여 프로세스와 연결되면 서비스 이용 가능

- 포트 번호는 16비트, 0~65535번까지 존재, 0~1023번은 가능하면 사용 X (웰 노운 포트)

- 주요 포트번호 : root의 권한이 필요한 포트

 

2) well known port (잘 알려진 포트)

- 어떤 특권을 가진 서비스에 의해 사용될 수 있도록 예약되어 있음

- 루트 권한으로만 포트를 열 수 있음

- 루트 권한으로 실행된 프로그램만이 이 포트에서 데이터를 수신할 수 있지만, 권한에 상관없이 모든 프로그램이 이 포트로 데이터를 보낼 수 있음

프로토콜 포트 용도
ECHO 7 두 장비의 연결 확인
FTP data 20 파일 전송 프로토콜, 데이터 포트, FTP는 두 개의 포트 사용
FTP 21 PUT, GET 등의 FTP 명령 전송 시 사용
SSH 22 암호화된 원격 로그인에 사용
TELNET 23 대화 방식의 원격 명령 라인 세션에 사용, 암호화되지 않느 텍스트 송신
SMTP 25 장비 간의 메일 전송
TIME 37 1990년 1월 1일 자정 이후의 경과 시간을 초로 반환
DNS 53 호스트 도메인의 이름을 네트워크 주소로 바꾸거나 그 반대의 변환 수행
HTTP 80 www 기반의 프로토콜
HTTPS 43 HTTP over SSL (암호화된 전송)

 

 

5. HTTP, URL

1) 개념

- 인터넷 상에서 데이터를 주고 받기 위해 클라이언트와 서버 사이에 이루어지는 요청/응답 프로토콜

- 어떤 종류의 데이터든지 전송 가능, 주로 HTML 문서를 주고받음

- 사용하는 포트 번호 : 80번

- 주로 웹브라우저를 이용하여 통신

- 단점 : 인터넷 상에서 받은 데이터는 평문이 그대로 노출 → 네트워크 상에서 패킷이 그대로 노출되는 취약점 발생

 

2) HTTP Header

- HTTP 통신을 위해 필요한 정보들이 입력되어 있는 데이터 영역

Host 요청이 전송되는 타겟의 host URL 주소
Accept 클라이언트가 허용할 수 있는 파일 형식
User-Agent 요청을 보내는 클라이언트의 정보
Referer 현재 요청된 페이지 이전의 페이지 주소
Cookie 클라이언트에게 설정된 쿠키 정보
Content-Type Request에 보내는 데이터의 type 정보
Content-Length Request에 보내는 데이터의 길이

 

3) HTTP Method

- HTTP 통신의 형태를 결정

GET   - URI(URL)가 가진 정보를 검색하기 위해 서버 측에 요청하는 형태
POST   - URI(URL)에 폼 입력을 처리하기 위해 구성한 서버 측 스크립트 혹은 CGI 프로그램으로 구성
  - Form Action과 함께 전송
  - 데이터 부분에 요청 정보가 들어감
HEAD   - GET과 유사한 방식
  - 헤더 정보 이외에는 어떤 데이터도 보내지 않음
  - 웹 서버의 다운 여부 점검이나 웹 서버 정보를 얻기 위해 사용
OPTIONS   - 시스템에서 지원되는 메소드 종류 확인 가능
PUT   - POST와 유사한 전송 구조
  - 헤더 이외에 메세지가 함께 전송
  - 원격지 서버에 지정한 콘텐츠를 저장하기 위해 사용
  - 홈페이지 변조에 악용
DELETE   - PUT과 반대 개념
  - 원격지 웹 서버에 파일을 삭제하기 위해 사용
TRACE   - 원격지 서버에 루프백 메세지를 호출하기 위해 사용
CONNECT   - 웹 서버에 프록시 기능을 요청할 때 사용

 

4) HTTP Content-Type

- HTTP 헤더에 보내지는 데이터

- 표준 MIME Type의 하나

     → 브라우저는 데이터를 나타내는데 어떤 종류의 파일 stream인지 알게 됨

     → 서버에서 데이터를 해석할 때 중요한 역할을 함

Text 사람이 읽고 이해할 수 있는 문자열
Image 그림 데이터
Audio 음성 데이터
Video 동영상 데이터
Application 모든 종류의 이진 데이터
Multipart 복수의 데이터로 이루어진 복합 데이터
Message 전자 메일 메세지
Model 복수 차원으로 구성하는 모델 데이터

 

5) URL

- URI (URL) : Uniform Resource Identifier의 약자로 리소스를 식별하기 위한 식별자

- URL은 Uniform Resource Locator의 약자로 리소스의 위치를 식별하기 위한 URI의 하위 개념

- URI는 Scheme, Authority (Userinfo, Host, Port), Path, Query, Fragment의 구성 요소를 가짐

- 자주 쓰이는 웹 URI 구성 요소

Scheme 웹 서버에 접속할 때 어떤 프로토콜을 이용할지에 대한 정보를 담고 있음
Host 접속할 웹 서버의 호스트(서버 주소)에 대한 정보를 가지고 있음
Port 접속할 웹 서버의 포트에 대한 정보를 가지고 있음
Path 접속할 웹 서버의 경로에 대한 정보를 가지고 있음, '/' 문자로 구분
Query 웹 서버에 전달하는 파라미터이며 URI에서 '?' 문자 뒤에 붙음
Fragment 메인 리소스 내에 존재하는 서브 리소스에 접근할 때 이를 식별하기 위한 정보를 담고 있으며
URI에서 '#' 문자 뒤에 붙음

 

 

7. TCP/IP

→ 인터넷에 연결된 다른 종류의 컴퓨터끼리 상호 데이터를 주고받을 수 있도록 한 인터넷 표준 프로토콜

     (TCP : 데이터를 패킷으로 나누고 묶는 역할, IP : 명령이 올바르게 전송되도록 하며 전달되지 못한 패킷은 재전송)

1) TCP(Transmission Control Protocol) 주요 특징

- 신뢰성 있음 : 패킷 손실, 중복, 순서바뀜 등이 없도록 보장

- 연결지향적

    : 느슨한 연결(Loosly Connected)을 가짐

    : 연결 관리를 위한 연결 설정 및 연결 해제 필요

    : 양단간 어플리케이션/프로세스는 TCP가 제공하는 연결성 회선을 통하여 서로 통신

- TCP 연결의 식별, 다중화, 포트번호

- 전이중 전송방식/양방향성

- 멀티캐스트 불가능

- 세그먼트화 처리 : 데이터를 패키징 처리

- 흐름제어, 혼잡제어

- 비실시간적 응용

 

2) IP(Internet Protocol) 주요 특징

- 신뢰성 및 흐름제어 기능이 전혀 없음

- 비연결성 데이터그램 방식

- 패킷의 완전한 전달을 보장하지 않음

- IP 헤더 내에 수신 및 발신 주소를 포함

- IP 헤더 내 최상위 바이트(MSB)를 먼저 보냄

- 경우에 따라 단편화가 필요함

- 모든 상위 계층 프로토콜들이 IP 데이터그램에 살려서 전송됨

 

3) IPv4 주소 체제

- 32비트의 IP 주소를 보기 쉽게 표시하기 위해 4바이트 단위로 나누고 10진수로 표시하는 표현 방식이 널리 사용

- IP 주소는 네트워크 식별자 필드와 호스트 식별자 필드의 두 부분으로 구성되며 각 필드에서 사용되는 비트 수에 따라 5개의 클래스로 나눔

 

① 클래스별 IP 주소 내용

클래스 A - 첫번째 비트가 0인 IP 주소
- 상위 1바이트 : 네트워크 주소, 하위 3바이트 : 호스트 주소
- 큰 규모의 호스트를 갖는 기관에 할당
클래스 B - 처음 두 비트의 값이 10인 주소
- 상위 2바이트 : 네트워크 주소, 하위 2바이트 : 호스트 주소
클래스 C - 처음 3비트의 값이 110인 주소
- 상위 3바이트 : 네트워크 주소, 하위 1바이트 : 호스트 주소
- 작은 규모의 네트워크에 할당
클래스 D - 처음 4비트의 값이 1110인 주소
- 전체 주소가 멀티캐스트용으로 사용
클래스 E - 처음 4비트의 값이 1111인 주소
- 추후 사용을 위해 예약된 주소

 

② 패킷의 전송방법

전송 방식 설명
유니캐스트 - 하나의 송신자가 하나의 수신자에게 패킷을 보내는 방식
멀티캐스트 - 하나의 송신자가 다수의 수신자에게 패킷을 보내는 방식
- 특정 다수에게 전송
브로드캐스트 - 같은 네트워크에 잇는 모든 호스트에게 패킷을 보내는 방식
- 호스트 주소를 모두 1로 설정
- 불특정 다수에게 전송

 

③ IPv4 주소 관리방식

- 서브네팅 : 이진수로 1인 부분은 네트워크 부분, 0인 부분은 호스트

- 슈퍼네팅 : 부족한 IP를 효율적으로 사용하기 위해 여러 개의 C클래스 주소를 묶어 하나의 네트워크로 구성하는 방식

 

④ CIDR(Classes InterDomain Routing)

- 표기법

     : 비트마스크를 사용하여 점으로 구분된 10진 표기법 지정

     : 서브넷 마스크에서 연속된 1의 수가 몇개인지 지정, 연속된 1은 서브넷 마스크의 맨 왼쪽 비트부터 시작

     : IP 주소에서 네트워크 ID 구성, /x로 비트 수 표현

- 장점

     : IPv4의 주소 공간을 효율적으로 할당

     : 인터넷 라우팅 테이블의 비대화를 줄임

 

⑤ VLSM(Variable Length Subnet Mask)

- IP를 효율적으로 할당하여 활용

- 서로 다른 크기의 서브넷 지원

- IP 주소 공간의 일부를 잘라서 사용, 한 기관에 이미 할당된 주소 공간을 나눔

 

⑥ 사설 네트워크를 위한 주소할당

공인 IP - 인터넷 상에 하나밖에 없는 IP로 유일
- 각 나라의 관할 기관에서 할당
사설 IP - 인터넷 상에서 확인할 수 없으며 내부 네트워크에서만 활용
- 홈 LAN이나 회사 내부에서 마음대로 할당

- 사설주소 영역 : 사설 인터넷을 위해 IANA가 할당한 IP 주소 블록

클래스 IP 주소 블록 주소 범위
class A 24비트 블록 10.0.0.0 ~ 10.255.255.255
class B 20비트 블록 172.16.0.0 ~ 172.31.255.255
class C 16비트 블록 192.168.0.0 ~ 192.168.255.255

- NAT(Network Address Translation) : 사설 IP 주소를 공인 IP 주소로 변환하는 주소 변환기

 

4) IPv6

- 128비트 주소 길이를 사용

- 보안문제, 라우팅 효율성 문제, QoS 보장, 무선 인터넷 지원과 같은 다양한 기능 제공

 

5) IPv4와 IPv6 특징 비교

구분 IPv4 IPv6
주소 길이 32비트 128비트
표시 방법 8비트 4부분 10진수 표시 16비트 8부분 16진수 표시
주소 개수 약 43억개 2^128개
주소 할당방식 A, B, C, D 등의 클래스 단위 비순차 할당 네트워크 규모, 단말기 수에 따라 순차 할당
브로드캐스트 주소 있음 없음
헤더 크기 가변 고정
QoS 제공 미흡 제공
보안 IPSec 프로토콜 별도로 설치 IPSec 자체 지원
서비스 품질 제한적 품질 보장 확장된 품질 보장

 

'네트워크캠퍼스 > NETWORK' 카테고리의 다른 글

네트워크 쉽게, 더 쉽게  (0) 2024.02.01
3주차  (0) 2024.02.01
포트포워딩 실습  (0) 2024.01.26
2주차  (0) 2024.01.26
모두의 네트워크  (0) 2024.01.22

1. 컨테이너 기술

 

1) 컨테이너란?

- 애플리케이션을 언제든 실행 가능하도록 필요한 모든 요소를 하나의 런타임 환경으로 패키징한 논리적 공간

- 도커 : 컨테이너를 쓸 수 있도록 도와주는 기술 중 하나

- docker에서는 Dockerfile이라는 이름의 파일(대소문자 구분)에 적힌 스크립트를 통해 구현 → 코드형 인프라

 

2) 컨테이너 기술의 역사

① Traditional Deployment

- 물리적 컴퓨터에 애플리케이션을 배포하는 형태

- 하나의 하드웨어에 여러 애플리케이션이 관리되는 경우 앱간의 라이브러리 의존성 문제 발생 가능

 

②  Virtualized Deployment

- Hypervisor : 운영체제 위에서 운영체제를 독립적으로 격리시켜 실행할 수 있도록 만드는 기술 ex) vmware, virtualbox 등

- 프로세스 개수만큼 서버를 사야할 필요가 없어짐

- Guest OS를 하나하나 올리는 것에 많은 자원이 소모되는 문제 발생

 

③ Container Deployment

- 애플리케이션과 종속 항목을 하나로 묶어 실행하게 해주는 운영 시스템을 가상화한 경량의 격리된 프로세스

- microVM이라고도 부름

- 운영체제 수준의 가상화 제공

- 독립성을 갖기 때문에 다른 컨테이너에 영향을 주지 않는 stateless 환경 제공

 

3) 컨테이너 기술의 장점

- 개인 데스크탑 뿐만 아니라 기업 내의 온프레미스 서버, AWS와 같은 퍼블릭 클라우드까지 언제 어디서든 빠르고 효율적으로 배포 가능

→ 서버구성, OS설치, 네트워크, 개발 도구 구성 등의 반복적이고 불편한 작업에 시간을 낭비하지 않고 개발 그 자체에 집중 가능

- 컨테이너는 우리가 개발한 최소한의 Image(OS+실행할 프로그램)를 통해 실행되므로 경량

→ 컨테이너 이미지 생성의 Best Practice 중 하나는 이미지 경량화

- 일반 서버의 애플리케이션 실행과 달리 프로세스 수준의 속도로 빠르게 실행할 수 있고, 한 번에 여러 개의 컨테이너를 동시에 실행 가능

→ Docker의 docker compose 기술을 통해 구현

- 어떤 OS, 어떤 환경에서도 동작 가능한 이식성 보유

- 컨테이너 자체 애플리케이션 환경에 대한 관리만 요구되므로 지속적 서버관리 비용 절감 가능

- 개발팀과 운영팀의 업무 분리로 각자의 업무와 세분화된 관리에 집중 가능

→ 컨테이너는 Devops workflow 구성에 최적

 

4) 컨테이너의 사례

- 구글 웹, 앱 서비스

- 에어비엔비 추천서비스

- 넷플릭스 추천서비스

- 당근마켓 딥러닝 기반 추천서비스

- 엔씨소프트 게임서비스

- 삼성전자 헬스케어서비스

- 타다 배차서비스

- 토스 금융서비스

 

5) 컨테이너 타입

① 시스템 (or OS) 컨테이너 : OS까지만 설치해서 실행되는 유형

- 호스트 OS 위에 Ubuntu와 같은 배포판 리눅스 Image를 통해 배포되는 컨테이너

- 또다른 VM의 형태(Hypervisor와 유사), 내부에 다양한 애플리케이션 및 라이브러리 도구를 설치&실행 가능

- ex) LXC, LXD, OpenVZ, Linux Server, BSD Jails 등

 

② 애플리케이션 컨테이너 : OS와 OS 위에서 돌아갈 애플리케이션까지 같이 설치하여 실행되는 유형

- 단일 애플리케이션 실행을 위해 해당 서비스를 패키징하고 실행하도록 설계된 컨테이너

- 3-tier 애플리케이션과 같은 경우 각 tier(frondend-backend-DB)를 개별 컨테이너로 실행하여 연결

- ex) Docker container runtime, Rocket 등

 

 

2. Docker

 

1) 도커란?

- 여러 계층의 애플리케이션을 컨테이너로 분리, 연결하여 실행하는 마이크로서비스 아키텍처 프로젝트에 유용

- 애플리케이션의 인프라는 이미지를 통해 제공하고, 퍼블릭 혹은 프라이빗하게 공유 가능

- 깃허브와 유사한 방식으로 Docker Hub에서 제공

- 제공된 Image를 기반으로 Application 서비스를 제공, 이를 컨테이너화할 수 있음

 

2) 가상화(Virtualization)란?

- 서버, 스토리지, 네트워크, 애플리케이션 등을 가상화하여 하드웨어 리소스를 효율적으로 사용하려는 목적

→ 효율적인 자원 활용, 자동화된 IT 관리, 빠른 재해 복구 가능

- 물리적 하드웨어 유지 관리 대신 소프트웨어적으로 추상화된 가상화를 통해 제한된 부분을 쉽게 관리하고 유지 가능

- 하이퍼바이저 기반의 가상머신을 통해 수행 ex) VMware, VirtualBox 등

 

3) 컨테이너 가상화 vs VM 가상화

  컨테이너 VM
공통점 실행하고자 하는 애플리케이션 프로세스 및 종속 요소와 소스 등을 패키지, 즉 이미지화하여 HostOS와 격리된 환경 제공
차이점 VM 가상화에 비해 경량이면서 호스트 운영체제의 커널을 공유하는 운영체제 수준의 가상화를 구현 → 원하는 애플리케이션 환경을 빠르게 번들링하여 패키징 실제 호스트 운영체제와 같이 별도의 GuestOS를 두고 원하는 애플리케이션을 설치하는 하드웨어 수준의 가상화를 구현
운영체제가 1개 운영체제가 적어도 2개 이상

 

※ 컨테이너는 가상머신인가?

→ Container는 hypervisor와 완전히 다른데, 궁극적으로는 hypervisor와 유사한 형태의 "가상화"를 목표로 하고 있다.

→ hypervisor는 OS 및 커널이 통째로 가상화되는 반면, container는 filesystem의 가상화만을 이룬다.

→ 컨테이너는 호스트 PC의 커널을 공유하고 따르기 때문에 init(1) 등의 프로세스가 떠있을 필요가 없으며 가상화 프로그램과는 다르게 적은 메모리 사용량, 적은 오버헤드를 보인다.

 

4) 컨테이너화(containerization) 기술

① LXC를 이용한 시스템 컨테이너화로 시작

→ cgroups, namespaces : Linux Kernel 위에서 LXC를 격리시키기 위해 필요

→ cgroup, namespace 등의 커널 기술을 공유해 컨테이너에 제공

 

※ namespaces

→ 각 게스트 머신별로 독립적인 공간을 제공하고, 서로가 충돌하지 않도록 하는 기능 (현재 리눅스 커널에서는 6가지 지원)

mnt (파일시스템 마운트)  호스트 파일시스템에 구애받지 않고 독립적으로 파일시스템을 마운트하거나 언마운트 가능
pid (프로세스) 독립적인 프로세스 공간 할당
net (네트워크) namespace 간에 network 충돌 방지
ipc (SystemV IPC) 프로세스 간의 독립적인 통신통로 할당
uts (hostname) 독립적인 hostname 할당
user (UID) 독립적인 사용자 할당

 

※ cgroups (Control Groups) 

→ 자원에 대한 제어를 가능하게 해주는 리눅스 커널의 기능

→ 메모리, CPU, I/O, 네트워크, device 노드(/dev/)를 제어

 

② containerd, runC를 이용한 도커

초기 도커는 LXC를 그대로 응용하여 사용

현재는 containerd, runC를 이용하도록 변경

- runC : 커널 기술 공유를 통해 컨테이너를 생성하도록 도와줌

- containerd : 생성된 컨테이너의 라이프사이클 관리

- dockerd : 사용자 환경에서 명령 전달

- docker 1.11 버전부터 위와 같은 구조로 작동

- containerd : OCI 구현체(주로 runC)를 이용해 컨테이너를 관리해주는 daemon

- Docker Engine 자체는 이미지, 네트워크, 디스크 등의 관리 역할

- 여기서 Docker Engine과 containerd 각각이 완전 분리

  → Docker Engine 버전을 올릴 때 Docker Engine을 재시작해도 container의 재시작 없이 사용 가능

1. JAVA API(Application Programming Interface) 

→ 프로그램 개발에 자주 사용되는 클래스 및 인터페이스의 모음으로 라이브러리라고 부름

※ 자바 표준 API 문서 : https://docs.oracle.com/javase/8/docs/api

 

1) java.lang 패키지

자바의 기본적인 클래스들을 담고 있는 패키지로 import 구문 없이 사용 가능

① Object : 자바클래스의 최상위 클래스

Object 클래스는 모든 클래스의 부모클래스이다.

public class MainClass {

	public static void main(String[] args) {
		ObjectInformation oi = new ObjectInformation();
		
		System.out.println(oi);
	}
}

Object 클래스의 toString 메서드

Object 클래스를 확인해보면 toString 메서드가 이미 정의되어 있기 때문에 위와 같은 출력 결과를 확인할 수 있다. 

public class ObjectInformation {
	// toString 오버라이딩 후 System.out.println() 등으로 객체변수 조회 시
	// 해당 인스턴스의 클래스 경로와 주소값 대신 toString에서 리턴한 문자가 콘솔에 찍힘
	
	@Override 
	public String toString() {
		return "조회 시 이게 나올거임";
	}
}

ObjectInformation 클래스에 toString() 메서드를 오버라이딩하면 오버라이딩한 내용으로 바뀌어 출력되는 것을 확인할 수 있다.

 

② System : 표준입력장치(키보드)로부터 데이터를 입력받거나 표준출력장치(모니터)로 출력하기 위해 사용

- exit() : 현재 실행하고 있는 프로세스 강제 종료, 정상 종료일 경우 매개값으로 0을 줌

- currentTimeMills() : 컴퓨터의 시계로부터 현재 시간을 읽어서 밀리세컨드 단위와 나노세컨드 단위의 long 값 리턴

                                  → 프로그램의 실행 소요 시간 측정으로 성능을 테스트할 때 사용

public class SystemTimeEx {
	public static void main(String[] args) {
		// currentTimeMilllis()와 nanoTime() 메서드는 UNIX 시간 사용
		// UNIX 시간 : 1970/01/01 00:00:00을 기점으로 얼마나 시간이 지났는지 숫자로 표현
		// 현재까지의 시간을 1000분의 1초로 변환한 에폭시간과 10억분의 1초로 변환한 에폭시간을 long 타입으로 리턴
		
		long start = System.currentTimeMillis();
		System.out.println("시작시간 : " + start);
		long sum = 0;
		
		for(long i = 1; i < 10_000_000_000L; i++) {
			sum += i;
		}
		long end = System.currentTimeMillis();
		System.out.println("종료시간 : " + end);
		System.out.println("계산에 소요된 시간 : " + (end - start));
	}
}

위와 같이 해당 로직이 수행되는데 얼마나 시간이 걸리는지 알 수 있다.

- getProperty() : JVM이 시작할 때 자동 설정되는 시스템의 속성값 구함

- gc() : Garbage Collector 실행

 

③ Class : 클래스를 메모리에 로딩할 때 사용

 

④ String : 문자열을 저장하고 문자열의 여러 가지 정보를 얻을 때 사용

→ 생성자를 사용하여 객체를 만들 필요 없이 기초 데이터처럼 바로 초기화 가능

- 주요 메서드

charAt() 특정 인덱스 글자 리턴
indexOf() 특정 문자열의 시작 인덱스 반환, 해당 문자가 없으면 -1 리턴
length() 문자열 길이 리턴
replace() 특정 문자열 변경
substring() 인덱스를 기준으로 그 앞의 문자열을 잘라줌
ex) 매개값으로 인덱스 2개 주면 처음 매개값~두번째 매개값의 문자열을 제외하고 삭제
toUpperCase() 문자열을 대문자로 치환
toLowerCase() 문자열을 소문자로 치환
trim() 문자열의 앞, 뒤 공백 제거
equals() 문자열의 값 비교
valueOf() 기본 데이터 타입의 값들을 문자열로 변환

 

-charAt( ) 메서드 예시

public class StringCharAt {
	public static void main(String[] args) {
		// 일반 배열은 아래와 같이 인덱싱 가능
		int [] iArr = {1, 2, 3, 4};
		System.out.println(iArr[2]);
		
		// 문자열은 일반 인덱싱([ ]을 사용하는 인덱싱)이 불가능
		String str = "가나다라";
		//System.out.println(str[2]);
		System.out.println(str.charAt(2));
	}
}

 

- indexOf( ) 메서드 예시

public class StringIndexOf {
	public static void main(String[] args) {
		// 특정 문자열의 시작 인덱스값을 반환
		String to = "tomatos";
		
		// 단일 파라키터로 조회만 할 경우 0번에서 제일 가까운 단어 하나만 조회
		System.out.println(to.indexOf(to));

		// 두 번째 파라미터로 조회 시작 파라미터 지정 가능
		System.out.println(to.indexOf("to", 1)); // 0번부터가 아닌 1번부터 조회
		
		// 없는 단어 조회 시 -1
		System.out.println(to.indexOf("na"));
	}
}

 

- replace( ) 메서드 예시

public class StringReplace {

	public static void main(String[] args) {
		// 자바는 15버전부터 멀티라인 문자열 지원
		// 원래 자바 문자열은 여닫는 "를 한 줄에 작성해야했음
		// String a = "가나다라"; (허용) 
		// String a = "가나다라
		//					"마바사";	(허용 X)
		
		// 여닫는 따옴표가 다른 줄에 위치한 경우 " 세 개 이용
		// """를 사용한 줄에는 문자열을 작성할 수 없고, 다음 줄부터 작성가능
		String notice = """
						<공지사항>
						1. 복습 철저히 해주세요
						2. 회고록 작성 해주세요
				""";
		System.out.println(notice);
		
		// replace()는 String을 리턴하고, 첫 단어를 두 번째 단어로 바꿔줌
		String newNotice = notice.replace("해주세요", "해주십시오");
		System.out.println(newNotice);
	}
}

 

- substring( ) 메서드 예시

public class StringSubstring {

	public static void main(String[] args) {
		// 주민번호 양식
		String ssn = "010808-4987654";
		System.out.println(ssn);

		// substring() 메서드에 매개값으로 인덱스를 1개 지정 시 
		// 해당 인덱스부터 마지막 지점까지의 문자 추출
		String last = ssn.substring(7); // 7번부터
		System.out.println(last);
		
		// substring() 메서드에 매개값으로 인덱스를 2개 지정 시
		// 첫 번째 매개값 이상, 두 번째 매개값 미만 범위 문자 추출
		String first = ssn.substring(0, 6); // 0 1 2 3 4 5까지 조회, 6은 범위 X
		System.out.println(first);
	}
}

 

- trim() 메서드 예시

public class StringTrim {

	public static void main(String[] args) {
		// trim은 좌측, 우측에서 다른 단어가 나오기 직전까지 공백을 전부 제거
		String trimBefore = "              옆에   거슬     려요       ";
		System.err.println(trimBefore);
		String trimAfter = trimBefore.trim();
		System.out.println(trimAfter);
	}
}

 

- valueOf() 메서드 예시

public class StringValueOf {

	public static void main(String[] args) {
		int a = 10;
		double b = 8.79;
		System.out.println(a + b);
		
		String str1 = String.valueOf(a); // int -> String
		String str2 = String.valueOf(b); // double -> String
		System.out.println(str1 + str2);
	}
}

 

★ String 클래스 단점 : 처음 초기화된 데이터 변경 시 기존 객체 재활용이 아닌 새로운 객체 생성 → 메모리 과소비

위와 같이 String 클래스는 문자 내용이 변경될 때마다 새로운 영역에 다시 할당되어 속도가 느려지는 현상이 발생한다.

→ 속도적인 측면에서 개선된 StringBuffer와 StringBuilder 사용

 

⑤ StringBuffer, StringBuilder : 문자열을 저장하고 내부 문자열을 조작할 때 사용

- StringBuilder가 성능적으로는 좀 더 낫지만, StringBuffer는 Thread safety를 보장한다.

- 정말 세밀한 성능 이슈를 따지지 않는 환경에서는 StringBuffer를 쓰면 된다.

public class StringMemory {
	public static void main(String[] args) {
		// String의 경우 내용이 다른 문자는 항상 새롭게 할당
		//String a = "0";
		
		// StringBuilder, StringBuffer는 문자도 메모리 저장 시 변경 가능하게 저장
		// 따라서 문자 내용이 바뀌어도 새로운 할당이 잘 일어나지 않으므로 성능상 우위에 있음
		// StringBuilder는 Thread safety하지 않지만 StringBuffer보다 근소하게 성능이 좋음
		//StringBuilder sb = new StringBuilder("0");
		StringBuffer sb = new StringBuffer("0");
		
		long start = System.currentTimeMillis();
		
		for(int i = 0; i < 1_000_000; i++) {
			//a += "0"; // a 문자에 0을 100만번 더함 -> 힙 할당도 100만번
			sb.append("0"); // sb에 0을 100만번 더함 -> 힙 할당은 거의 새롭게 일어나지 않음
		}
		 
		long end = System.currentTimeMillis();
		System.out.println("소요시간(밀리초 : " + (end - start));
	}
}

 

- StringBuilder 클래스의 주요 메서드

append() 기존 문자열의 뒤에 문자열 추가
insert() 특정 위치에 문자열 추가
delete() 문자열 삭제
deleteCharAt() 특정 인덱스의 문자 하나 삭제
replace() 문자열의 일부분을 다른 문자열로 대체
setCharAt() 문자열에서 주어진 index의 문자를 다른 문자로 대체
toString() stringBuilder 객체의 값을 문자열로 반환
reverse() 문자열을 거꾸로 뒤집기
public class StringBuilderEx {
	public static void main(String[] args) {
		// 이 코드에서 StringBuilder는 전부 StringBuffer로 대체해도 잘 동작한다.
		// 둘의 차이는 쓰레드 안전이 보장되는지 아닌지의 여부뿐
		// 따라서 쓰레드 안전을 보장받고 싶다면 StringBuffer만 사용하면 됨
		//StringBuilder sb = new StringBuilder("JAVA");
		StringBuffer sb = new StringBuffer("JAVA");
		
		// 문자열 끝에 추가하는 메서드 append()
		sb.append(" Program Study");; // sb += " Program Study"와 동일
		System.out.println(sb);
		
		// 문자열을 특정 인덱스 위치에 삽입하는 메서드 insert()
		sb.insert(12, "ming");
		System.out.println(sb);
		
		// 특정 인덱스 범위 문자열을 교체하는 메서드 replace()
		sb.replace(5, 16, "book"); // 5~15번 인덱스 11글자를 book 4글자로 치환
		System.out.println(sb);
		
		// 문자열을 삭제하는 메서드 delete(begin, end)
		sb.delete(4, 9);
		System.out.println(sb);
		System.out.println(sb.length());
	}
}

 

☆ 매번 할당하지 않는 원리

StringBuilder와 StringBuffer는 생성 시 할당하는 저장용량 capacity(16)를 가지고 있으며, append 연산으로 저장 용량을 초과하는 경우 기존 저장 용량을 가진 객체를 재할당하게 된다.

 

⑥ Math : 수학 함수를 이용할 때 사용

- 주요 메서드

abs() 절대값
ceil() 올림값
floor() 내림값
max() 최대값
min() 최소값
random() 랜덤값 (0.0 <= 값 <1.0)
rint() 현재 수에서 가까운 정수를 실수 형태로 구함
round() 반올림값
public class MathEx {
	public static void main(String[] args) {
		// 수학 관련된 연산이나 혹은 상수를 저장해둔 Math 클래스는 정적 변수와 메서드를 가지므로
		// 굳이 Math 객체를 생성하지 않아도 활용 가능
		
		// 절대값 : 부호 무시
		System.out.println(Math.abs(-15.294));
		
		// 올림 : 소수점 아래자리가 존재하면 1 증가
		System.out.println(Math.ceil(10.0));
		System.out.println(Math.ceil(10.00001));
		
		// 내림 : 소수점 아래자리가 존재하면 없애버림
		System.out.println(Math.floor(10.0));
		System.out.println(Math.floor(10.99999));
		
		// 최대값 : 제시된 수 중 가장 큰 값 하나만 남김
		System.out.println(Math.max(99.9, 12.34));
		
		// 최소값 : 제시된 수 중 가장 작은 값 하나만 남김
		System.out.println(Math.min(99.9, 12.34));
		
		// 랜덤값 : 컴퓨터 시스템은 완벽한 난수가 아닌 시득닶에 따른 의사난수를 사용
		System.out.println(Math.random());
		
		// 가장 가까운 실수 구하기
		System.out.println(Math.rint(12.500001));
		
		// 반올림 : 소수점 아래값이 0.5 미만이면 정수를 그대로, 이상이면 1 증가
		System.out.println(Math.round(24.604));
        
        	// 혹은 Math 클래스 내에 정적변수로 자주 사용하는 상수값(원주율, 자연상수 등)도 제공
		System.out.println(Math.PI);
		System.out.println(Math.E);
	}
}

 

 

⑦ Wrapper(Byte, Short, Integer, Long, Float, Double, Boolean, Character) : 기본 데이터 타입의 객체를 만들 때 사용

 

 

 

 

 

 

 

 

 

 

 

 

'네트워크캠퍼스 > JAVA' 카테고리의 다른 글

객체지향 정리  (0) 2024.01.25
프로세스와 쓰레드  (0) 2024.01.24
자바의 예외처리전략  (0) 2024.01.18
예외처리  (0) 2024.01.17
인터페이스  (0) 2024.01.16

1. 예외를 처리하는 방법

※ 최근 자바 개발자들끼리 checked exception을 unchecked exception으로 전환시키는 것이 좋다는 결론을 내림

 

1) 예외 복구

// 일반적으로 예외를 던지는 경우
public void exceptionTest() throws SomeException {

}

// 어느정도 처리하고 예외를 던지는 경우
public void exceptionTest() throws SomeException {
    try {
        ...
    } catch (SomeException e) {
// 예외 처리의 필요성이 있을 때 어느정도 처리하고 던지는 경우
	throw e;
    }
}

- 예외 발생 시 다른 작업 흐름으로 유도 ( try ~ catch ~ finally )

- 예외가 발생해도 어플리케이션은 정상적인 흐름으로 진행됨

- 예외 발생 시 재시도를 통해 정상 흐름으로 진행되게 하거나 미리 예측하여 다른 흐름으로 유도시키도록 구현하면 예외가 발생하더라도 정상적으로 작업 종료 가능

 

2) 예외 처리 회피

public void exceptionTest() {
    try {
        ...
    } catch (SQLException e) {
// 더 명확하게 인지할 수 있도록 다른 예외로 전환해서 던지는 방법
	throw new DuplicationUserIdException(message);
    }
}

- 예외 처리를 직접 담당하지 않고 호출한 쪽으로 던져 회피하는 방법

- 무책임하게 상위 메서드로 throw를 던지는 행위는 상위 메서드의 책임이 증가하기 때문에 적절한 경우에만 사용하는 것이 좋음

 

3) 예외 전환

- 예외를 잡아 다른 적절한 예외로 전환하여 자신을 호출한 메서드로 던져버리는 방법

- 호출한 쪽에서 예외를 받아 처리 시 좀 더 명확하게 인지할 수 있도록 돕기 위한 방법

- 어쩔 수 없이 API에서 가져다 쓰는 기능(Thread.sleep() 등)은 checked exception이 강제되는 경우 어떤 로직을 호출하거나 실행하려 하는지 명시되는 문제가 발생

→ try ~ catch를 쓰되 catch 블럭에서 다른 runtimeException을 throw

→  예외를 유발했던 요소가 아닌 catch 블럭에서 일으킨 예외가 대신 콘솔에 찍힘

→  throw 되는 예외를 바꿔서 어떤 로직이 예외를 유발했는지 추론하기 어렵게 만들어 캡슐화 유지

'네트워크캠퍼스 > JAVA' 카테고리의 다른 글

프로세스와 쓰레드  (0) 2024.01.24
자바 API  (0) 2024.01.18
예외처리  (0) 2024.01.17
인터페이스  (0) 2024.01.16
추상화  (0) 2024.01.15

1. 예외처리(Exception)

→ 오류 발생 가능성이 있는 부분에 대한 처리를 미리 프로그래밍 해주는 것

 

1) 컴파일러  체크 예외 (Checked Exception)

- 자바 소스를 컴파일하는 과정에서 예외 처리 코드를 검사하여 예외 처리 코드가 없다면 컴파일 오류 발생

- 실행하지 않고도 오류가 발생한 것을 알 수 있음

- Checked Exception은 필요하지 않다고 결론이 남

 

2) 실행 예외 (Runtime Exception)

- 컴파일하는 과정에서 예외처리 코드를 검사하지 않는 예외

- 개발자들 사이에서 실행 예외만 신경쓰기로 합의, 오로지 개발자의 경험에 의해 처리

- 실행 예외에 대한 예외처리 코드를 넣지 않았을 때 해당 예외가 발생하면 프로그램 즉시 종료

 

RuntimeException을 상속받는 예외들은 모두 Unchecked Exception이다.

둘 다 확인 시점은 실행 단계이고, rollback 여부는 설정에 따라 달라진다.

 

 

2. 실행 예외 (Unchecked Exception = Runtime Exception)

1) NullPointerException

→ 객체 참조가 없는 상태, null 값을 갖는 참조 변수로 객체 접근 연산자인 "."을 사용했을 때 발생

public class NullPointerEx {
	public static void main(String[] args) {
		String str = null;
		//str = "HELLO";
		
		// .toLowercase()는 모든 문자를 소문자로 만들어줌
		System.out.println(str.toLowerCase());
	}
}

참조형 변수로 선언한 str이 null값이므로 위와 같은 오류가 발생하는 것을 확인할 수 있다.

 

2) ArrayIndexOutOfBoundsException

→ 배열에서 인덱스 범위를 초과하여 사용할 경우 발생

public class ArrayIndexEx {
	public static void main(String[] args) {
		int [] arr = {3, 6, 9};
		
		// 있지도 않은 인덱스 번호 조회하기, 그러나 문법상 오류는 없음
		System.out.println(arr[3]);
	}
}

배열의 길이가 3인데 존재하지 않는 3번 인덱스 값을 조회했으므로 위와 같은 오류가 발생하는 것을 확인할 수 있다. 

 

3) NumberFormatException

→ 문자열로 되어 있는 데이터를 숫자로 변경하는 경우 발생

public class NumberFormatEx {
	public static void main(String[] args) {
		String a = "35";
		String b = "21";
		System.out.println(a + b);
		
		// str -> int 변환
		int i = Integer.parseInt(a); // 문자 35를 숫자 35로 변환
		int j = Integer.parseInt(b); // 문자 21을 숫자 21로 변환 
		System.out.println(i + j);
		
		// parseInt는 문자열 내부에 순수한 정수가 들어있어야 변환을 실행하며 
		// 정수값이 아니라면 NumberFormatException이 발생
		String s = "Hello";
		System.out.println(Integer.parseInt(s));
	}
}

s 변수는 String 타입으로 정수값이 아닌데 parseInt()는 문자열 내부에 순수한 정수가 있어야함 변환을 실행하기 때문에 위와 같은 오류가 발생하는 것을 확인할 수 있다.

 

4) ClassCastException

→ 상속 관계나 인터페이스 관계가 없는 클래스들을 억지로 형 변환할 경우 발생

☆ 형 변환은 부모클래스 -자식클래스, 구현클래스-인터페이스 간에 발생  이 관계가 아니라면 다른 클래스로 타입 변환 불가

//하나의 클래스 파일에 2개 이상의 클래스 선언 가능 (자주 사용하지는 않음)
// 상속관계 : 부모 Animal을 상속한 자식 Dog, Cat
class Animal{}
class Dog extends Animal{}
class Cat extends Animal{}

public class ClassCastEx {
	public static void main(String[] args) {
		Dog d = new Dog();
		Animal da = d;
		d = (Dog)da;
		
		System.out.println("타입 변환 성공 : Animal -> Dog");
		
		Animal c = new Cat();
		Dog d2 = (Dog)c; // Cat은 Dog 타입으로 변환 불가
		
		System.out.println("타입 변환 성공? : Dog -> Cat");
	}
}

 

Cat과 Dog는 상속 관계에 있는 클래스가 아니므로 위와 같은 오류가 발생하는 것을 확인할 수 있다.

 

 

3. 예외처리코드

1) try ~ catch

- 예외 발생 시 갑작스러운 종료를 막고 정상 실행을 유지할 수 있도록 처리하는 코드

- try~catch~finally 블록 : 생성자나 메서드 내부에서 작성되어 컴파일 예외나 실행 예외가 발생할 경우 예외처리

- try 블록 : 예외 발생 가능성이 있는 코드 작성 예외 발생 시 실행을 멈추고 catch 블록으로 이동

- finally 블록 : 예외 발생 여부와 상관없이 항상 실행 → 필수는 X, 로직이 블럭과 관련 있을 시 작성

※ finally 구문이 실행되지 않는 경우

① finally 구문 이전에 System.exit() 구문 호출 시

② 컴퓨터가 꺼져서 시스템이 멈추었을 시

③ finally 블록 내부에서 예외가 발생했을 시

public class TryCatchEx1 {
	public static void main(String[] args) {
		int i = 10;
		int j = 5;
		
		try { // 예외가 발생할 가능성이 있는 코드를 넣는 구역
			System.out.println(i / j); // 예외 발생 가능성이 있음
			System.out.println("예외 발생하지 않을 때만 실행됨");
		} catch(Exception e) { //catch 블럭에는 Exception의 종류를 기입
			System.out.println("0으로 나눠서 catch 블럭으로 넘어왔습니다.");
		} finally { // try, catch 둘 중 어느 블럭이라도 실행되면 마무리 블럭 실행
			System.out.println("어쨌든 잘 마무리 했습니다.");
		}
	}
}

변수 j가 5라면 try 블럭 안의 내용과 finally 블럭 내용이 출력된다.

변수 j가 0이라면 예외가 발생하여 catch 블럭으로 넘어가고 해당 내용과 finally 블럭 내용이 출력된다.

 

2) 다중 catch

- 여러 가지 예외가 발생한다면 다중 catch 블록 작성

- 상위 예외 클래스가 하위 예외 클래스보다 아래쪽에 위치해야 함

- 상위 예외 클래스의 catch 블록이 위에 있다면 하위 예외 클래스의 catch 블록은 실행되지 않음

- 자바 7 버전부터 하나의 catch 블록에서 여러 개의 예외 처리 가능

- catch() 괄호 안에 동일하게 처리하고 싶은 예외를 |로 연결 (※ 두 예외가 상속 관계에 있으면 안됨)

ublic class MultiCatchEx {
	public static void main(String[] args) {
		String data1 = "30";
		String data2 = "11";
		
		try {
			// NumberFormatException 발생 가능 (정수가 아닌 값이 들어갈 경우)
			int i = Integer.parseInt(data1);
			int j = Integer.parseInt(data2);
		
			// ArithmeticException 발생 가능 (j에 0이 들어갈 경우)
			int result = i / j;
			System.out.println("i / j = " + result);
		
			// NullPointerException 발생 가능
			String str = null;
			str.charAt(0); // 0번째 문자 얻기인데 null값인 경우
		} catch(NumberFormatException | NullPointerException e) {
			System.err.println("데이터를 숫자만 넣어주세요.");
			System.err.println("혹은 문자를 제대로 만들어주세요.");
		} catch(ArithmeticException e) {
			System.err.println("0으로 나눌 수 없습니다.");
		} catch(Exception e) { // 범용 에러 처리 (대부분의 에러를 다 커버)
			System.err.println("알 수 없는 에러가 발생했습니다.");
			System.err.println("복구중입니다.");
		}
	}
}

catch 블록은 위에서부터 차례대로 검색되고, 예외 발생 시 해당하는 예외처리를 할 수 있게 된다.

위 예제의 경우 NullPointerException 예외만 발생하므로 첫번째 catch 블록의 내용만 출력하는 것을 확인할 수 있다.

 

3) throws

- 메서드나 생성자를 호출한 곳으로 예외를 던지는 방법 → 예외 처리를 직접 수행하지 않고 메서드 호출자에게 던짐

- try 블록 내부에서 호출되어야 하고, catch 블록에서 떠넘겨 받은 예외 처리를해야 함

- throws가 붙어있는 메서드는 반드시 try 블록 내부에서 호출되어야 하고, catch 블록에서 떠넘겨 받은 예외를 처리해야 함

- main() 메서드에서 throws를 사용하는 것은 예외처리를 JVM에게 넘기겠다는 의미

  ※ JVM은 예외를 직접 처리해주지 않고 예외 메시지만 출력하고 프로그램 종료

public class ThrowsEx {
	public static String[] greetings = {"안녕", "싸왓디", "헬로"};
	
	// 예외의 원인이 메서드 선언부가 아닌 호출부에 있을 경우
	// 메모리 영역이 다르므로 예외처리를 메서드 호출지역으로 떠넘겨줘야 함
	// 이를 throws라고 하고, 메서드 혹은 생성자 호출 시 예외처리를 강요할 때 사용
	public static void greet(int idx) {
		try {
			System.out.println(greetings[idx]);
		} catch(ArrayIndexOutOfBoundsException e){
			// 코드 안적어도됨
		}
		
	}
	
	public static void main(String[] args) {
		// throws가 붙어 있는 메서드나 생성자 호출 시에는
		// 해당 메서드를 try 블록 내부에서 호출해야 예외처리를 진행해줌
		greet(3);
	}
}

위 예제에서 greetings 배열의 크기가 3인데 4번째 인덱스를 조회하고 있으므로 ArrayIndexOutOfBoundsException이 발생하고, 이 경우 위와 같이 greet 함수에서 예외처리를 해줄 수 있다. 하지만, 객체 지향 측면에서 해당 메서드의 책임이 많아지므로 위 코드는 좋은 코드가 아니다. 

public class ThrowsEx {
	public static String[] greetings = {"안녕", "싸왓디", "헬로"};
	
	// 예외의 원인이 메서드 선언부가 아닌 호출부에 있을 경우
	// 메모리 영역이 다르므로 예외처리를 메서드 호출지역으로 떠넘겨줘야 함
	// 이를 throws라고 하고, 메서드 혹은 생성자 호출 시 예외처리를 강요할 때 사용
	
	// 해당 예외가 발생하면 호출부(여기서는 main)에게 처리를 떠넘기는 것				
	public static void greet(int idx) throws Exception {
		System.out.println(greetings[idx]);
	}
	
	public static void main(String[] args) {
		// throws가 붙어 있는 메서드나 생성자 호출 시에는
		// 해당 메서드를 try 블록 내부에서 호출해야 예외처리를 진행해줌
		try {
			greet(3);
		} catch(Exception e) {
			// .printSackTrace()는 예외발생 경로를 추적하는 메세지 출력
			// 주로 개발 과정에서 예외의 원인을 역추적할 때 유용
			e.printStackTrace();
		}
		System.out.println("프로그램 정상 종료!");
	}
}

위와 같이 throws가 붙은 greet() 메서드 호출 시 해당 메서드가 호출되고 있는 메인함수 쪽에서 예외처리를 진행할 수 있도록 하는 것이 바람직하다.

위와 같이 예외처리가 잘 이루어지고, 프로그램이 정상 종료된 것을 확인할 수 있다.

 

public class ThrowsEx2 {
	public void aaa(int n) throws Exception {
		System.out.println("aaa 호출");
		int i = 10 / n;
		System.out.println("계산 결과 : " + i);
		System.out.println("aaa 실행 중");
	}
	
	public void bbb() throws Exception {
		System.out.println("bbb 호출");
		aaa(0);
		System.out.println("bbb 실행 중");
	}
	
	public void ccc() throws Exception {
		System.out.println("ccc 호출");
		bbb();
		System.out.println("ccc 실행 종료");
	}
	
	public ThrowsEx2() throws Exception {
		System.out.println("생성자 호출");
		ccc();
		System.out.println("생성자 실행 종료");
	}
	
	public static void main(String[] args) {
		try {
			ThrowsEx2 te = new ThrowsEx2();
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println("진짜 코드 호출 끝!");
	}
}

 

4) throw

- 예외를 강제로 발생시키려면 throw 키워드 이용 → 개발자가 직접 예외 클래스를 정의하여 만들 수 있음

public class ThrowEx {
	public static int calcSum(int n) throws Exception {
		// 프로그램이 throw 구문을 만나는 순간 예외를 즉시 발생시키고,
		// 해당 예외를 처리해줄 catch 블록이 있는지 검색
		if(n <= 0) {
			throw new Exception(); // 예외도 클래스로 정의되기 때문에 인스턴스 생성
		}
		int sum = 0;
		for(int i = 1; i <= n; i++) {
			sum += i;
		}
		return sum;
	}
	
	public static void main(String[] args) {
		try {
			int result1 = calcSum(100);
			System.out.println("1~100까지의 누적합 : " + result1);
			
			int result2 = calcSum(-100);
			System.out.println("1~100까지의 누적합 : " + result2);
		} catch (Exception e) {
			e.printStackTrace();
			System.err.println("매개값을 양수로 전달해주세요.");
		}
	}
}

throw 키워드가 없다면 위 코드에서 논리적으로는 문제가 없기 때문에 정상적으로 작동한다.

하지만, 반복문 사용 시 i 값에 음수가 들어간다면 반복문을 실행하지 않기 때문에 위 예시에서는 throw를 사용하여 강제로 예외처리를 해주는 것이 좋다.

객체 생성 시 throw 키워드를 붙여주면 위와 같이 강제로 설정한 예외처리를 해주는 것을 확인할 수 있다.

 

5) 사용자 정의 예외

- 자바 표준 API에서 제공하는 예외 클래스만으로 다양한 종류의 예외를 표현할 수 없는 문제가 발생

- 일반 예외로 선언할 경우 Exception 클래스 상속, 실행 예외로 선언할 경우 RuntimeException 클래스 상속

- 사용자 정의 예외 클래스의 이름은 Exception으로 끝나는 것이 좋음

// 잔고 불충분 예외
// 사용자 정의 예외 클래스 생성 시 Exception 클래스나 RuntimeException 클래스 상속
public class BalanceInsufficientException extends RuntimeException {
	// 일반적으로 사용자 정의 예외 클래스를 만들 때는 
	// 기본 생성자와 예외원인 메세지를 받는 생성자를 두 개 오버로딩하여 선언만 해줌
	public BalanceInsufficientException() {};
	
	public BalanceInsufficientException(String message) {
		super(message);
	}
}
// 음수값 입금 예외
public class DepositMinusMoneyException extends RuntimeException {
	public DepositMinusMoneyException() {}
	
	public DepositMinusMoneyException(String message) {
		super(message);
	}
}
public class Account {
	private long balance;
	
	public long getBalance() {
		return this.balance;
	}
	
	// 음수로 입금할 경우 강제 예외처리
	public void deposit(int money) throws DepositMinusMoneyException {
		if (money < 0) {
			throw new DepositMinusMoneyException("음수로 입금할 수 없습니다.");
		}
		this.balance += money;
	}
	
	// 인출 시 잔액이 부족한 경우 강제 예외처리
	public void withdraw(int money) throws BalanceInsufficientException {
		if(this.balance < money) {
			throw new BalanceInsufficientException("잔고가 부족합니다.");
		}
		this.balance -= money;
	}
}
public class MainClass {
	public static void main(String[] args) {
		Account acc = new Account();
		
		try {
			acc.deposit(100000);
			System.out.println("입금 후 잔액 : " + acc.getBalance() + "원");
			acc.withdraw(100000);
		} catch(BalanceInsufficientException e) {
			// 예외 클래스가 제공하는 getMessage() 메서드는 예외의 원인 메세지를 String 타입으로 리턴
			// 자바 표준 API에서 제공하는 다양한 예외클래스들은 각각의 예외 원인 메세지가 기본적으로 객체 안에 저장
			e.printStackTrace();
			// 생성자에서 제공해준 메세지 그대로 출력
			System.err.println(e.getMessage());
		} catch(DepositMinusMoneyException e) {
			e.printStackTrace();
			System.err.println(e.getMessage());
		}
		System.out.println("출금 후 잔액 : " + acc.getBalance() +"원");
	}
}

위와 같이 어떤 종류의 예외가 발생했는지 정확히 알 수 있기 때문에 유지보수성을 높일 수 있다.

'네트워크캠퍼스 > JAVA' 카테고리의 다른 글

자바 API  (0) 2024.01.18
자바의 예외처리전략  (0) 2024.01.18
인터페이스  (0) 2024.01.16
추상화  (0) 2024.01.15
final  (0) 2024.01.15

1. Shell Script

→ 실행할 명령어를 미리 파일에 작성해두고 매크로처럼 실행

1) 셔뱅을 이용하는 방법

ex) du -h ~ | tall -n 1 : 홈 디렉토리의 파일 사용량 출력

위와 같은 명령어는 직접 타이핑하기 불편함 쉘 스크립트로 작성해두고 짧게 실행하는 것이 효율적

#!/bin/bash : 셔뱅

#! 뒤에 오는 파일/경로를 실행매개로 간주하고 명령을 내린다는 의미 → 어디에서 해당 파일을 실행하든 /bin/bash를 통해 실행

위와 같이 해당 파일에 실행 권한을 준 후 ./파일명을 통해 실행하면 위와 같이 동일한 결과가 출력되는 것을 확인할 수 있다.

 

2) source 명령어를 이용하는 방법

위와 같이 source 명령어를 이용해서도 쉘 스크립트 실행이 가능하고,

source를 사용하면 셔뱅을 적지 않아도 현재 실행한 쉘을 이용해 스크립트를 실행한다.

위와 같이 "."를 사용하여 source 명령어를 대체할 수 있지만 가독성 문제로 source를 사용하여 실행한다.

 

3) source와 ./ 실행의 차이점

위와 같이 vim 에디터를 이용해 test1.sh 파일을 생성하고, poiuqwer라는 사전에 지정된 적 없는 리눅스 명령어를 실행한다.

alias 명령어로 별명을 등록할 수 있고, 해당 명령을 실행하면 poiuqwer은 ls -alF로 대체된다.

또한, source 명령어로 해당 파일을 실행해보면 ls -alF 명령을 수행한 결과가 잘 출력되는 것을 확인할 수 있다.

하지만, 위와 같이 . 명령어를 사용하여 실행하면 command not found 오류가 발생하는 것을 확인할 수 있다.

. 명령어로 실행 시 새로운 쉘을 하나 더 순간적으로 열게 되는데 이 때 새로운 쉘에는 alias 설정이 되어 있지 않기 때문에 해당 명령을 수행하지 못한다.

 

4) 쉘스크립트의 배치

→ 파일 관리 용이성을 위해 쉘스크립트를 모아두어야 함

먼저, ~/bin 디렉토리를 생성하고 해당 경로로 모든 쉘 스크립트를 옮긴다.

어떤 경로에서든 파일명만 적어도 실행되도록 만드는 것이 효율적이다. → 전역 경로 설정

검색 경로에 ~/bin을 추가하기 위해 ~/.profile 파일에 위와 같은 PATH를 추가해준다.

위 명령어를 실행하면 즉시 적용되고, 해당 작업을 수행한 계정은 어디서든 .sh 파일을 호출할 수 있다.

위와 같이 파일명만 입력해도 쉘스크립트에 작성해뒀던 명령어가 잘 실행되는 것을 확인할 수 있다.

 

5) 전역 경로 비활성화

shopt -u sourcepath 명령어를 사용하면 source 명령어 사용 시 해당 단축경로를 비활성화할 수 있다.

위와 같이 현재 경로에 test.sh 파일이 없기 때문에 source 명령어를 사용하여 실행하면 오류가 발생하는 것을 확인할 수 있다.

 

2. Shell Script 작성하기

1) 개행

- 실제 쉘 스크립트는 여러줄로 작성

- 여러 줄 명령어를 순차적으로 실행시킬 때 기본적으로 엔터키를 눌러 개행시키면 순차적으로 하나씩 실행

위와 같이 엔터로 개행시킨후 실행해보면 쉘스크립트에 작성했던 명령들이 잘 수행되는 것을 확인할 수 있다.

- 엔터키 개행 대신 ;로 대체 가능

위와 같이 ; 로 수정해도 같은 결과로 동작되는 것을 확인할 수 있다.

 

2) 개행 무시

\ (역슬래시)를 사용하여 여러줄을 한 줄에 쓴 것처럼 동작시킬 수있다.

위와 같이 개행이 있지만 echo "root" 명령을 한 결과가 출력되는 것을 확인할 수 있다.

 

3) 주석 : #

 

4) 변수 

변수명=저장할내역 : 변수 저장

$변수명 : 변수값 참조

기본적으로 위와 같이 변수를 저장하고 사용할 수 있다.

\$문자 : 일반문자 그대로 출력

\\$문자 : 백슬래시 문자(변수값) 출력

\\\$문자 : 백슬래시 일반문자 출력

 

5) quote : 따옴표

홑따옴표 : 변수값 포매팅 X

쌍따옴표 : 변수값 포매팅 O

위와 같이 홑따옴표는 일반 문자를 그대로 출력하고, 쌍따옴표는 해당 이름의 변수값이 출력되는 것을 확인할 수 있다.

만약 변수값 대입이 아닌 $name을 출력하고 싶다면 마찬가지로 \ (역슬래쉬)를 붙여주면 된다.

 

6) 명령어 치환

특정 명령어를 수행한 결과를 파일 이름 등으로 사용하고 싶은 경우 $(명령어) 로 이용 가능

위와 같이 $(명령어)를 이용해 변수를 생성하고 파일 생성 명령어 touch를 이용하는 쉘스크립트를 작성했다.

쉘스크립트를 실행해보면 위와 같이 touch $filename 명령이 잘 수행된 것을 확인할 수 있다.

 

7) 파라미터 전달

쉘 스크립트에서는 파라미터의 위치에 따라 $번호에 해당하는 변수에 대입된다. ($0부터 시작)

위와 같은 쉘스크립트를 작성해주고

위 파일을 실행해보면 위와 같이 파라미터 위치에 따라 0부터 순서대로 해당 변수에 대입되는 것을 확인할 수 있다.

위와 같이 전달된 인자의 개수가 몇 개인지는 $#를 사용하여 조회할 수 있다.

 

8) 제어문

① if문

- if [ 명령어 ]; then ~ else ~ fi

위와 같이 첫번째 파라미터 값이 bin이면 OK를, 아니면 NO를 출력하는 조건문을 작성했다.

※ if [ 명령어 ]; 입력 시 대괄호 안에 공백을 주의해야 한다.

※ 세미콜론이 있다면 then과 조건식이 같이 놓일 수 있지만 생략했다면 다음줄로 내려야 한다.

위와 같이 출력 결과가 잘 수행되는 것을 확인할 수 있다.

 

- 명령어의 종료 상태

$?를 사용하여 직전에 실행한 명령어의 상태를 조회할 수 있다.

기본적으로 명령어는 정상 종료 시 0을 가지지만, 에러 발생 시 0이 아닌 다른 번호를 가진다.

 

- if와 종료 상태

조건식을 작성하는 [ ] 역시 명령어이기 때문에 해당 조건식이 참이면 0, 거짓이면 0 이외의 숫자를 반환한다.

조건문 사용 시 반드시 [ ] 를 사용해야 하는 것은 아니고 위와 같이 참과 거짓을 판단할 수 있는 명령어라면 [ ] 없이도 사용이 가능하다.

 

- test 명령어로 [ ] 대신하기

위와 같은 조건문이 있을 때 [ ]를 test 명령어로 대체할 수 있다.

이처럼 [ ]를 사용했을 때와 같은 결과를 출력하는 것을 볼 수 있지만 [ ]가 가독성이 더 좋으므로 test 명령어를 잘 사용하지는 않는다.

 

- 문자열 비교

= 같다
!= 다르다
-n null이 아니다
-z null이다

위 스크립트에서는 첫 파라미터(filename)가 null이라면 default.dat을, 값이 있으면 filename을 출력해준다.

위와 같이 결과가 잘 출력되는 것을 확인할 수 있다.

 

- 정수 비교

-eq 같다
-ne 다르다
-lt 작다
-gt 크다
-le 작거나 같다
-ge 크거나 같다

위와 같이 기본적으로 max 변수에는 첫번째 파라미터 값이 들어 있고, -lt로 두 값을 비교하여 두번째 파라미터 값이 더크다면 max를 두 번째 파라미터로 넣어주는 조건문을 작성했다.

위와 같이 조건에 따라 결과가 잘 수행되는 것을 확인할 수 있다.

 

- 파일 비교

-e 파일 존재
-d 파일 존재하고, 디렉터리임
-h / -L 파일 존재하고, 심볼릭링크임
-f 파일 존재하고, 일반파일임
-r 파일 존재하고, 읽기 권한이 있음
-w 파일 존재하고, 쓰기 권한이 있음
-x 파일 존재하고, 실행 권한이 있음
file1 -nt file2 file1이 file2보다 최근에 변경됨
file1 -ot file2 file2가 file1보다 최근에 변경됨

 

- 연산자 결합

-a and 연산
-o or 연산
! not 연산

연산자 결합 역시 ( )를 이용하여 우선순위를 다르게 지정할 수도 있다.

 

- &&와 ||를 활용한 명령어 순차평가

&& 왼쪽이 참이어야 오른쪽을 실행
|| 왼쪽이 거짓일 때 오른쪽을 실행

위와 같이 && 연산자를 이용하여 iftest.sh 파일이 존재하기 때문에 ifex.sh의 내용을 잘 출력하는 것을 볼 수 있다.

위와 같이 || 연산자를 이용하여 ifor.sh 파일이 존재하지 않기 때문에 ifor.sh 파일을 잘 생성해주는 것을 볼 수 있다.

 

② for문

- for 변수 in 리스트 ~ do ~ done

위와 같이 반복문을 작성할 수 있고 name이라는 변수에 값을 차례로 넣어 출력하는 것을 확인할 수 있다.

head : 맨 위부터, tail : 맨 뒤부터

위와 같이 경로에 따라서는 와일드카드를 사용할 수도 있고, 현재 경로의 모든 .sh 파일의 내용을 세번째 줄까지 출력해주는 것을 확인할 수 있다.

 

- seq 1 5 : 1~5 출력

for을 쓰지 않고 seq을 이용하여 더 간단하게 반복문을 사용할 수 있다.

위와 같이 seq을 이용하여 현재 경로에 5개의 파일을 생성하라는 코드를 작성할 수 있다.

실행 후 확인해보면 위와 같이 5개의 파일이 잘 생성된 것을 확인할 수 있다.

 

- 커맨드라인으로 보낸 인자 일괄처리

"$@"를 in 우변에 사용하면 받은 파라미터를 전부 반복문 타겟으로 잡는다.

위 코드는 paratest.sh를 실행하며 넘긴 모든 인자를 $@에 받아 처리해준다는 의미이다.

이와 같이 파라미터 값들이 다 넘겨지고 출력되는 것을 확인할 수 있다.

 

③ case문 : if문보다 강한 분기처리

case 문자열 in 패턴1) ~ ;; 패턴2) ~ ;; esac

case문을 사용하여 첫번째 파라미터 값이 start나 stop인 경우에만 checked가 출력되도록 하는 코드를 작성했다.

위와 같이 분기문이 잘 처리되어 결과가 출력되는 것을 확인할 수 있다.

 

④ while문 : 조건이 거짓이 될 때까지 반복

i 값이 10보다 작은 경우 계속 반복하는 while문을 작성했다.

실행해보면 위와 같이 반복문이 수행된 결과가 잘 출력되는 것을 확인할 수 있다.

 

⑤ until문 : while문과 반대로 조건이 거짓인 동안만 실행

위와 같이 until은 while과 사용법이 동일하게 수행된다.

 

⑥ C언어식 반복문

위와 같이 C언어식으로 반복문을 작성하는 것도 가능하다.

이 때 괄호는 겹쳐야 하고, 겹친 괄호 내에서는 변수에 $를 붙이지 않는다는 것을 주의해야 한다.

실행해보면 위와 같이 반복문이 잘 수행되는 것을 확인할 수 있다.

 

9) 셀 내부에서 함수 활용하기

function 함수명 (){
	실행문;
}

function 함수명 {
	실행문;
}

함수명(){
	실행문;
}

위의 세 가지 방식으로 쉘 내부에서 함수를 활용할 수 있다. 주로 세번째 방식을 사용한다.

date 결과와 디렉터리의 용량을 보여주는 du 명령어를 수행한 결과를 마지막 1줄만 출력하라는 homesize() 함수를 선언했고, 선언 후 homesize 함수를 호출해준다.

※ 쉘 함수는 반드시 호출구문 위쪽에 위치해야 한다.

위와 같이 수행 결과가 잘 출력되는 것을 확인할 수 있다.

또한, 종료코드는 return 상태코드 형식으로 전달하면 된다.

'네트워크캠퍼스 > LINUX' 카테고리의 다른 글

크론잡과 크론탭  (0) 2024.02.21
Shell Script 실습  (0) 2024.02.20
Devops와 SE를 위한 리눅스 커널 이야기  (0) 2024.01.17
프로세스  (0) 2024.01.16
텍스트에디터  (0) 2024.01.15

1. 시스템 구성정보 확인하기

uname 커널 버전 관련 정보 조회
dmesg 디버깅 메세지 체크
dmidecode bios, system, processor
dmidecode memory
df 디스크 파티션 타입 정보 조회
smartctl 디스크의 물리적 정보 조회
lspci 네트워크 정보 조회
ethtool 네트워크 카드의 세팅 정보 조회

 

 

2. top 명령어를 통해 프로세스 정보 조회하기

1) top 명령어

- top : 시스템 정보 확인 가능

- 구동된 시간, 로그인된 사용자 숫자, 실행 중인 프로세스의 개수, cpu, memory, swap 메모리의 사용량

- 우선순위, 조정 우선순위, 가상배정 메모리, 실제배정 메모리, 공통사용영역 등

 

2) VIRT, RES, SHR

- VIRT : VIRT + RES + SHR를 모두 포함한 영역, 각 Task에 할당된 메모리 전체

- RES : 할당된 메모리 중 실제로 사용되고 있는 물리 메모리의 양

- SHR : 다른 프로세스와 공유 중인 메모리의 양

 

 

3. 가상 메모리 배정과 memory commit

1) memory  commit : 메모리에 쓰기 작업이 들어가야 진짜 할당이 되도록 하는 것

- 메모리는 동적으로 배정

- 처음부터 할당 시 비효율적 → 최대 배분 상한선만 정해놓고 실제 쓰기 작업 시 진짜 할당 진행

 

2) 가상 메모리 배정의 이유

- fork() 프로세스 콜 : 현재 실행 중인 프로세스와 똑같은 프로세스를 하나 더 할당 → 실질적으로 사용하는 영역만 배정

- COW(Copy On Write) : 복사된 메모리 영역에 실제 쓰기 작업이 발생한 후에 실질적인 메모리 할당 시작

 

 

4. 프로세스의 상태 변화

- SHR의 S 항목 : 프로세스 상태 확인 가능

D 디스크 혹은 네트워크 I/O를 위해 대기하는 프로세스
R 실행 중인 프로세스
S 요청한 리소스를 즉시 사용할 수 있는 상태의 프로세스
T 프로세스의 시스템콜을 추적하고 있는 상태
Z 부모 프로세스가 죽으 자식 프로세스
Zombie 프로세스라고 함

 

 

5. 프로세스의 우선순위

→ PR과 NI 항목을 통해 조절

- NI(Nice value) : 우선순위 → 숫자가 낮을수록 높은 값

- Run Queue : 우선순위별로 프로세스 연결

- Run Queue 상태에서 NI를 호출해 PR을 올리면 호출 우선순위가 올라가 실행될 확률이 높아지는 형식

 

 

6. Load Average

1) Load Average

- R/D 상태인 프로세스의 1, 5, 15분마다의 평균 개수

- 얼마나 많은 프로세스가 실행중이거나 대기중인지 나타내는 수치

- 값이 높을수록 실행/대기중인 프로세스가 많음을 의미

- 하나의 코어에 2개의 프로세스 vs 두 개의 코어에 2개의 프로세스

   → load average값은 같으나 가용자원 측면에서는 다르게 인식

위와 같이 uptime 명령어를 이용하여 load average를 계산할 수 있다.

 

2) CPU Bound vs I/O Bound

→ 부하의 종류에 따라 처리하는 방법론이 달라지기 때문에 구분하는 것이 중요

- CPU Bound : CPU의 자원(ex.연산)을 많이 필요로 하는 프로세스

- I/O Bound : 많은 I/O 자원(ex.디스크 쓰기)을 필요로 하는 프로세스

 

3) vmstat : 부하 원인 확인 (r, b 값이 중요)

- r : 현재 실행되기를 기다리거나 실행되고 있는 프로세스의 개수 → r이 높으면 CPU Bound일 확률이 높음

- b : I/O를 위해 대기열에 있는 프로세스의 개수 → b가 높으면 I/O Bound일 확률이 높음

 

4) Load Average가시스템에 끼치는 영향

Load Average 값이 같다고 해도 실제 시스템에 미치는 영향은 부하의 원인에 따라 달라짐

→ CPU나 I/O 자원에 대한 경합 정도에 따라 실제롤 딜레이되는 시간이 다를 수 있음

 

5) OS 버전과 Load Average

커널 차이로 인해 버그건 아니면 실제로 건 차이가 발생할 수도 있음

'네트워크캠퍼스 > LINUX' 카테고리의 다른 글

Shell Script 실습  (0) 2024.02.20
Shell Script  (0) 2024.01.17
프로세스  (0) 2024.01.16
텍스트에디터  (0) 2024.01.15
파일시스템  (0) 2024.01.11

1. 인터페이스(Interface)

- 객체의 사용 방법을 정의한 타입으로 객체의 교환성을 높여줌 → 다형성을 구성하는 매우 중요한 역할

- interface 키워드로 선언, 클래스 이름 뒤에 implements 키워드로 구현

- 상수와 메서드만을 구성멤버로 가짐

- 데이터를 저장할 수 없기 때문에 데이터를 저장할 객체 또는 정적 변수 선언 불가능

- 인터페이스 선언된 변수는 public static final을 생략하더라도 자동으로 붙음

- 인터페이스의 메서드를 추상메서드 형식으로 선언하면 abstract를 생략하더라도 자동으로 붙음

- extends 키워드를 사용하여 인터페이스 간의 상속 구현 가능, 다중 상속 표현 가능

 

public interface RemoteController {
	// 최대 배터리량, 최소 배터리량을 상수로 지정
	int MAX_BATTERY = 100;
	int MIN_BATTERY = 0;
	
	// 리모콘이 가져야 하는 필수 기능에 대해서만 정의
	public void turnOn();
	public void turnOff();
	public void showStatus();
}
public class TVRemoteController implements RemoteController {
	private final int inch;
	private int channel;
	
	public TVRemoteController(int inch) {
		this.inch = inch;
		this.channel = 1;
	}
	
	@Override
	public void turnOn() {
		System.out.println("TV를 켭니다.");
	}

	@Override
	public void turnOff() {
		System.out.println("TV를 끕니다.");
	}

	@Override
	public void showStatus() {
		System.out.println("화면크기 : " + this.inch);
		System.out.println("채널 : " + this.channel);
	}
	
	public void setChannelDown() {
		// 1번까지만 채널이 있음
		if(this.channel - 1 < 1) {
			this.channel = 1;
		} else {
			this.channel--;
		}
	}
	
	public void setChannelUp() {
		this.channel++;
	}
}
public class RobotCleanerRemoteController implements RemoteController{
	public String modelName;
	public String price;
	
	// 로봇청소기 생성자
	public RobotCleanerRemoteController(String modelName, String price) {
		this.modelName = modelName;
		this.price = price;
	}
	
	@Override
	public void turnOn() {
		System.out.println("로봇청소기를 켭니다.");
	}

	@Override
	public void turnOff() {
		System.out.println("로봇청소기를 끕니다.");
	}

	// 로봇청소기에 맞는 정보조회
	@Override
	public void showStatus() {
		System.out.println("모델명 : " + this.modelName);
		System.out.println("가격 : " + this.price);
	}
}
public class MainClass {

	public static void main(String[] args) {
		// 인터페이스 역시 구현체를 다형성 형식으로 받을 수 있음
		RemoteController rc = new TVRemoteController(50);
		//RemoteController rc = new RobotCleanerRemoteController("imou", "280000");
	
		rc.turnOn();
		rc.showStatus();
		rc.turnOff();
	}
}

위와 같이 인터페이스를 이용하여 해당하는 타입의 객체를 생성할 수 있고, 해당 객체에서 구현한 함수에 따라 내용이 다르게 출력, 즉 다형성이 활용되는 것을 확인할 수 있다.

 

 

2. has - a 관계

- 상속의 전제는 is - a 관계

- 현실에서는 is - a 관계가 아니더라도 다른 객체의 기능을 쓸 수 있는 경우가 많음

  → has - a 관계로 설정해 객체 간 사용 구현

※ 현업에서는 상속보다 합성을 많이 이용한다. 

public class Gun {
	private int bullet;
	private String modelName;
	private String gunNumber;
	
	public Gun(String modelName, String gunNumber) {
		this.bullet = 5;
		this.modelName = modelName;
		this.gunNumber = gunNumber;
	}
	
	public void shoot() {
		if(this.bullet > 0) {
			this.bullet--;
			System.out.println("총을 쐈습니다.");
		} else {
			System.out.println("방아쇠를 당겼지만 총알이 없습니다.");
		}
	}
	
	public void reload() {
		this.bullet = 5;
	}
}
public class Police {
	// 상속 없이 Gun 기능을 사용하기 위해 멤버변수도 Gun을 가짐
	private Gun gun;
	private String name;
	private int height;
	
	public Police(Gun gun, String name, int height) {
		this.gun = gun;
		this.name = name;
		this.height = height;
	}
	
	public void shoot() {
		this.gun.shoot();
	}
	
	public void showStatus() {
		System.out.println("소유총기 : " + this.gun);
		System.out.println("총기이름 : " + this.name);
		System.out.println("총기크기 : " + this.height);
	}
}
public class MainClass {
	public static void main(String[] args) {
		// Gun을 new 키워드로 생성해야 Police 생성자에 전달 가능
		Gun gun = new Gun("M-16", "369486");
		
		// Gun을 사전에 생성하지 않으면 넘길 방법이 없음
		Police police = new Police(gun, "나경찰", 180);

		police.shoot();
		police.shoot();
		police.shoot();
		police.shoot();
		police.shoot();
		police.shoot();
	}
}

'네트워크캠퍼스 > JAVA' 카테고리의 다른 글

자바의 예외처리전략  (0) 2024.01.18
예외처리  (0) 2024.01.17
추상화  (0) 2024.01.15
final  (0) 2024.01.15
싱글톤 패턴  (0) 2024.01.15

+ Recent posts