Home > Network > 2024 > ๐ŸŒ[Network] ์›น์†Œ์ผ“(WebSocket) ํ”„๋กœํ† ์ฝœ์ด๋ž€ ๋ฌด์—‡์ผ๊นŒ์š”?

๐ŸŒ[Network] ์›น์†Œ์ผ“(WebSocket) ํ”„๋กœํ† ์ฝœ์ด๋ž€ ๋ฌด์—‡์ผ๊นŒ์š”?
Network

๐ŸŒ[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๏ธโƒฃ ๋™์ž‘ ํ™•์ธ.

    1. Spring Boot ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
    1. ๋ธŒ๋ผ์šฐ์ €์—์„œ WebSocket ํด๋ผ์ด์–ธํŠธ๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
    1. ์„œ๋ฒ„์—์„œ ํด๋ผ์ด์–ธํŠธ๋กœ ๋ฉ”์‹œ์ง€๋ฅผ ์ „์†กํ•˜๊ณ , ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ฐ›์€ ๋ฉ”์‹œ์ง€๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

6๏ธโƒฃ ๊ฒฐ๊ณผ.

    1. ํด๋ผ์ด์–ธํŠธ ์ฝ˜์†”.
      WebSocket ์—ฐ๊ฒฐ ์—ด๋ฆผ
      ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๋ฐ›์€ ๋ฉ”์‹œ์ง€: ์„œ๋ฒ„ ์‘๋‹ต: Hello from client!
      
    1. ์„œ๋ฒ„ ๋กœ๊ทธ
      ํด๋ผ์ด์–ธํŠธ ์—ฐ๊ฒฐ๋จ: f9351a2c-7f2e-4bd7-b930-bddf37e78e0d
      ๋ฐ›์€ ๋ฉ”์‹œ์ง€: Hello from client!
      ํด๋ผ์ด์–ธํŠธ ์—ฐ๊ฒฐ ์ข…๋ฃŒ: f9351a2c-7f2e-4bd7-b930-bddf37e78e0d