๐[Network] ์น์์ผ(WebSocket) ํ๋กํ ์ฝ์ด๋ ๋ฌด์์ผ๊น์?
- ์น์์ผ(WebSocket)์ ํด๋ผ์ด์ธํธ(์: ๋ธ๋ผ์ฐ์ )์ ์๋ฒ ๊ฐ์ ์๋ฐฉํฅ(full-duplex) ํต์ ์ ๊ฐ๋ฅํ๊ฒ ํ๋ ํ๋กํ ์ฝ์ ๋๋ค.
- ์น์์ผ(WebSocket)์ HTTP(Hypertext Transfer Protocol)์๋ ๋ค๋ฅธ ํ๋กํ ์ฝ๋ก, ํ์คํ๋ ๋ฐฉ์์ผ๋ก ์ค์๊ฐ ๋ฐ์ดํฐ ๊ตํ์ ์ง์ํฉ๋๋ค.
- ์น์์ผ(WebSocket)์ ์ด๊ธฐ ์ฐ๊ฒฐ๋ง HTTP๋ก ์์ํ๊ณ , ์ดํ์๋ ํ๋์ ์ฐ๊ฒฐ์ ์ ์งํ๋ฉฐ ์๋ฐฉํฅ ๋ฐ์ดํฐ ์ ์ก์ ์ง์ํฉ๋๋ค.
- ์ด๋ฅผ ํตํด ์น ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ค์๊ฐ ์ํธ ์์ฉ์ ์ฝ๊ฒ ๊ตฌํํ ์ ์์ต๋๋ค.
1๏ธโฃ ์น์์ผ ํ๋กํ ์ฝ์ ํน์ง.
1๏ธโฃ ์๋ฐฉํฅ ํต์ฑ(Full-Duplex)
- ํด๋ผ์ด์ธํธ์ ์๋ฒ๊ฐ ๋์์ ๋ฐ์ดํฐ๋ฅผ ์ฃผ๊ณ ๋ฐ์ ์ ์์ต๋๋ค.
- HTTP์ฒ๋ผ ํด๋ผ์ด์ธํธ์ ์์ฒญ-์๋ต ๊ตฌ์กฐ๊ฐ ์๋๋ผ, ์ฐ๊ฒฐ์ด ์ ์ง๋๋ ๋์ ์ธ์ ๋ ์ง ๋ฐ์ดํฐ ์ ์ก์ด ๊ฐ๋ฅํฉ๋๋ค.
2๏ธโฃ ์ง์์ ์ธ ์ฐ๊ฒฐ(Persistent Connection)
- ํ๋ฒ ์ฐ๊ฒฐ์ด ์ค์ ๋๋ฉด ํด๋ผ์ด์ธํธ์ ์๋ฒ ๊ฐ์ ์ง์์ ์ธ ์ฐ๊ฒฐ์ด ์ ์ง๋ฉ๋๋ค.
- ์ฌ์ฐ๊ฒฐ์ ์ค๋ฒํค๋๊ฐ ์์ด, ํจ์จ์ ์ธ ๋ฐ์ดํฐ ๊ตํ์ด ๊ฐ๋ฅํฉ๋๋ค.
3๏ธโฃ ๋ฎ์ ์ค๋ฒํค๋
- HTTP๋ณด๋ค ํจ์ฌ ๊ฐ๋ฒผ์ด ํค๋๋ฅผ ์ฌ์ฉํ๋ฏ๋ก ๋ฐ์ดํฐ ์ ์ก๋์ด ์ ๊ณ , ์๋๊ฐ ๋น ๋ฆ
๋๋ค.
- ํนํ, ์ค์๊ฐ ์ ํ๋ฆฌ์ผ์ด์ ์์ ํจ์จ์ ์ ๋๋ค.
4๏ธโฃ ํ์ค ํ๋กํ ์ฝ
- RFC 6455์์ ํ์ค์ผ๋ก ์ ์๋ฉ๋๋ค.
- ๋๋ถ๋ถ์ ์ต์ ๋ธ๋ผ์ฐ์ ์ ์๋ฒ ํ๋ ์์ํฌ์์ ์ง์ํฉ๋๋ค.
2๏ธโฃ ์น์์ผ์ ์๋ ๋ฐฉ์.
1๏ธโฃ ํธ๋์ ฐ์ดํฌ(Handshake)
- ํด๋ผ์ด์ธํธ์ ์๋ฒ ๊ฐ์ ์ด๊ธฐ ์ฐ๊ฒฐ์ HTTP ์์ฒญ์ ์ฌ์ฉํ์ฌ ์ด๋ฃจ์ด์ง๋๋ค.
- ํด๋ผ์ด์ธํธ๊ฐ ์๋ฒ์ ์
๊ทธ๋ ์ด๋ ์์ฒญ์ ๋ณด๋
๋๋ค:
GET /chat HTTP/1.1 Host: example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== Sec-WebSocket-Version: 13
- ์๋ฒ๋ ์ด๋ฅผ ์น์ธํ์ฌ ์๋ตํฉ๋๋ค:
HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
2๏ธโฃ ์ฐ๊ฒฐ์ด ์ ๊ทธ๋ ์ด๋๋จ.
- HTTP ์ฐ๊ฒฐ์ด WebSocket ์ฐ๊ฒฐ๋ก ์ ๊ทธ๋ ์ด๋๋๋ฉฐ, ์ดํ์๋ ์ง์์ ์ธ ์๋ฐฉํฅ ํต์ ์ด ๊ฐ๋ฅํฉ๋๋ค.
3๏ธโฃ ๋ฐ์ดํฐ ์ ์ก.
- ์ฐ๊ฒฐ์ด ์ค์ ๋๋ฉด, ํด๋ผ์ด์ธํธ์ ์๋ฒ๋ ๋ฉ์์ง๋ฅผ ์์ ๋กญ๊ฒ ์ก์์ ํ ์ ์์ต๋๋ค.
4๏ธโฃ ์ฐ๊ฒฐ ์ข ๋ฃ.
- ํ์์ ๋ฐ๋ผ ํด๋ผ์ด์ธํธ๋ ์๋ฒ๊ฐ ์ฐ๊ฒฐ์ ์ข ๋ฃ(Close)ํ ์ ์์ต๋๋ค.
3๏ธโฃ ์น์์ผ์ ์ฅ์ .
1๏ธโฃ ์ค์๊ฐ ํต์ .
- HTTP์ ์์ฒญ-์๋ต ๋ชจ๋ธ๊ณผ ๋ฌ๋ฆฌ, ์ค์๊ฐ ์ํธ์์ฉ์ ์ง์ํฉ๋๋ค.
- ์ค์๊ฐ ์ฑํ , ๊ฒ์, ์ฃผ์ ๊ฐ๊ฒฉ ์ ๋ฐ์ดํธ ๋ฑ์์ ํจ์จ์ ์ ๋๋ค.
2๏ธโฃ ํจ์จ์ฑ.
- HTTP์ ๋นํด ์ค๋ฒํค๋๊ฐ ์ ๊ณ , ๋์ญํญ ์๋น๊ฐ ๋ฎ์ต๋๋ค.
- ์ง์์ ์ธ ์ฐ๊ฒฐ๋ก ์ธํด ๋ค์์ ๋ฉ์์ง๋ฅผ ๋น ๋ฅด๊ฒ ๊ตํ ๊ฐ๋ฅ.
3๏ธโฃ ํ์ฅ์ฑ.
- ๋์ ํธ๋ํฝ์์๋ ํจ์จ์ ์ผ๋ก ์๋ํ๋ฏ๋ก, ๋๊ท๋ชจ ์ค์๊ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ํฉํฉ๋๋ค.
4๏ธโฃ ์น์์ผ๊ณผ HTTP์ ์ฐจ์ด.
ํน์ง | HTTP | WebSocket |
---|---|---|
ํต์ ๋ฐฉ์ | ์์ฒญ-์๋ต(Request-Response) | ์๋ฐฉํฅ(Full-Duplex) |
์ฐ๊ฒฐ ์ ์ง | ์์ฒญ๋ง๋ค ์ ์ฐ๊ฒฐ ์์ฑ | ์ฐ๊ฒฐ ์ ์ง(Persistent) |
์ค๋ฒํค๋ | ๋น๊ต์ ๋์ ํค๋ ์ค๋ฒํค๋ | ๋ฎ์ ํค๋ ์ค๋ฒํค๋ |
์ฌ์ฉ ์ฌ๋ก | ์ผ๋ฐ ์น ํ์ด์ง, REST API | ์ค์๊ฐ ์ฑํ , ๊ฒ์, ์คํธ๋ฆฌ๋ฐ |
5๏ธโฃ ์น์์ผ์ ์ฌ์ฉ ์ฌ๋ก.
1๏ธโฃ ์ค์๊ฐ ์ฑํ ์ ํ๋ฆฌ์ผ์ด์ .
- ์: Slack, Discord
2๏ธโฃ ๋ผ์ด๋ธ ์ ๋ฐ์ดํธ.
- ์ฃผ์ ์ฌ๊ฒฉ, ์คํฌ์ธ ๊ฒฝ๊ธฐ ์ ์.
3๏ธโฃ ์ค์๊ฐ ๊ฒ์.
- ๋ฉํฐํ๋ ์ด์ด ๊ฒ์์์ ๋น ๋ฅธ ๋ฐ์ดํฐ ๊ตํ.
4๏ธโฃ IoT ์ ํ๋ฆฌ์ผ์ด์ .
- ์ฅ์น ์ํ ๋ชจ๋ํฐ๋ง ๋ฐ ์ ์ด.
5๏ธโฃ ํ์ ๋๊ตฌ.
- ๋ฌธ์ ํธ์ง, ํ์ ํ์ ๋ฑ.
6๏ธโฃ ์น์์ผ ์ฌ์ฉ ์์ .
1๏ธโฃ JavaScript ํด๋ผ์ด์ธํธ ์ฝ๋(๋ธ๋ผ์ฐ์ ํด๋ผ์ด์ธํธ)
const socket = new WebSocket('ws://localhost:8080/ws/chat');
// ์ฐ๊ฒฐ ์ด๋ฆผ
socket.onopen = () => {
console.log('WebSocket ์ฐ๊ฒฐ ์ด๋ฆผ');
socket.send('Hello from client!');
};
// ๋ฉ์์ง ์์
socket.onmessage = (event) => {
console.log('์๋ฒ๋ก๋ถํฐ ๋ฐ์ ๋ฉ์์ง:', event.data);
};
// ์ฐ๊ฒฐ ๋ซํ
socket.onclose = () => {
console.log('WebSocket ์ฐ๊ฒฐ ๋ซํ');
};
// ์๋ฌ ๋ฐ์
socket.onerror = (error) => {
console.error('WebSocket ์๋ฌ:', error);
};
2๏ธโฃ Spring Boot WebSocket ์๋ฒ ์ฝ๋.
1๏ธโฃ ์์กด์ฑ ์ถ๊ฐ.
- Spring Boot ํ๋ก์ ํธ์ build.gradle ํ์ผ์ WebSocket ๊ด๋ จ ์์กด์ฑ์ ์ถ๊ฐํฉ๋๋ค.
implementation 'org.springframework.boot:spring-boot-starter-websocket'
2๏ธโฃ WebSocket Config ์ค์ .
- WebSocket ์๋ํฌ์ธํธ์ ํธ๋ค๋ฌ๋ฅผ ์ค์ ํ๋
@Configuration
ํด๋์ค๋ฅผ ์์ฑํฉ๋๋ค.
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
// WebSocket ํธ๋ค๋ฌ ๋ฑ๋ก
registry.addHandler(new MyWebSocketHandler(), "/ws/chat")
.setAllowedOrigins("*"); // CORS ์ค์
}
}
3๏ธโฃ WebSocket ํธ๋ค๋ฌ ์์ฑ.
- WebSocket ์ฐ๊ฒฐ์ ์ฒ๋ฆฌํ๋ ํธ๋ค๋ฌ๋ฅผ ์์ฑํฉ๋๋ค.
- ํด๋ผ์ด์ธํธ์์ ๋ฐ์ ๋ฉ์์ง๋ฅผ ๋ก๊ทธ์ ์ถ๋ ฅํ๊ณ ๋ค์ ํด๋ผ์ด์ธํธ๋ก ์ ๋ฌํฉ๋๋ค.
```java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
public class MyWebSocketHandler extends TextWebSocketHandler {
private static final Logger logger = LoggerFactory.getLogger(MyWebSocketHandler.class);
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
logger.info("ํด๋ผ์ด์ธํธ ์ฐ๊ฒฐ๋จ: {}", session.getId());
}
@Override
public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
logger.info("๋ฐ์ ๋ฉ์์ง: {}", message.getPayload());
// ํด๋ผ์ด์ธํธ๋ก ๋ฉ์์ง ๋ค์ ์ ์ก(Echo)
session.sendMessage(new TextMessage("์๋ฒ ์๋ต: " + message.getPayload()));
}
@Override
public void afterConnectionClosed(WebSocketSession session, org.springframework.web.socket.CloseStatus staus) throws Exception {
logger.info("ํด๋ผ์ด์ธํธ ์ฐ๊ฒฐ ์ข
๋ฃ: {}", session.getId());
} } ```
4๏ธโฃ Spring Boot Application ์คํ.
- Spring Boot ์ ํ๋ฆฌ์ผ์ด์
์ ์คํํ๋ฉด
/ws/chat
์๋ํฌ์ธํธ๋ก WebSocket ์ฐ๊ฒฐ์ ๋ฐ์ ์ ์์ต๋๋ค.
5๏ธโฃ ๋์ ํ์ธ.
-
- Spring Boot ์ ํ๋ฆฌ์ผ์ด์ ์ ์คํํฉ๋๋ค.
-
- ๋ธ๋ผ์ฐ์ ์์ WebSocket ํด๋ผ์ด์ธํธ๋ฅผ ์คํํฉ๋๋ค.
-
- ์๋ฒ์์ ํด๋ผ์ด์ธํธ๋ก ๋ฉ์์ง๋ฅผ ์ ์กํ๊ณ , ํด๋ผ์ด์ธํธ๊ฐ ๋ฐ์ ๋ฉ์์ง๋ฅผ ํ์ธํฉ๋๋ค.
6๏ธโฃ ๊ฒฐ๊ณผ.
-
- ํด๋ผ์ด์ธํธ ์ฝ์.
WebSocket ์ฐ๊ฒฐ ์ด๋ฆผ ์๋ฒ๋ก๋ถํฐ ๋ฐ์ ๋ฉ์์ง: ์๋ฒ ์๋ต: Hello from client!
- ํด๋ผ์ด์ธํธ ์ฝ์.
-
- ์๋ฒ ๋ก๊ทธ
ํด๋ผ์ด์ธํธ ์ฐ๊ฒฐ๋จ: f9351a2c-7f2e-4bd7-b930-bddf37e78e0d ๋ฐ์ ๋ฉ์์ง: Hello from client! ํด๋ผ์ด์ธํธ ์ฐ๊ฒฐ ์ข ๋ฃ: f9351a2c-7f2e-4bd7-b930-bddf37e78e0d
- ์๋ฒ ๋ก๊ทธ