CORS(Cross-Origin Resource Sharing)는 웹 브라우저가 다른 출처의 리소스에 접근할 수 있는 권한을 부여하는 체제입니다. 이를 통해 웹 애플리케이션은 자신의 출처와 다른 출처의 리소스에 안전하게 접근할 수 있습니다. 즉, 무분별하게 클라이언트가 다른 리소스에 접근하는 것을 막는 보안 이슈입니다. CORS를 허용하려면 서버 측에서 응답에 접근 권한을 주는 헤더를 추가해야 합니다. 이를 위해서는 서버에서 CORS를 지원하는 미들웨어나 라이브러리를 사용하거나, 직접 HTTP 응답 헤더를 설정하는 방법을 사용할 수 있습니다.
2. Priority Queue에 대해 설명해주세요.
우선순위 큐(Priority Queue)는 각 요소가 우선순위를 가지고 있는 자료구조입니다. 요소들은 우선순위에 따라 정렬되어 있으며, 높은 우선순위의 요소가 낮은 우선순위의 요소보다 먼저 처리됩니다. 우선순위 큐는 힙(Heap)과 같은 자료구조를 사용하여 구현할 수 있습니다.
시스템 콜은 사용자가 커널 기능에 접근하기 위한 인터페이스입니다. 프로그램이 다른 프로그램을 사용하기 위한 인터페이스인 API와 유사합니다. 작동방식은 시스템 콜에는 번호가 할당되고 시스템 콜 인터페이스는 이 번호에 따라 색인되는 테이블을 유지합니다. 이 테이블은 응용 프로그램에서 시스템 콜을 호출하면 번호를 보고 해당 함수가 호출한 후 시스템 콜의 상태와 반환 값을 돌려줍니다.
(커널이란? 시스템의 모든 것을 완전히 통제하는 운영체제의 핵심이 되는 프로그램입니다)
🔥꼬리질문🔥
< 시스템 콜이 잘못 호출되면 어떤 문제가 발생할 수 있나요? >
시스템콜은 모든 컴퓨터 리소스에 접근할 수 있기 때문에 다양한 문제가 발생할 수 있습니다. 일반적인 문제로는 프로그램 충돌, 데이터 손상, 보안 취약 등이 있습니다. 시스템 콜을 잘못 호출하는 것을 방지하기 위해 할 수 있는 몇 가지 방법이 있습니다. 첫째, 시스템 콜을 호출하기 전에 문서를 주의 깊게 읽으십시오. 둘째, 시스템 콜에 올바른 인수를 전달했는지 확인하십시오. 셋째, 잘못된 메모리 위치에 액세스하지 마십시오. 넷째, 운영 체제의 보호 메커니즘을 우회하려고 하지 마십시오.
시스템 콜이 잘못 호출되었을 수 있다고 생각되면 시스템을 종료하고 다시 시작하십시오. 이렇게 하면 시스템이 손상된 데이터를 복구하고 보안 취약점을 수정하는 데 도움이 될 수 있습니다.
< 시스템 콜의 종류에는 어떤 것들이 있나요? >
프로세스 관리: 프로세스 생성, 프로세스 종료, 프로세스 전환, 프로세스 동기화와 같은 작업에 사용되는 시스템 콜입니다. 메모리 관리: 메모리 할당, 메모리 해제, 메모리 보호와 같은 작업에 사용되는 시스템 콜입니다. 파일 관리: 파일 생성, 파일 삭제, 파일 읽기, 파일 쓰기와 같은 작업에 사용되는 시스템 콜입니다. 장치 관리: 장치 열기, 장치 닫기, 장치 읽기, 장치 쓰기와 같은 작업에 사용되는 시스템 콜입니다. 네트워크 관리: 네트워크 소켓 생성, 네트워크 소켓 연결, 네트워크 소켓 통신과 같은 작업에 사용되는 시스템 콜입니다.
2. 자료구조에서의 Tree에 대해 설명해주세요.
Tree는 자료구조 중 하나로 계층적인 구조를 가지고 있습니다. Tree는 노드(node)와 노드를 연결하는 엣지(edge)로 구성됩니다. 각 노드는 하나 이상의 자식 노드를 가질 수 있으며, 최상위 노드인 루트(root) 노드는 부모 노드가 없습니다. Tree의 각 층을 레벨(level)이라고 하며, 루트 노드의 레벨은 0입니다. Tree는 이진 트리(binary tree), 이진 검색 트리(binary search tree), AVL 트리(AVL tree), B-트리(B-tree) 등 다양한 종류가 있습니다.
🔥꼬리질문🔥
< 트리에서 레벨은 어떤 역할을 하는 건가요? >
트리의 레벨은 루트 노드부터 시작해 아래로 갈수록 증가합니다. 트리의 레벨은 트리의 구조를 이해하고 분석하는데 중요한 역할을 합니다. 예를 들어, 완전 이진 트리(complete binary tree)는 높이가 k일 때, 레벨 1부터 k-1까지는 노드가 채워져 있고, 마지막 레벨 k에서는 왼쪽부터 오른쪽으로 노드가 차례대로 채워져 있어야 합니다2. 이처럼 트리의 구조와 종류를 파악하는데 레벨이 중요한 역할을 합니다.
< tree 자료구조에서 깊이(depth) 와 높이(height)는 어떻게 정의되나요? >
트리 데이터 구조에서 깊이(depth)는 루트 노드에서 특정 노드까지의 간선 수입니다. 루트 노드는 깊이가 0이고, 자식 노드는 깊이가 1입니다. 자식 노드의 깊이는 자식 노드의 자식 노드에 따라 결정됩니다. 트리 데이터 구조의 높이는 트리에서 가장 깊은 노드의 깊이입니다. 트리에 리프 노드(자식이 없는 노드)가 여러 개 있는 경우 트리의 높이는 가장 깊은 리프 노드의 깊이입니다. 트리의 깊이와 높이는 트리의 크기를 측정하는 데 사용할 수 있습니다. 트리의 크기는 트리의 노드 수로 정의할 수 있습니다. 트리의 높이는 트리의 노드 사이의 최대 거리로 정의할 수 있습니다.
JWT(JSON Web Token)는 사용자 인증 정보를 담은 토큰입니다. 서버와 클라이언트 간 정보를 주고 받을 때 HTTP 리퀘스트 헤더에 JWT를 넣어 서버는 별도의 인증 과정 없이 헤더에 포함되어 있는 JWT 정보를 통해 인증합니다. 일반적으로 Access token의 유효기간이 만료되면 Refresh token을 이용하여 새로운 Access token을 발급받습니다 다른 API 서비스 호출 시 인증 처리 방식은 서비스 제공자마다 다르며 일반적으로 Authorization header에 Access token을 담아서 보내거나, URL 파라미터로 Access token을 전달하는 방식 등이 있습니다.
🔥꼬리질문🔥
< 클라이언트의 토큰이 변경되었을 시 JWT를 사용하는 서버는 이를 어떻게 알아채나요? >
일반적으로 JWT를 사용하는 서버에서 클라이언트의 토큰이 변경되었을 때는, 서버에서는 이를 알아채지 못합니다. 클라이언트에서 토큰이 변경되었다면, 클라이언트는 새로운 토큰을 발급받아 서버에 전달해야 합니다. 이를 위해 클라이언트는 주기적으로 토큰을 갱신하거나, 토큰 만료 시간을 설정하여 만료되기 전에 새로운 토큰을 발급받도록 구현할 수 있습니다.
그러나 서버는 클라이언트의 토큰이 변경되었는지 여러가지 방법으로 확인할 수 있습니다. 예를 들어, 서버는 클라이언트의 MAC 주소를 암호화하여 JWT의 Payload에 저장할 수 있습니다. 그리고 클라이언트는 매 요청시 JWT와 함께 현재 MAC 주소를 함께 전송합니다. 서버는 복호화한 JWT 내부의 MAC 주소와 현재 요청 온 MAC 주소를 비교하여 같은 사용자인지 검증합니다. 또 다른 방법으로는 서버가 토큰의 유효성을 public key (RS256)나 secret (HS256)을 활용하여 검증할 수 있습니다.
< JWT를 구현할 때 주의해야 할 점은 무엇인가요? >
Payload가 많아지면 토큰이 커져서 서버의 부담이 갈 수 있습니다. 이를 해결하기 위해서는 Payload의 크기를 최소화하는 것이 좋습니다.
토큰이 재발급되기 전까지 사용자 정보가 갱신되더라도 적용되지 않는 문제가 있습니다. 이를 해결하기 위해서는 토큰의 유효기간을 짧게 설정하거나 사용자 정보가 변경될 때마다 토큰을 재발급하는 것이 좋습니다.
JWT의 취약점은 토큰이 노출되면 암호화에 의미가 없어진다는 점입니다. 따라서 JWT를 Local Storage에 저장하는 대신 쿠키에 저장하거나 서버에서 관리하는 것이 좋습니다.
< JWT 이외에도 사용자 인증을 위해 사용할 수 있는 다른 방법은 무엇인가요? >
세션 기반 인증: 이 방법에서는 서버가 인증된 각 사용자에 대해 세션을 생성하고 고유한 세션 식별자를 할당합니다. 세션 식별자는 일반적으로 클라이언트의 브라우저에 쿠키로 저장됩니다. 서버는 사용자를 인증하기 위한 각 요청과 함께 세션 식별자의 유효성을 검사합니다. 토큰 기반 인증: 토큰 기반 인증은 로그인 성공 시 클라이언트에 토큰을 발급하는 것과 관련됩니다. 토큰은 클라이언트 측(예: 로컬 저장소 또는 쿠키)에 저장하고 이후의 각 요청과 함께 보낼 수 있습니다. 서버는 토큰을 확인하여 사용자를 인증합니다. OAuth: OAuth는 자격 증명을 공유하지 않고 타사 애플리케이션이 사용자 데이터에 액세스할 수 있도록 허용하는 데 사용되는 인증 프로토콜입니다. 사용자는 Google, Facebook 또는 Twitter와 같은 플랫폼에서 기존 계정을 사용하여 인증할 수 있습니다. 생체 인증: 지문이나 안면 인식과 같은 생체 인증 방법은 고유한 물리적 특성을 사용하여 사용자의 신원을 확인합니다. 이러한 방법은 일반적으로 모바일 장치에서 사용되며 추가 보안 계층을 제공할 수 있습니다.
전통적인 방법으로 ID/PASSWORD도 있습니다.
2. 완전탐색 알고리즘에 대해 설명해주세요.
완전 검색 알고리즘은 가능한 모든 옵션을 체계적으로 확인하여 문제에 대한 솔루션을 찾는 데 사용되는 방법입니다. 최적의 솔루션을 찾도록 보장하는 간단하고 철저한 접근 방식이지만 계산 비용이 많이 들 수 있습니다. 따라서 일반적으로 문제 공간이 합리적인 시간과 리소스 내에서 탐색할 수 있을 만큼 충분히 작거나 최적의 솔루션을 찾는 것이 중요하고 더 효율적인 대안이 없을 때 사용됩니다.
🔥꼬리질문🔥
< 완전탐색 알고리즘이 빠른 시간 안에 해결할 수 없는 문제도 있나요? >
완전탐색 알고리즘은 가능한 모든 경우의 수를 일일이 나열하면서 답을 찾는 방법입니다 . 이 방식은 절대 답을 못 구하는 경우는 없으므로 나름 강력한 방법이지만, 답으로 가능한 경우의 수가 많은 경우에는 이용하기가 어려울 수 있습니다. 예를 들어, 탐색 공간의 크기가 입력 크기에 비례적으로 증가하는 경우, 완전탐색은 지수적으로 증가하는 시간 복잡도를 가질 수 있습니다. 따라서 입력의 크기가 커지면 완전탐색은 실용적으로 해결하기 어려워집니다. 따라서 완전탐색이 최적의 선택이 아닐 수 있는 경우, 효율적인 다른 알고리즘 및 최적화 기법을 사용하여 문제를 해결하는 것이 중요합니다.
< 완전탐색 알고리즘의 최적화 방법에는 어떤 것들이 있나요? >
백트래킹 (Backtracking): 백트래킹은 재귀적으로 가능한 모든 조합을 시도하면서 불필요한 계산을 줄이는 기법입니다. 조건을 만족하지 않으면 해당 가지를 폐기하고 다음 가지로 넘어갑니다. 이는 가능한 조합의 일부를 미리 제외하여 탐색 공간을 줄이는 효과를 가집니다. 가지치기 (Pruning): 가지치기는 조건을 사용하여 앞으로 탐색해야 할 가지를 제한하는 기법입니다. 조건을 통해 비효율적인 조합이나 더 이상 유망하지 않은 가지를 탐색에서 제외할 수 있습니다. 이는 불필요한 계산을 피하고 탐색 시간을 단축시킵니다. 메모이제이션 (Memoization): 메모이제이션은 이전에 계산한 결과를 저장하여 동일한 계산을 반복하지 않고 재사용하는 기법입니다. 계산 결과를 캐시하고 필요할 때마다 재활용함으로써 중복 계산을 피하고 성능을 향상시킬 수 있습니다. 인덱스 최적화 (Indexing Optimization): 문제에 따라 인덱스를 사용하여 탐색 범위를 제한하는 최적화 방법을 적용할 수 있습니다. 인덱스를 활용하여 필요한 부분만 탐색하고 중복되는 계산을 줄일 수 있습니다. 병렬화 (Parallelization): 탐색 과정을 여러 개의 스레드나 프로세스로 분할하여 병렬적으로 처리하는 것입니다. 병렬화는 다중 코어 또는 분산 시스템에서 성능을 향상시킬 수 있습니다. 탐색 순서 최적화 (Search Order Optimization): 탐색 순서를 조정하여 더 유망한 가지를 먼저 탐색하는 것입니다. 유망한 가지를 먼저 탐색함으로써 조기에 최적해를 찾을 가능성을 높이고 불필요한 계산을 최소화할 수 있습니다. 알고리즘 변경: 완전탐색 대신 더 효율적인 알고리즘으로 문제를 해결하는 방법을 고려할 수 있습니다. 문제의 특성과 제약 사항을 분석하여 최적화된 알고리즘을 사용할 수 있습니다.
NestJS는 Node.js 웹 애플리케이션을 구축하기 위한 프레임워크입니다. 특징은 아키텍처가 정의되어 개발자들 간에 협업하기 편하고, 타입스크립트를 기본으로 제공하며, 테스트 코드를 작성을 지원합니다.
🔥꼬리질문 : 프로젝트에서 Nest.js를 왜 사용하셨나요?🔥 Nest.js를 사용하게 된 가장 큰 이유는 아키텍처가 정의되어 있었기 때문입니다. 프로젝트를 진행하면서 많은 것을 팀원끼리 의사결정을 하여야 했는데, 자유로운 Node.js보단 아키텍처가 있는 Nest.js가 협업하기 편했습니다.
또한 개발에 자주 사용되는 기능들이 Nest.js에 내장되어 있습니다. express에서는 IoC와 유효성검사를 위한 기능을 설치해야 했지만, Nest.js는 이러한 기능들을 데코레이터를 통해 사용할 수 있기 때문에 Nest.js를 선택하였습니다.
🔥꼬리질문 : IoC에 대해 설명해주세요.🔥 IoC(Inversion of Control)는 제어의 역전이라는 뜻으로, 객체의 생성과 생명주기를 개발자가 아닌 프레임워크가 관리하는 것을 의미합니다. 이를 통해 개발자는 객체의 생성과 관리에 대한 부담을 덜 수 있으며, 코드의 재사용성과 유지보수성이 향상됩니다. 예를 들어, 전통적인 방식에서는 개발자가 직접 객체를 생성하고 관리해야 했습니다. 하지만 IoC가 적용된 경우, 프레임워크가 객체의 생성과 관리를 담당하며, 개발자는 필요한 객체를 프레임워크로부터 주입(DI:의존성 주입)받아 사용할 수 있습니다. (DI는 IoC의 한 형태로, 객체 간의 의존성을 프레임워크가 관리하고, 필요한 객체를 주입하는 방식을 의미합니다. 즉, DI는 IoC의 구현 방법 중 하나입니다.)
< 예상되는 질문리스트>
1. Nest.js는 무엇이며 다른 Node.js 프레임워크와 어떻게 다릅니까? 2. Nest.js 사용의 주요 기능과 이점은 무엇입니까? 3. Nest.js에서 종속성 주입은 어떻게 작동합니까? 4. Nest.js를 다른 데이터베이스 및 ORM 라이브러리와 함께 사용할 수 있습니까? 5. Nest.js는 인증 및 승인을 어떻게 처리합니까? 6. Nest.js에서 데코레이터의 역할은 무엇입니까? 7. Nest.js는 실시간 통신과 WebSocket을 지원합니까? 8. Nest.js에서 테스트는 어떻게 작동합니까? 일반적으로 사용되는 테스트 도구는 무엇입니까? 9. Nest.js는 마이크로서비스 구축에 적합합니까? 10. Nest.js의 미들웨어 개념과 사용 방법에 대해 설명해 주시겠습니까?
실제로 CPU가 느려지는 것은 아니지만 시스템의 전체적인 효율은 저하된다고 할 수 있습니다.
반면에 비동기는 요청을 보낸후, 응답 수락 여부와는 상관없이 다음 작업이 동작하는 방식입니다.
자원을 효율적으로 사용할 수 있으며, 비동기 요청이 완료되었을 때 콜백 함수가 자동으로 호출되어 작업을 처리합니다.
하지만 비동기 처리를 위해 여러개의 콜백함수를 중첩시키면 콜백지옥이 발생합니다.
이를 해결하기 위해 Promise를 도입하였고, 코드의 가독성을 높이기 위해 Async / Await가 추가로 도입되었습니다.
< 예상되는 질문리스트>
1. Node.js에 대해 설명해주세요.
Node.js는 확장성 있는 네트워크 애플리케이션 (특히 서버 사이드)에 사용되는 소프트웨어입니다.
자바스크립트를 활용하며, 논블로킹 I/O와 단일 스레드 이벤트 루프를 통한 높은 처리 성능을 가지고 있습니다.
( 서버 사이드(server-side)란 클라이언트-서버 모델에서 서버 측에서 일어나는 일을 말합니다.)
2. Node.js가 확장성이 크다는 이유는 무엇일까요?
Node.js는 비동기 I/O를 사용함으로써 상대적으로 적은 리소스 사용량으로 많은 수의 동시 연결을 처리할 수 있습니다.
이벤트 루프는 여러 요청의 실행을 효율적으로 관리하여 하나의 요청이 다른 요청을 차단하지 않도록 합니다.
Node.js는 내장 HTTP 서버 라이브러리를 포함하고 있어 웹 서버에서 아파치 등의 별도의 소프트웨어 없이 동작하는 것이 가능합니다.
V8의 기능을 활용하여 높은 처리량과 낮은 대기 시간을 달성하여 성능이 뛰어난 네트워크 애플리케이션을 개발하는 것에 적합합니다.
또한 NPM을 통해 다양한 모듈을 사용함으로써 개발속도와 효율성이 크게 향상됩니다.
이러한 이유로 Node.js가 확장성이 큰 네트워크 어플리케이션에 사용되는 소프트웨어라고 할 수 있습니다.
3. Node.js를 어떻게 웹 애플리케이션 구축할 수 있을까요?
일반적으로 Node.js에서는 Express와 같은 웹 프레임워크를 사용하여 웹 애플리케이션을 구축합니다. Express는 Node.js에서 가장 널리 사용되는 웹 프레임워크 중 하나로, 미들웨어와 라우팅 기능을 제공하여 웹 애플리케이션 개발을 쉽게 할 수 있도록 도와줍니다.
4. Express에 대해 설명해주세요.
Express는 Node.js에서 가장 널리 사용되는 웹 프레임워크 중 하나입니다.
Express는 웹 애플리케이션 개발을 쉽게 할 수 있도록 미들웨어와 라우팅 기능을 제공합니다.
미들웨어는 요청과 응답 사이에서 실행되는 함수로, 요청을 처리하거나 응답을 수정하는 등의 작업을 수행할 수 있습니다.
Express에서는 다양한 미들웨어가 제공되며, 개발자가 직접 미들웨어를 작성할 수도 있습니다. 라우팅은 클라이언트로부터 들어오는 요청을 적절한 핸들러 함수로 전달하는 기능입니다.
6. Node.js는 멀티스레딩을 지원합니까? (= Node.js는 CPU 집약적인 작업을 어떻게 처리합니까?)
Node.js는 기본적으로 단일 스레드로 작동합니다. 하지만 Node.js에서는 멀티스레딩을 지원하는 몇 가지 방법이 있습니다. Node.js의 child_process 모듈을 사용하면 자식 프로세스를 생성하여 멀티스레딩과 유사한 작업을 수행할 수 있습니다. 또한, cluster 모듈을 사용하면 다수의 코어에 로드 밸런싱이 가능하도록 프로세스 간에 소켓을 공유할 수 있습니다. 그리고 worker_threads 모듈을 사용하여 멀티스레딩을 지원합니다. worker_threads 모듈을 사용하면
새로운 스레드를 생성하고 데이터를 주고받을 수 있습니다.
7. Node.js를 프런트엔드 JavaScript 프레임워크와 통합할 수 있습니까?
Node.js는 프런트엔드 JavaScript 프레임워크와 통합하여 사용할 수 있습니다.
Node.js는 백엔드에서 사용되는 JavaScript 런타임이며, 프런트엔드 JavaScript 프레임워크는 클라이언트 사이드에서 사용됩니다. Node.js와 프런트엔드 JavaScript 프레임워크를 통합하여 사용하면, 백엔드와 프런트엔드 간의 데이터 교환을 쉽게 할 수 있습니다.
예를 들어, Node.js에서 Express와 같은 웹 프레임워크를 사용하여 RESTful API를 구현하고,
프런트엔드에서는 이 API를 호출하여 데이터를 주고받을 수 있습니다. Node.js는 React, Angular, Vue.js 등의 다양한 프런트엔드 JavaScript 프레임워크와 함께 사용할 수 있습니다.
8. 프로젝트에서 Node.js를 사용하는 장점과 단점은 무엇입니까? Node.js를 사용하는 장점으로는 다음과 같은 것들이 있습니다. 빠른 개발 속도: Node.js는 JavaScript 언어를 사용하며, npm을 통해 다양한 패키지를 제공합니다. 이를 통해 개발 속도를 높일 수 있습니다. 확장성: Node.js는 이벤트 기반, Non-blocking I/O 모델을 사용하여 확장성이 높습니다. 높은 부하에서도 안정적으로 작동할 수 있습니다. 통합성: Node.js는 JavaScript 프레임워크와 쉽게 통합할 수 있습니다. 백엔드와 프런트엔드 간의 데이터 교환을 쉽게 할 수 있습니다.
Node.js의 단점으로는 다음과 같은 것들이 있습니다. 단일 스레드: Node.js는 단일 스레드로 작동하기 때문에 CPU 집약적인 작업을 처리하는 데 어려움이 있을 수 있습니다. 콜백 지옥: Node.js에서 비동기 작업을 처리할 때 콜백 함수를 사용하는 경우, 코드의 가독성이 떨어지고 콜백 지옥에 빠질 수 있습니다.
TCP와 UDP는 모두 인터넷 프로토콜 스택의 전송 계층에서 사용되는 프로토콜입니다. TCP는 연결 지향형 프로토콜로, 높은 신뢰성을 보장하지만 속도가 느립니다. 반면, UDP는 비연결형 서비스로 신뢰성이 낮지만 속도가 빠르며 네트워크 부하가 적습니다. 간단하게 말하면, TCP는 신뢰성이 높은 전송이 필요할 때 사용하고, UDP는 연속성이 중요한 서비스에 자주 사용됩니다. 사용예시로는 TCP는 파일전송, 메일 등에서 주로 사용되며,
3-way handshake는 TCP 세션 연결을 위해 수행되는 과정입니다. 이 과정은 다음과 같습니다: 1. 클라이언트가 서버에게 SYN 패킷을 보내 세션 연결을 요청합니다. 2. 서버는 클라이언트의 SYN 요청을 받고, 클라이언트에게 요청을 수락한다는 ACK와 SYN을 보냅니다. 3. 클라이언트가 서버의 ACK를 받으면 세션이 설정됩니다.
4-way handshake는 TCP 세션 종료를 위해 수행되는 과정입니다. 이 과정은 다음과 같습니다: 1.클라이언트가 서버에게 FIN 패킷을 보내 세션 종료를 요청합니다. 2.서버는 클라이언트의 FIN 요청을 받고, 클라이언트에게 ACK를 보냅니다. 3.서버가 통신이 끝나면, 즉 연결을 종료할 준비가 되면 클라이언트에게 FIN 패킷을 보냅니다. 4.클라이언트가 서버의 FIN 패킷을 받고 ACK를 보내면 세션이 종료됩니다.
TCP 프로토콜에서 패킷의 재전송은 수신자로부터의 ACK(Acknowledgement)에 기반을 두고 이루어집니다. 수신자는 세그먼트를 받으면 다음 세그먼트를 보내 달라는 ACK를 전송합니다. 만약 송신자가 ACK를 받지 못하면 일정 시간을 대기한 후 패킷을 재전송합니다. 만약 수신자가 순서에 벗어난 세그먼트를 받으면 중복 ACK를 전송합니다. 이 경우 송신자는 중복 ACK를 받으면 패킷을 재전송합니다.
2. MST 알고리즘에 대해 설명해주세요.
MST는 Minimum Spanning Tree의 약자로, 최소 신장 트리를 의미합니다. 이는 그래프 내의 모든 정점을 포함하는 트리 중에서 사용된 간선들의 가중치 합이 최소인 트리를 말합니다. 간단하게 말하면, MST는 여러 개의 도시가 있을 때 각 도시를 모두 연결하는 도로망을 만들 때, 가장 적은 비용으로 만들 수 있는 도로망을 찾는 것과 같습니다. 이를 구하는 알고리즘으로는 Kruskal 알고리즘과 Prim 알고리즘이 대표적입니다.
Kruskal 알고리즘과 Prim 알고리즘은 모두 최소 신장 트리(Minimum Spanning Tree, MST)를 찾는 알고리즘입니다. 두 알고리즘 모두 O(ElogV)의 시간복잡도를 가지지만, 그 방법이 다릅니다.
Kruskal 알고리즘은 간선들을 가중치 순으로 정렬한 후, 가장 작은 가중치의 간선부터 선택하면서 사이클을 형성하지 않는 간선을 선택합니다. 이 과정에서 서로소 집합 자료 구조(유니온 파인드: 결합과 검색)를 이용하여 어떤 꼭짓점이 어떤 콤포넌트(component)에 속하는 지 추적합니다.
반면에 Prim 알고리즘은 시작 정점에서부터 출발하여 신장트리 집합을 단계적으로 확장해나가는 방법입니다. 이전 단계에서 만들어진 MST 집합에 인접한 정점들 중에서 최소 간선으로 연결된 정점을 선택하여 트리를 확장합니다.
Kruskal 알고리즘은 간선 선택을 기반으로 하는 반면, Prim 알고리즘은 정점 선택을 기반으로 합니다. Kruskal 알고리즘은 이전 단계에서 만들어진 신장 트리와는 상관없이 무조건 최소 간선만을 선택하는 방법이며, Prim 알고리즘은 이전 단계에서 만들어진 신장 트리를 확장하는 방법입니다.
MST는 그래프의 모든 정점을 포함하는 트리 중에서 간선의 가중치 합이 최소인 트리입니다. MST는 트리의 특수한 형태이므로 모든 정점들이 연결되어 있어야 하고 사이클을 포함해서는 안됩니다. 따라서 MST는 그래프에 있는 n개의 정점을 정확히 (n-1)개의 간선으로 연결합니다. 이러한 이유로 MST에서 사이클이 발생하는 경우는 없습니다.
OSI 7계층은 네트워크에서 통신이 일어나는 과정을 7단계로 나눈 것으로, 국제표준화기구 (ISO)에서 네트워크 간의 호환을 위해 OSI 7 계층이라는 표준 네트워크 모델을 만들었습니다. 이 모델은 물리 계층, 데이터 링크 계층, 네트워크 계층, 전송 계층, 세션 계층, 표현 계층 및 응용 계층으로 구성됩니다.
OSI 7계층은 다음과 같습니다:
1. 물리 계층: 전기적 신호로 변환하여 물리적인 전송이 가능하게 합니다. (리피터 , 케이블 , 허브) 2. 데이터 링크 계층: 인접한 노드간의 신뢰성 있는 데이터 전송을 제어합니다. ( 브릿지 , 스위치 ) 3. 네트워크 계층: 종단간 전송을 위한 경로 설정을 담당합니다. ( 라우터 , IP ) 4. 전송 계층: 종단간 신뢰성 있는 데이터 전송을 담당합니다. ( TCP , UDP ) 5. 세션 계층: 응용 프로그램간의 논리적인 연결 생성 및 제어를 담당합니다. ( API , Socket ) 6. 표현 계층: 데이터 표현방식, 상이한 부호체계 간의 변화에 대해 규정합니다. ( JPEG , MPEG ) 7 .응용 계층: 사용자가 네트워크에 접근할 수 있도록 해주는 인터페이스를 제공합니다. ( HTTP , FTP , DNS )
계층을 3단계로 나누면,
계층1,2,3(네트워크 지원계층) : 하나의 장치에서 다른 장치로 전송되는 데이터의 물리적인 면을 처리
계층5,6,7(사용자 지원계층) : 관계 없는 소프트웨어 시스템 간 상호 운용성 제공
계층4(전송계층) : 네트워크 지원 계층과 사용자 지원 계층을 서로 연결, 네트워크 지원 계층이 전송한 것을 사용자 지원 계층이 사용할 수 있는 형태가 되도록 보장
SSH와 TLS는 둘 다 네트워크 통신을 보호하는 데 사용되는 프로토콜이지만 다른 용도로 사용됩니다.
SSH는 Secure Shell의 약자이며 네트워크를 통해 두 장치 간에 암호화된 보안 연결을 설정하는 데 사용되는 프로토콜입니다. 일반적으로 원격 로그인 및 파일 전송에 사용됩니다. SSH를 사용하여 원격 장치에 연결하면 장치 간에 교환되는 모든 데이터가 암호화되므로 네트워크에서 도청 중인 공격자가 데이터를 가로채거나 변조할 수 없습니다.
TLS는 Transport Layer Security의 약자로 웹 트래픽을 보호하는 데 사용되는 프로토콜입니다. SSL(Secure Sockets Layer)의 후속 제품이며 일반적으로 웹 서버와 웹 브라우저 간의 보안 통신을 제공하는 데 사용됩니다. HTTPS를 사용하여 웹 사이트를 방문할 때 TLS는 브라우저와 웹 서버 간에 전송되는 데이터를 암호화하는 데 사용되는 프로토콜입니다. TLS는 두 당사자 간에 교환되는 데이터의 인증, 기밀성 및 무결성을 제공합니다.
요약하면 SSH는 일반적으로 원격 액세스를 위해 두 장치 간에 보안 연결을 설정하는 데 사용되는 반면 TLS는 웹 트래픽을 보호하고 서버와 클라이언트 간에 교환되는 데이터에 대한 기밀성, 무결성 및 인증을 제공하는 데 사용됩니다.
데이터 링크 계층에서 사용되는 에러 체크 기술에는 패리티 검사(Parity Check), 순환 중복 검사(CRC, Cycle Redundancy Check), 해밍 코드(Hamming Code) 등이 있습니다. 패리티 검사(Parity Check)는 데이터 뒤에 하나의 비트를 추가하여 오류가 있는지 찾아내는 방법입니다. 데이터는 0과 1로만 이루어져 있기 때문에, 마지막에 비트 하나를 추가해서 데이터의 1의 총개수를 짝수 또는 홀수로 맞추는 형태입니다. 순환 중복 검사(CRC, Cycle Redundancy Check)는 데이터를 나누어서 나머지 연산을 수행하여 오류를 검출하는 방법입니다. 이 방법은 패리티 검사보다 더 강력한 오류 검출 기능을 가지고 있습니다. 해밍 코드(Hamming Code)는 데이터 전송 중 발생할 수 있는 오류를 검출하고 수정하는 기능을 가진 에러 정정 코드입니다. 이 코드는 데이터의 일부 비트를 추가하여 오류 검출 및 정정을 수행합니다. 이러한 기술들은 데이터 전송 중 발생할 수 있는 오류를 검출하고 수정하는 역할을 합니다.
HTTP, SMTP, FTP, DNS, SNMP 및 SIP를 비롯한 여러 네트워크 프로토콜이 OSI 계층 7을 기반으로 합니다. 이러한 프로토콜은 웹 브라우징, 이메일, 파일 전송, 네트워크 관리 및 VoIP와 같은 다양한 서비스를 사용자 애플리케이션에 제공합니다.
2. DP 알고리즘에 대해 설명해주세요.
DP(Dynamic Programming) 알고리즘은 이미 계산된 결과는 별도의 메모리 영역에 저장하여 다시 계산하기 않도록 설계함으로써 메모리를 적절히 사용하여 수행 시간 효율성을 향상시키는 방법입니다. DP구현 방법은 일반적으로 Top-down(하향식)과 Bottom-up(상향식)으로 구성됩니다. 대표적인 예시로는 피보나치 수열이 있습니다.
DP 알고리즘의 대표적인 예시로 피보나치 수열이 있습니다. 피보나치 수열은 다음과 같은 점화식으로 표현됩니다: F(n) = F(n-1) + F(n-2). 이를 단순 재귀 함수로 구현하면 같은 함수를 계속해서 중복 호출을 하기 때문에 시간복잡도가 O(2^n)이 됩니다. 이는 n이 커질수록 엄청나게 커지게 됩니다.
하지만 DP 알고리즘을 사용하면 중복 호출을 방지할 수 있습니다. 이미 계산된 결과(하위 문제)는 별도의 메모리 영역에 저장하여 다시 계산하지 않도록 설계함으로써 메모리를 적절히 사용하여 수행 시간 효율성을 비약적으로 향상시키는 것입니다. 이를 메모이제이션(Memoization)이라고 합니다. 정상적으로 중복호출을 방지하면 시간복잡도가 O(n)이 됩니다.
🔥꼬리질문🔥
<이미 계산된 결과를 다시 계산할 일이 없으면 오히려 메모리 사용이 효율적이지 않은 건 아닌가요? 이 관점에 대해서는 어떻게 생각하시나요?>
이미 계산된 결과를 다시 계산할 일이 없다면 DP 알고리즘을 사용하지 않아도 됩니다. 그러나 DP 알고리즘은 이미 계산된 결과를 다시 계산하지 않아야만 효율적으로 동작할 수 있기 때문에, 입력 크기가 작은 경우에는 DP 알고리즘보다 더 간단한 알고리즘을 사용하는 것이 더 효율적일 수 있습니다. 하지만 입력 크기가 큰 경우에는 DP 알고리즘이 더 효율적일 수 있습니다. 따라서 DP 알고리즘을 사용할지 여부는 입력 크기와 같은 여러 가지 요소를 고려하여 결정해야 합니다.
<DP 알고리즘을 사용할 때 고려해야 할 최적 부분 구조와 중복 부분 문제에 대해서 설명해주세요.>
DP 알고리즘에서 최적 부분 구조(Optimal Substructure)란 큰 문제를 작은 문제로 나눌 수 있으며, 작은 문제의 최적해를 이용해서 큰 문제의 최적해를 구할 수 있는 성질을 말합니다. (최적해(Optimal Solution)란 주어진 문제에서 가장 좋은 해결책을 말합니다.) 중복 부분 문제(Overlapping Subproblems)란 작은 문제들이 서로 중복되어 반복적으로 해결되는 성질을 말합니다. DP 알고리즘은 이러한 최적 부분 구조와 중복 부분 문제를 이용하여 문제를 해결합니다. 따라서 DP 알고리즘을 사용할 때는 이러한 성질을 고려하여 적절한 구현 방법을 선택해야 합니다.
동적 프로그래밍(DP)은 최적화 문제를 더 작은 하위 문제로 나누고 각 하위 문제를 한 번만 해결하고 결과를 저장하여 중복 계산을 방지하여 최적화 문제를 해결하는 데 사용되는 기술입니다. DP는 광범위한 문제를 해결하는 데 사용할 수 있지만 다음과 같은 특성을 가진 문제에 가장 일반적으로 사용됩니다.
겹치는 하위 문제: 문제는 더 작은 하위 문제로 나눌 수 있으며 이러한 하위 문제에는 겹치는 하위 하위 문제가 있습니다. 이는 동일한 하위 하위 문제를 여러 번 풀 수 있으며 중복 계산을 피하기 위해 DP를 사용할 수 있음을 의미합니다.
최적의 하위 구조: 더 큰 문제에 대한 최적의 솔루션은 더 작은 하위 문제에 대한 솔루션을 결합하여 찾을 수 있습니다. 즉, 더 작은 하위 문제에 대한 솔루션을 사용하여 더 큰 문제에 대한 솔루션을 얻을 수 있습니다.
독립 하위 문제: 하위 문제는 서로 독립적으로 풀 수 있습니다. 이는 하나의 하위 문제에 대한 솔루션이 다른 하위 문제에 대한 솔루션에 의존하지 않음을 의미합니다.
일반적인 예에는 그래프에서 최단 경로 찾기, 두 문자열 간의 가장 긴 공통 하위 시퀀스 계산 및 배열에서 하위 배열의 최대 합계 찾기가 포함됩니다.
DFS (Depth First Search)는 깊이 우선 탐색으로 그래프의 모든 정점을 방문하는 방법 중 하나입니다. BFS (Breadth First Search)는 너비 우선 탐색으로 시작 노드를 방문한 후,
시작 노드에 있는 인접한 모든 노드들을 우선 방문하는 방법입니다.
DFS는 적은 메모리를 사용하고 깊은 단계에 있는 노드를 빠르게 찾을 수 있지만, 최단 경로를 보장하지 않습니다. 반면 BFS는 최단 경로를 보장하지만, 더 많은 저장 공간이 필요합니다.
DFS와 BFS의 시간복잡도는 O(N)으로 동일하지만
DFS는 스택 또는 재귀함수로 구현하는 반면
BFS는 큐를 이용해서 구현한다는 차이점이 있습니다.
2. Isolation level에 대해 설명해주세요.
트랜젝션에서 Isolation level(격리 수준)은 데이터베이스 트랜잭션에서 동시성 제어를 위해 사용되는 개념입니다.
데이터베이스에서 여러 트랜잭션이 동시에 실행될 때, 격리 수준을 설정하여 각 트랜잭션 간에 데이터의 일관성과 안정성을 보장할 수 있습니다. 격리 수준이 높을수록 트랜잭션 간의 상호작용을 제한하여 무결성을 유지시켜주지만 성능에 영향을 미칩니다. 격리 수준은 여러 단계가 있으며 일반적인 격리수준으로 Read Uncommitted, Read Committed, Repeatable Read, Serializable 의 네 가지 수준이 있습니다.
1. Read uncommitted 다른 트랜잭션이 수정 중인 데이터를 읽을 수 있습니다. 2. Read committed 다른 트랜잭션이 수정을 완료한 데이터만 읽을 수 있습니다. 3. Repeatable read 트랜잭션 내에서 같은 쿼리를 실행하면 항상 같은 결과가 나옵니다. 4. Serializable 가장 엄격한 격리 수준입니다. 다른 트랜잭션에서는 해당 데이터에 접근할 수 없습니다.