LiveKit | The all-in-one Voice AI platform
Build, deploy, and scale realtime agents. Open source. Enterprise grade.
livekit.io
- 확장 가능하고 유연한 webRTC SFU (Selective Forwarding Unit) 기반의 오픈소스 미디어 서버
- 실시간 비디오, 오디오 및 데이터 통신을 위한 도구 제공
- 개발자가 web RTC 애플리케이션을 쉽게 구축할 수 있도록 지원
=> LiveKit은 실시간 영상통화, 음성채팅 기능을 직접 구현할 수 있게 도와주는 오픈소스 라이브러리
Q. 왜 필요한가 ?
요즘 앱들 보면 이런 기능 많죠?
1 :1 영상통화 기능 (틴더, 헬로톡)
라이브 방송 (인스타그램 라이브, 유튜브 라이브)
원격회의 (줌, 팀즈)
게임 내 음성채팅 (배틀그라운드, 포트나이트)
이런 걸 처음부터 직접 구현하려면 어렵고 복잡하기 때문에 Livekit 같은 webRTC 기반 미디어 서버 도구가 필요하다.
어떻게 동작하나?
1. 사용자는 방(Room)에 입장
Zoom 회의방처럼 방 단위로 사용자 연결을 관리함
2. 마이크/카메라 데이터를 Livekit 서버로 보낸다
LiveKit 서버는 이걸 다른 참가자들에게 전달해줌 (중개서버역할)
3. 실시간으로 영상과 음성이 동기화되어 전송됨
참가자들은 서로 화면과 음성을 거의 지연없이 볼 수 있다
예 : 내가 React로 만든 웹사이트에, 친구와 영상통화 기능을 넣고 싶다!
-> Livekit을 쓰면 직접 Zoom같은 기능을 붙일 수 있음
쓰이는 기술
- WebRTC – 실시간 영상·음성 전송 기술의 표준
- SFU(Server-side Forwarding Unit) – 서버가 미디어 스트림을 중계
- gRPC / HTTP – API 통신
- Docker / Kubernetes – 서버 배포 환경
- JWT 인증 – 사용자 권한 처리
webRTC란?
Web Real-Time Communication의 줄임말로, 웹 브라우저끼리 실시간으로 영상, 음성, 데이터를 주고받을 수 있게 해주는 기술
즉, 설치 없이 웹에서 바로 화상통화, 음성통화, 채팅, 파일 전송 등을 가능하게 만들어주는 기술
주요 기능
| 🎥 MediaStream | 내 카메라, 마이크에서 영상·음성 가져오기 |
| 🔗 RTCPeerConnection | 상대방과 직접 연결(P2P) 하기 위한 통신 통로 |
| 📩 RTCDataChannel | 텍스트, 이미지, 파일 전송 등 데이터 교환용 채널 |
동작 흐름
1. A가 B와 화상 통화를 하고 싶다
2. A와 B는 먼저 신호를 주고 받아서 서로를 인지
3. RTCPeerConnection을 통해 직접 연결 (p2p)을 만듦
4. 연결되면 각자의 카메라/마이트를 상대방에게 보냄
5. 동시에 데이터를 주고받을 수 있는 DataChannel도 쓸 수 있다.
1. 📌 전체 목적 요약
이 코드는:
- 사용자가 브라우저에서 /hello-servlet 주소로 요청하면,
- 서버가 “Hello World!”라는 HTML을 UTF-8 인코딩으로 만들어 응답하는
- 자바 서블릿 기본 구조입니다.
여기서 배우는 건 다음 4가지입니다:
학습 포인트 설명
| 🧠 서블릿 구조 | 클래스 생명주기, 메서드 흐름 이해 |
| 🌐 HTTP 요청·응답 처리 | HttpServletRequest, HttpServletResponse 사용 |
| 🧾 HTML 응답 출력 | Java 코드에서 직접 HTML 작성하는 방식 |
| 🌍 인코딩 처리 | UTF-8 설정을 통해 한글 깨짐 방지 |
2. 📦 전체 코드 구조 한눈에 보기
package com.koreait.servlet; // 패키지 선언
import java.io.*; // PrintWriter, IOException 등 I/O 클래스 사용
import jakarta.servlet.http.*; // HttpServlet 등 서블릿 클래스 사용
import jakarta.servlet.annotation.*; // 서블릿을 애너테이션으로 등록
@WebServlet(name = "helloServlet", value = "/hello-servlet") // 브라우저 URL 매핑
public class HelloServlet extends HttpServlet {
private String message; // 출력할 메시지를 저장할 변수
public void init() { // 서블릿 최초 1회 초기화
message = "Hello World!";
}
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.setContentType("text/html; charset=UTF-8"); // 브라우저에 HTML 형식 + 한글 인코딩 설정
response.setCharacterEncoding("UTF-8"); // 응답 문자 인코딩 설정
try (PrintWriter out = response.getWriter()) { // try-with-resources로 안전하게 출력 스트림 관리
out.println("<!DOCTYPE html>"); // HTML5 문서 타입
out.println("<html><body>");
out.println("<h1>" + message + "</h1>"); // 실제 출력할 메시지 삽입
out.println("</body></html>");
}
}
public void destroy() { // 톰캣이 종료되거나 서블릿이 언로드될 때 호출됨
}
}
3. 🧠 서블릿의 생명주기(Life Cycle)
서블릿은 자바 객체이지만 웹 서버(Tomcat)에서 다음처럼 특별하게 관리돼요:
단계 메서드 설명
| 초기화 | init() | 서블릿이 처음 로딩될 때 딱 1번 실행됨 |
| 요청 처리 | doGet() / doPost() | 클라이언트 요청이 들어올 때마다 호출 |
| 종료 | destroy() | 서버가 꺼지거나 서블릿이 사라질 때 호출 |
즉,
처음 한 번만 init()
요청이 올 때마다 doGet()
서버 종료되면 destroy()
4. 🧾 코드 한 줄씩 상세 해석
📌 패키지 및 import
package com.koreait.servlet;
- 이 자바 파일이 속한 폴더 구조. src/com/koreait/servlet/HelloServlet.java
import java.io.*;
- HTML을 출력할 때 필요한 PrintWriter, 예외처리용 IOException 등을 포함
import jakarta.servlet.http.*;
import jakarta.servlet.annotation.*;
- 서블릿 생성을 위한 표준 라이브러리
HttpServlet, HttpServletRequest, HttpServletResponse, @WebServlet 등 포함
📌 서블릿 등록
@WebServlet(name = "helloServlet", value = "/hello-servlet")
- 이 클래스가 서블릿임을 서버에게 알리는 역할
- 브라우저에서 http://localhost:8080/hello-servlet로 접속하면 이 서블릿이 실행됨
🧠 과거에는 web.xml로 등록했지만, 요즘은 이렇게 애너테이션 방식이 더 일반적
📌 변수 선언 & init()
private String message;
- 클래스 멤버변수로, 이후 응답에 출력할 텍스트 저장소
public void init() {
message = "Hello World!";
}
- 서블릿이 최초로 로딩될 때 단 한 번만 실행
- message 변수에 출력할 텍스트 저장
📌 doGet(): 요청 처리
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
- 클라이언트가 GET 방식으로 접속하면 실행됨
- 보통 주소창에 입력하거나 a 태그, form의 기본 요청이 모두 GET
response.setContentType("text/html; charset=UTF-8");
response.setCharacterEncoding("UTF-8");
- 응답의 타입을 HTML로 지정
- 인코딩을 UTF-8로 설정하여 한글 깨짐 방지
try (PrintWriter out = response.getWriter()) {
- 브라우저로 HTML을 출력할 스트림(PrintWriter) 을 생성
- try-with-resources 문법을 사용 → 자동으로 닫힘 (자바 7부터 지원)
out.println("<!DOCTYPE html>");
out.println("<html><body>");
out.println("<h1>" + message + "</h1>");
out.println("</body></html>");
- HTML 코드를 문자열로 작성해서 출력
- message 변수에 저장된 "Hello World!"가 <h1> 태그로 표시됨
📌 destroy(): 정리 메서드
public void destroy() {
}
- 톰캣 종료, 서블릿 언로드 시 실행됨
- 보통 DB 연결 종료, 파일 닫기 등 리소스 정리에 사용
5. 💡 실무에서 이 구조가 왜 중요할까?
실무 포인트 설명
| ✅ 요청 처리 구조의 기본 | 모든 웹 로직은 결국 요청 → 처리 → 응답으로 구성됨 |
| ✅ REST API 개발 기반 | 이 구조 위에 GET, POST, PUT, DELETE 같은 HTTP 메서드를 구현 |
| ✅ 보안 처리, 세션 처리 | request, response를 통해 로그인, 인증처리 가능 |
| ✅ JSP, HTML 분리 구조 학습 전 필수 | 화면과 로직을 나누기 전에 전체 흐름 파악 가능 |
6. 🚀 확장 아이디어 및 다음 학습 주제
학습 내용 예시
| doPost() 구현 | 사용자 입력받기 (폼 데이터 처리) |
| request.getParameter() | 클라이언트가 보낸 데이터 읽기 |
| JSP 연동 | RequestDispatcher.forward() 사용 |
| DB 연동 | JDBC로 메시지 DB에서 불러오기 |
| session/cookie 관리 | 로그인 구현으로 확장 가능 |
✅ 최종 요약
이 서블릿 예제는 사용자의 GET 요청(/hello-servlet)을 받아 Hello World! 메시지를 UTF-8 HTML로 응답하는 기본 웹 서버 코드입니다. init() → doGet() → destroy() 흐름을 중심으로 서블릿의 동작 구조를 처음부터 끝까지 학습할 수 있으며, 실무에서의 웹 요청 처리의 핵심 개념을 포함하고 있습니다.
MyController.jsp
📌 한 줄 요약
.korea로 끝나는 URL 요청이 들어오면, MyController가 모든 요청을 가로채서 로그인/회원가입/정보수정 등 요청에 맞는 기능을 분기 처리합니다.
📁 이 코드의 실무 역할
역할 설명
| ✅ URL 매핑 중앙 처리기 | /join.korea, /login.korea 등 여러 URL을 하나의 컨트롤러에서 처리 |
| ✅ GET/POST 통합 처리기 | GET이든 POST든 하나의 doAction() 메서드에서 처리 |
| ✅ 한글 인코딩 처리 | 폼 전송 시 깨짐 방지 |
| ✅ 명령어 추출 로직 | URL에서 어떤 기능을 실행할지 구분함 (command) |
🧠 흐름 요약 다이어그램 (초보자용)
[ 브라우저 요청: /controller/join.korea ]
↓
[ MyController 서블릿 호출 ]
↓
[ doGet() 또는 doPost() 호출됨 ]
↓
[ 모든 요청은 doAction() 으로 위임됨 ]
↓
[ 요청 URL에서 command 추출 → 분기 처리 ]
↓
[ 회원가입, 로그인 등 기능 실행 ]
🧾 코드 해석 – 한 줄씩 뜯어보기
📦 1) 패키지 및 import
package com.koreait.servlet.controller;
- 이 파일은 controller라는 역할(요청 분기처리)을 담당하는 폴더에 속해 있음
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import jakarta.servlet.annotation.*;
- 자바 웹 개발에 필요한 서블릿 관련 클래스들:
- HttpServletRequest: 요청정보
- HttpServletResponse: 응답정보
- @WebServlet: 서블릿 URL 매핑을 위한 애너테이션
🌐 2) URL 패턴 등록
@WebServlet("*.korea")
*.korea로 끝나는 모든 요청을 이 컨트롤러가 처리하게 만듦
예 의미
| /controller/join.korea | 회원가입 요청 |
| /controller/login.korea | 로그인 요청 |
| /controller/modify.korea | 정보 수정 요청 |
과거엔 web.xml에서 설정했지만, 요즘은 이렇게 애너테이션으로 관리
🔁 3) doGet, doPost → 공통 처리
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doAction(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doAction(req, resp);
}
- GET, POST 방식 모두 하나의 메서드로 통합 처리함
protected void doAction(...) { ... }
- 모든 요청은 이 doAction()에서 공통적으로 처리됨
→ 실무에서도 가장 자주 쓰는 방식!
✂️ 4) 요청 URI에서 기능명 추출
String uri = req.getRequestURI(); // 전체 요청 경로
String contextPath = req.getContextPath(); // 프로젝트 루트 경로
String command = uri.substring(contextPath.length()); // 기능만 추출
예를 들어, 주소가 이렇다면:
http://localhost:8080/servlet_war_exploded/controller/join.korea
변수 결과
| uri | /servlet_war_exploded/controller/join.korea |
| contextPath | /servlet_war_exploded |
| command | /controller/join.korea |
즉, command를 통해 지금 어떤 기능을 요청했는지 파악할 수 있음!
🧠 5) 기능 분기 처리 로직
if (command.equals("/controller/join.korea")) {
System.out.println("회원가입 작업!");
} else if (command.equals("/controller/login.korea")) {
System.out.println("로그인 작업!");
} else if (command.equals("controller/info.korea")) {
System.out.println("회원정보 작업!");
} else if (command.equals("controller/modify.korea")) {
System.out.println("회원정보 수정 작업!");
}
- command 값에 따라 각 기능을 조건문 if-else로 분기
- 나중에는 System.out.println() 자리에 실제 로직 (예: DB 저장, 로그인 인증 등) 을 넣게 됨
🧪 실무에서 어떻게 확장하나?
확장 포인트 설명
| JSP 연동 | 각 기능별 JSP 파일에 포워딩 (예: request.getRequestDispatcher().forward()) |
| DB 연동 | 회원가입 시 DB에 사용자 정보 저장 |
| Command 패턴 적용 | 각 기능별 클래스를 분리하여 유지보수 편하게 |
| 세션/쿠키 활용 | 로그인 인증 처리 및 세션 관리 |
| 예외처리 + 리다이렉트 | 잘못된 요청 처리 등 UX 향상 |
📎 연관해서 공부할 것
개념 이유
| 서블릿의 생명주기 | 왜 init(), doGet(), doPost()가 중요한지 이해 |
| request.getParameter() | 폼 데이터 처리 필수 |
| RequestDispatcher vs sendRedirect | 화면 이동 방식 차이 |
| JSP와 MVC 패턴 | 뷰, 모델, 컨트롤러 구조 이해 |
| Servlet + JDBC 연동 | DB까지 연결하면 실무의 기본이 완성됨 |
✅ 최종 요약
이 컨트롤러는 .korea로 끝나는 모든 요청을 하나의 서블릿에서 처리하며, GET, POST 요청을 구분하지 않고 doAction()으로 통합 처리합니다. URL에서 기능명을 추출하여 join.korea, login.korea 등으로 분기 처리하며, 실제 웹 시스템에서 로그인, 회원가입, 수정 등을 구현하는 기초 구조입니다.
EL (Expression Language)
JSP에서 자바 코드를 직접 쓰지 않고, 간단한 문법으로 데이터를 표현할 수 있도록 도와주는 언어
request.getAttribute("name") <- 기존에 name 변수에 담아져 있던 거 가져왕!
print 하려면 <%= request.getAttribute("name")%> 이렇게 썼었음
근데 ${name} 이렇게 써도 됨
내장 객체 우선순위 (이름이 동일했을 때, 아래의 순서대로 먼저 찍힘)
1. pageScope : 현재 페이지에서만 사용할 수 있는 속성
2. requestScope : request 객체
3. sessionScope
4. applicationScope
EL의 주요 기능
${user}
${user.userid} = ${user["userid"]} <- user가 객체고 그 안에 필드가 존재한다면 이 형식도 가능함
${user[0]} <- 배열이라면 이런식으로 접근 가능
${user["key"]} : 맵
* 연산도 가능하다
${price+1000} // 산술연산,비교연산 등 다 가능 (mod : 나머지)
* 삼항연산도 가능
${price > 10000 ? "비싸다" : "싸다" }
&{empty name} // name이 null 또는 빈 문자열이면 true
예제
<%--
Created by IntelliJ IDEA.
User: dmddn
Date: 2025-06-10
Time: 오전 9:36
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>el</title>
</head>
<body>
<h2>el</h2>
<p>el 태그는 jsp의 표현식을 대체함</p>
<%-- http://localhost:8080/model_war_exploded/EL/1_basic.jsp --%>
${1+2}<br>
${'안녕하세요, EL'} <br>
${1 >= 2}<br>
${1<2 || 1>2}<br>
${1<2 && 1>2}<br>
${1==1 ? '같다' : '다르다'}<br>
${'김사과'=='김사과'}<br>
<%--같다고 나옴.--%>
${'김사과'eq'김사과'}<br>
<%--같다고 나옴.--%>
${5 gt 3}<br>
${3 lt 4}<br>
</body>
</html>

JSTL (JavaServer pages Standard Tag Library)
JSP에서 자주 사용하는 기능들을 표준 태그로 제공하는 라이브러리
자바 코드 없이도 jsp에서 반복, 조건, 변수 설정, 출력 날짜 포맷 등을 html 태그처럼 사용할 수 있다.
<p>성인입니다.</p>
<% } %><c:if test="${age > 19}"><p>성인입니다.</p></c:if><% for(String item : list) { %>
<p>반복합니다.</p>
<% } %><c:forEach var="item" items="${list}"><p>반복합니다.</p></c:forEach>