Skip to content

๐ŸŒ์›น์†Œ์ผ“ ์•Œ์•„๋ณด๊ธฐ

Changhyun-Hong edited this page Dec 5, 2024 · 1 revision

์›น์†Œ์ผ“

ํ”„๋กœํ† ์ฝœ ์กฐ์ฐจ ๋‹ค๋ฅด๋‹ค

์šฐ๋ฆฌ๊ฐ€ ํ”ํžˆ ์‚ฌ์šฉํ•˜๋Š” HTTP ํ”„๋กœํ† ์ฝœ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ ์›น์†Œ์ผ“ ํ”„๋กœํ† ์ฝœ (ws, wss)์„ ์‚ฌ์šฉํ•จ

  • http:// ๊ฐ€ ์•„๋‹Œ ws://๋‚˜ wss://์˜ ํ˜•ํƒœ๋ฅผ ๊ฐ–์Œ

ํ”„๋กœํ† ์ฝœ ๋น„๊ต

image

HTTP๋กœ๋Š” ์‹ค์‹œ๊ฐ„ ํ†ต์‹ ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ์ด์œ  (๋‹จ๋ฐฉํ–ฅ ํ†ต์‹ )

  • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์„œ๋ฒ„์—๊ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ด๋Š” ๊ฒƒ์€ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, ์ƒ๋Œ€๋ฐฉ์ด ๋‚ด ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›๋Š” ๊ฒƒ์€ ์ƒ๋Œ€๋ฐฉ์ด ํŠน๋ณ„ํ•œ ์š”์ฒญ์ด ์—†๋Š” ํ•œ ์ด๋ฃจ์–ด์งˆ ์ˆ˜๊ฐ€ ์—†์Œ
  • HTTP์˜ Polling ๊ธฐ๋ฒ•์œผ๋กœ ํ•ด๊ฒฐ๊ฐ€๋Šฅ
    • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ฃผ๊ธฐ์ ์œผ๋กœ ์„œ๋ฒ„์— ์š”์ฒญ์„ ๋ณด๋‚ด์„œ ์ƒ๋Œ€๊ฐ€ ์ƒˆ๋กœ์šด ์ฑ—์„ ๋ณด๋ƒˆ๋Š”์ง€ ํ™•์ธ
      • ์š”์ฒญ์ฃผ๊ธฐ์— ๋”ฐ๋ผ์„œ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ฐ›์„ ์ˆ˜๊ฐ€ ์—†์Œ
      • ๋ถˆํ•„์š”ํ•œ ์š”์ฒญ
    • Long Polling : ์„œ๋ฒ„๊ฐ€ ํด๋ผ์ด์–ธํŠธ ์š”์ฒญ์— ๋ฐ”๋กœ ์‘๋‹ตํ•˜์ง€ ์•Š๊ณ  ์—…๋ฐ์ดํŠธ๊ฐ€ ๋ฐœ์ƒํ•  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆผ
      • ์ƒ๋Œ€๋ฐฉ์ด ์ฑ—์„ ๋ณด๋‚ด๊ฑฐ๋‚˜ ํƒ€์ž„์•„์›ƒ์— ๊ฑธ๋ฆฌ๋ฉด ์‘๋‹ต์„ ๋ณด๋‚ด๊ณ  ํด๋ผ์ด์–ธํŠธ๋Š” ๋‹ค์‹œ ์š”์ฒญ์„ ๋ณด๋‚ด์„œ ๋‹ค์Œ ์‘๋‹ต์„ ๊ธฐ๋‹ค๋ฆผ
      • ๋ฐ์ดํ„ฐ ์—…๋ฐ์ดํŠธ์— ๋ฐ˜์‘ํ•˜๋Š” ์†๋„๋Š” ๋นจ๋ผ์ง€์ง€๋งŒ ์„œ๋ฒ„์˜ ๋ถ€๋‹ด์ด ์ปค์ง (์—ฌ๋Ÿฌ๋ช…์˜ ํ†ก๋ฐฉ)
  • ๋ฌผ๋ก  HTTP/2 ์ด์ƒ์—์„œ๋Š” ์–‘๋ฐฉํ–ฅ ํ†ต์‹ ์ด ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, ์žฅ์‹œ๊ฐ„์˜ ์–‘๋ฐฉํ–ฅ ํ†ต์‹ ์„ ์œ„ํ•œ ์„ค๊ณ„๋Š” ์•„๋‹˜

์›น์†Œ์ผ“์˜ ๊ณผ์ •

ํ•ธ๋“œ์‰์ดํฌ

  • ํด๋ผ์ด์–ธํŠธ๋Š” ์„œ๋ฒ„์—๊ฒŒ WebSocket์„ ์—ฐ๊ฒฐํ•˜์ž๋Š” ์š”์ฒญ์„ HTTP๋ฅผ ํ†ตํ•ด ๋ณด๋ƒ„
    • Upgrade์™€ Connection: Upgrade ํ—ค๋”๊ฐ€ ํฌํ•จ๋˜์–ด ์›น์†Œ์ผ“ ์ „ํ™˜์„ ์š”์ฒญ
  • ์„œ๋ฒ„๋Š” ๊ทธ๊ฒƒ์ด ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ ์ด๋ฅผ ์ˆ˜๋ฝํ•˜๋Š” ์‘๋‹ต์„ HTTP๋กœ ๋ณด๋ƒ„
    • 101 Switching Protocols ์‘๋‹ต์„ ๋ณด๋ƒ„
  • ํ•ธ๋“œ์‰์ดํฌ ๊ณผ์ •์ด ๋๋‚˜๊ฒŒ ๋˜๋ฉด ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„๋Š” WebSocket ํ”„๋กœํ† ์ฝœ์„ ์‚ฌ์šฉํ•˜์—ฌ ์†Œํ†ต

๋ฐ์ดํ„ฐ ์ „์†ก

  • ํ•ธ๋“œ์…ฐ์ดํฌ ์ดํ›„ ์›น์†Œ์ผ“์€ ํ”„๋ ˆ์ž„์ด๋ผ๋Š” ๋‹จ์œ„๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ ๋ฐ›์Œ
  • ํ”„๋ ˆ์ž„์€ ๋ฐ์ดํ„ฐ์˜ ์ž‘์€ ๋ฌถ์Œ์œผ๋กœ, ํ…์ŠคํŠธ๋‚˜ ๋ฐ”์ด๋„ˆ๋ฆฌ ๋ฐ์ดํ„ฐ๋กœ ๊ตฌ์„ฑ

์—ฐ๊ฒฐ ์ข…๋ฃŒ

  • ์›น์†Œ์ผ“ ์—ฐ๊ฒฐ์€ ์–‘์ชฝ์—์„œ ์ข…๋ฃŒ ์‹ ํ˜ธ๋ฅผ ๋ณด๋‚ด๋ฉด ์ข…๋ฃŒ๋จ
  • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ธŒ๋ผ์šฐ์ €๋ฅผ ๋‹ซ๊ฑฐ๋‚˜ ๋ช…์‹œ์ ์œผ๋กœ ์—ฐ๊ฒฐ์„ ๋Š์„ ๋•Œ ์—ฐ๊ฒฐ์ด ์ข…๋ฃŒ๋˜๊ณ , ์„œ๋ฒ„์—์„œ๋„ ํŠน์ • ์กฐ๊ฑด์— ๋”ฐ๋ผ ํด๋ผ์ด์–ธํŠธ์™€์˜ ์—ฐ๊ฒฐ์„ ์ข…๋ฃŒํ•  ์ˆ˜ ์žˆ์Œ

์›น์†Œ์ผ“ ๋ฐฉ์‹

๋„คํŠธ์›Œํฌ OSI 7๊ณ„์ธต์—์„œ 7๊ณ„์ธต์—์„œ ์ž‘๋™ํ•˜๋ฉฐ TCP socket์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ž‘๋™

image 1

์›น์†Œ์ผ“์˜ ์žฅ์ 

์‹ค์‹œ๊ฐ„ ์–‘๋ฐฉํ–ฅ ํ†ต์‹  (Full-Duplex)

์—ฐ๊ฒฐ ์œ ์ง€

  • ์ผ๋ฐ˜์ ์ธ HTTP์—์„œ๋Š” ์š”์ฒญ๊ณผ ์‘๋‹ต์ด ๋๋‚˜๋ฉด ์—ฐ๊ฒฐ์ด ๋Š์–ด์ง€์ง€๋งŒ, ์›น์†Œ์ผ“์€ ํ•œ ๋ฒˆ ์—ฐ๊ฒฐ์ด ์„ฑ๋ฆฝ๋˜๋ฉด ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„ ๊ฐ„์˜ ์—ฐ๊ฒฐ์ด ๊ณ„์† ์œ ์ง€๋จ
  • ์˜ค๋ฒ„ํ—ค๋“œ ๊ฐ์†Œ
  • HTTP์˜ ๊ฒฝ์šฐ ๋งค ์š”์ฒญ๋งˆ๋‹ค ํ—ค๋”์™€ ๊ฐ™์€ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•ด์•ผ ํ•˜์ง€๋งŒ, ์›น์†Œ์ผ“์€ ์ฒ˜์Œ ํ•ธ๋“œ์‰์ดํฌ ์ดํ›„์—๋Š” ์ด๋Ÿฌํ•œ ์ถ”๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ด์ง€ ์•Š์Œ

๋‚ฎ์€ ์ง€์—ฐ ์‹œ๊ฐ„ (Low Latency)

  • ์›น์†Œ์ผ“์€ ์—ฐ๊ฒฐ์ด ์—ด๋ฆฐ ํ›„ ๋ฐ์ดํ„ฐ๋ฅผ ๋น ๋ฅด๊ฒŒ ์ „์†กํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ง€์—ฐ ์‹œ๊ฐ„์ด ๋งค์šฐ ์งง์Œ
  • ์›น์†Œ์ผ“์€ ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ง์ ‘ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ, HTTP ๊ธฐ๋ฐ˜์˜ ์š”์ฒญ/์‘๋‹ต ์ฃผ๊ธฐ๋ณด๋‹ค ํ›จ์”ฌ ๋น ๋ฅธ ์‘๋‹ต์„ ์ œ๊ณต

ํšจ์œจ์ ์ธ ๋Œ€์—ญํญ ์‚ฌ์šฉ

  • ์›น์†Œ์ผ“์€ ์ดˆ๊ธฐ ํ•ธ๋“œ์‰์ดํฌ ์ดํ›„์— ํ—ค๋” ํฌ๊ธฐ๊ฐ€ ์ž‘๊ณ  ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋งŒ์„ ์ „์†กํ•˜๋ฏ€๋กœ, ๋Œ€์—ญํญ์„ ํšจ์œจ์ ์œผ๋กœ ์‚ฌ์šฉ
  • ๋ฐ˜๋ณต์ ์ธ HTTP ์š”์ฒญ/์‘๋‹ต์˜ ๊ฒฝ์šฐ ์ƒ๋Œ€์ ์œผ๋กœ ๋งŽ์€ ๋ฐ์ดํ„ฐ๊ฐ€ ์˜ค๊ฐ€๋Š”๋ฐ, ์›น์†Œ์ผ“์€ ์ง€์†์ ์ธ ์—ฐ๊ฒฐ๋กœ ์ธํ•ด ์ด๋Ÿฌํ•œ ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ์ค„์–ด๋“ฆ

์„œ๋ฒ„ ํ‘ธ์‹œ (Server Push)

  • ์„œ๋ฒ„๋Š” ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์š”์ฒญํ•˜์ง€ ์•Š์•„๋„ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•  ์ˆ˜ ์žˆ์Œ
  • ์ด๋ฅผ ํ†ตํ•ด ์‹ค์‹œ๊ฐ„ ์•Œ๋ฆผ, ์ด๋ฒคํŠธ ์—…๋ฐ์ดํŠธ ๋“ฑ ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ ์ฃผ๊ธฐ์ ์œผ๋กœ ์„œ๋ฒ„๋ฅผ ์กฐํšŒํ•  ํ•„์š” ์—†์ด ์„œ๋ฒ„์—์„œ ์ž๋™์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ํ‘ธ์‹œํ•  ์ˆ˜ ์žˆ์Œ

์›น์†Œ์ผ“ ํ†ต์‹ ์˜ ๋‹จ์ 

์ดˆ๊ธฐ ์—ฐ๊ฒฐ ์˜ค๋ฒ„ํ—ค๋“œ

  • ์›น์†Œ์ผ“์€ ์ดˆ๊ธฐ ํ•ธ๋“œ์‰์ดํฌ๊ฐ€ ํ•„์š”ํ•จ
  • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์„œ๋ฒ„์— ์›น์†Œ์ผ“ ์—ฐ๊ฒฐ์„ ์š”์ฒญํ•˜๊ณ , ์„œ๋ฒ„๊ฐ€ ์ด๋ฅผ ์Šน์ธํ•˜๋Š” ๊ณผ์ •์—์„œ HTTP๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ—ค๋” ํฌ๊ธฐ๊ฐ€ ํผ
  • ํ•œ ๋ฒˆ ์—ฐ๊ฒฐ๋œ ํ›„์—๋Š” ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ์ ์ง€๋งŒ, ์ดˆ๊ธฐ ์—ฐ๊ฒฐ ์„ค์ •์— ์‹œ๊ฐ„์ด ๊ฑธ๋ฆด ์ˆ˜ ์žˆ์Œ

์ƒํƒœ ์œ ์ง€ ๋ฌธ์ œ (Stateful)

  • ์›น์†Œ์ผ“ ์—ฐ๊ฒฐ์€ ์ƒํƒœ๊ธฐ๋ฐ˜, HTTP ์—ฐ๊ฒฐ์€ ๋ฌด์ƒํƒœ(Stateless)
  • ์—ฐ๊ฒฐ์ด ๋Š์–ด์ง€๋ฉด ํ•ด๋‹น ์ƒํƒœ๊ฐ€ ๋ชจ๋‘ ์‚ฌ๋ผ์ง€๋ฏ€๋กœ, ์„œ๋ฒ„๋Š” ํด๋ผ์ด์–ธํŠธ์™€์˜ ์—ฐ๊ฒฐ์„ ์œ ์ง€ํ•˜๊ณ  ๊ด€๋ฆฌํ•ด์•ผ ํ•จ
  • ์Šค์ผ€์ผ๋ง์ด ํ•„์š”ํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ๋Š” ์—ฌ๋Ÿฌ ์„œ๋ฒ„๊ฐ€ ์›น์†Œ์ผ“ ์—ฐ๊ฒฐ์„ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•˜๋ฏ€๋กœ, ํด๋ผ์ด์–ธํŠธ ์ƒํƒœ๋ฅผ ๋™๊ธฐํ™”ํ•˜๊ฑฐ๋‚˜ ํด๋Ÿฌ์Šคํ„ฐ ๊ฐ„์— ์—ฐ๊ฒฐ์„ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ์ถ”๊ฐ€์ ์ธ ๋ถ€๋‹ด

๋ธŒ๋ผ์šฐ์ € ๋ฐ ๋„คํŠธ์›Œํฌ ์ œํ•œ

  • ์ผ๋ถ€ ๋„คํŠธ์›Œํฌ ํ™˜๊ฒฝ์—์„œ๋Š” ์›น์†Œ์ผ“ ์—ฐ๊ฒฐ์„ ์ฐจ๋‹จํ•˜๊ฑฐ๋‚˜ ์ œํ•œํ•  ์ˆ˜ ์žˆ์Œ
    • ์˜ˆ๋ฅผ ๋“ค์–ด, ๋ฐฉํ™”๋ฒฝ์ด๋‚˜ ํ”„๋ก์‹œ ์„œ๋ฒ„
  • ๋ธŒ๋ผ์šฐ์ €์—์„œ๋„ ์›น์†Œ์ผ“์„ ์ง€์›ํ•˜์ง€ ์•Š๊ฑฐ๋‚˜, ๋ณด์•ˆ์ƒ์˜ ์ด์œ ๋กœ ์ผ๋ถ€ ์ œํ•œ์„ ๋‘๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Œ

์„œ๋ฒ„ ๋ฆฌ์†Œ์Šค ์†Œ๋ชจ

  • ์›น์†Œ์ผ“ ์—ฐ๊ฒฐ์€ ์„œ๋ฒ„ ๋ฆฌ์†Œ์Šค๋ฅผ ๋งŽ์ด ์†Œ๋ชจ
  • ํด๋ผ์ด์–ธํŠธ์™€ ์—ฐ๊ฒฐ์ด ์ง€์†์ ์œผ๋กœ ์œ ์ง€๋˜๊ธฐ ๋•Œ๋ฌธ์—, ๋งŽ์€ ์ˆ˜์˜ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์—ฐ๊ฒฐ๋  ๊ฒฝ์šฐ ์„œ๋ฒ„๋Š” ์ด๋ฅผ ํšจ์œจ์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์ƒ๋‹นํ•œ ๋ฆฌ์†Œ์Šค๋ฅผ ์†Œ๋น„ํ•  ์ˆ˜ ์žˆ์Œ
  • ๋Œ€๊ทœ๋ชจ์˜ ์›น์†Œ์ผ“ ์„œ๋ฒ„๋ฅผ ์šด์˜ํ•˜๋ ค๋ฉด ์Šค์ผ€์ผ๋ง๊ณผ ๋กœ๋“œ ๋ฐธ๋Ÿฐ์‹ฑ์„ ์ž˜ ๊ณ ๋ คํ•ด์•ผ ํ•จ

๋ณด์•ˆ ๋ฌธ์ œ

  • ๊ธฐ๋ณธ์ ์œผ๋กœ๋Š” ws://(์›น์†Œ์ผ“)์™€ wss://(์›น์†Œ์ผ“ ๋ณด์•ˆ) ํ”„๋กœํ† ์ฝœ์„ ์‚ฌ์šฉํ•˜๋ฉฐ, wss://๋Š” HTTPS์ฒ˜๋Ÿผ SSL/TLS๋กœ ์•”ํ˜ธํ™”๋œ ์—ฐ๊ฒฐ์„ ์‚ฌ์šฉํ•˜์ง€๋งŒ ์—ฌ์ „ํžˆ ์›น์†Œ์ผ“ ํ”„๋กœํ† ์ฝœ์„ ์•…์šฉํ•˜๋ ค๋Š” ๊ณต๊ฒฉ์ด ์žˆ์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด๋ฅผ ๋ฐฉ์–ดํ•˜๊ธฐ ์œ„ํ•œ ์ถ”๊ฐ€์ ์ธ ๋ณด์•ˆ ์กฐ์น˜๊ฐ€ ํ•„์š”

๋ธŒ๋ผ์šฐ์ €์˜ ์ œํ•œ๋œ ์—ฐ๊ฒฐ ์ˆ˜

  • ๋Œ€๋ถ€๋ถ„์˜ ๋ธŒ๋ผ์šฐ์ €๋Š” ๊ฐ ๋„๋ฉ”์ธ์—์„œ ๋™์‹œ์— ์—ด ์ˆ˜ ์žˆ๋Š” ์›น์†Œ์ผ“ ์—ฐ๊ฒฐ ์ˆ˜์— ์ œํ•œ์„ ๋‘๊ณ  ์žˆ์Œ
    • ์˜ˆ๋ฅผ ๋“ค์–ด, ํŠน์ • ๋ธŒ๋ผ์šฐ์ €์—์„œ๋Š” ํ•œ ๋„๋ฉ”์ธ์— ๋Œ€ํ•ด ์ตœ๋Œ€ 6๊ฐœ์˜ ์›น์†Œ์ผ“ ์—ฐ๊ฒฐ๋งŒ์„ ํ—ˆ์šฉ

React์—์„œ ์›น์†Œ์ผ“ ๊ตฌํ˜„

  • ํŠน๋ณ„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ•„์š” ์—†์ด ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ์ œ๊ณตํ•˜๋Š” websocket ์ด์šฉ
import React, { useState, useEffect } from 'react';

const ChatApp = () => {
  const [ws, setWs] = useState<WebSocket | null>(null);
  const [messages, setMessages] = useState<string[]>([]);
  const [userId, setUserId] = useState<string>('');
  const [inputMessage, setInputMessage] = useState<string>('');

  useEffect(() => {
    // WebSocket ์„œ๋ฒ„ ์—ฐ๊ฒฐ
    const socket = new WebSocket('ws://localhost:8080');
    socket.onopen = () => {
      console.log('WebSocket connected');
    };

    // ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๋ฉ”์‹œ์ง€ ์ˆ˜์‹ 
    socket.onmessage = (event) => {
      const data = JSON.parse(event.data);
      if (data.type === 'userId') {
        setUserId(data.userId);  // ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ์‚ฌ์šฉ์ž ID ๋ฐ›๊ธฐ
      } else {
        setMessages((prevMessages) => [...prevMessages, data.message]);
      }
    };

    setWs(socket);

    // ์ปดํฌ๋„ŒํŠธ ์–ธ๋งˆ์šดํŠธ ์‹œ WebSocket ์—ฐ๊ฒฐ ์ข…๋ฃŒ
    return () => {
      socket.close();
    };
  }, []);

  // ๋ฉ”์‹œ์ง€ ๋ณด๋‚ด๊ธฐ
  const sendMessage = () => {
    if (ws && inputMessage) {
      const message = JSON.stringify({
        userId,
        message: inputMessage,
      });
      ws.send(message);
      setInputMessage('');
    }
  };

  return (
    <div>
      <h1>์ฑ„ํŒ…๋ฐฉ</h1>
      <div>
        {messages.map((message, index) => (
          <div key={index}>{message}</div>
        ))}
      </div>
      <input
        type="text"
        value={inputMessage}
        onChange={(e) => setInputMessage(e.target.value)}
        placeholder="๋ฉ”์‹œ์ง€๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”"
      />
      <button onClick={sendMessage}>๋ณด๋‚ด๊ธฐ</button>
    </div>
  );
};

export default ChatApp;

LiBoo

ํŒ€

๊ณตํ†ต

๋ฏผ์ง€

์˜๊ธธ

์ค€์„œ

์ง€์ˆ˜

์ฐฝํ˜„

๋ฐ์ผ๋ฆฌ ์Šคํฌ๋Ÿผ

ํšŒ์˜๋ก

๋ฐœํ‘œ

์ผ๊ธฐ์žฅ

Clone this wiki locally