개발노트

76. [Flutter] 웹소켓 통신하기 (웹소켓과 http와의 차이) 본문

앱 개발/Flutter

76. [Flutter] 웹소켓 통신하기 (웹소켓과 http와의 차이)

mroh1226 2024. 8. 6. 00:49
반응형

WebSocket (TCP/IP)

WebSocket은 실시간 양방향 통신을 가능하게 하는 기술로, 지속적인 연결을 유지하며 언제든지 클라이언트와 서버가 서로 통신

주요 특징:

  • 양방향 통신: 클라이언트와 서버가 서로 데이터를 주고받음(ex 전화통화)
  • 지속적인 연결: 연결이 수립된 후에는 클라이언트와 서버가 지속적으로 연결을 유지
  • 실시간 통신: 실시간 데이터 전송이 가능, 지연 없이 즉시 통신
  • Open - Close 개념: 연결이 시작될 때 HttpRequest를 WebSocket으로 Upgrade 요청을 한뒤, 101 Response를 받아 오픈(Open)하며, 통신이 끝날 때 클로즈(Close) 함
    * HTTP 상태 코드 101은 "Switching Protocols"를 의미(HTTP에서 WebSocket으로 변경한다는 것을 나타냄)
  • 메모리 및 리소스 사용: 많은 클라이언트와의 연결할 경우, 그 만큼의 메모리와 리소스가 필요(ex 단톡방)

사용 사례:

  • 채팅 애플리케이션
  • 온라인 게임 서버

HTTP

HTTP는 단방향 통신 프로토콜로, 클라이언트가 요청(Request)을 보내면 서버가 응답(Response)을 반환 후, 연결이 종료

주요 특징:

  • 단방향 통신: 클라이언트가 요청을 보내야 서버가 응답할 수 있음
  • 연결의 지속성 없음: 요청과 응답이 완료되면 연결 종료
  • Request - Response 개념: 클라이언트가 요청을 보내고, 서버가 응답을 반환
  • 비연결형 통신: 각 요청과 응답은 독립적이며, 지속적인 연결 유지불가

사용 사례:

  • RESTful API
  • 파일 다운로드

비교표

  WebSocket HTTP  
통신 방식 양방향 실시간 단방향  
연결 유형 지속적인 연결 비연결형  
주요 개념 Open - Close Request - Response  
실시간 통신 가능 불가능  
리소스 사용 메모리 및 리소스 중요 상대적으로 적음  
사용 사례 채팅, 실시간 알림 웹 페이지, RESTful API  

 


준비물.

아래에서 web_socket_channel 을 설치해줌

- 사용 라이브러리: https://pub.dev/packages/web_socket_channel/install

 

web_socket_channel install | Dart package

StreamChannel wrappers for WebSockets. Provides a cross-platform WebSocketChannel API, a cross-platform implementation of that API that communicates over an underlying StreamChannel.

pub.dev

 

- Flutter WebSocket  관련 공식문서: https://docs.flutter.dev/cookbook/networking/web-sockets

 

Communicate with WebSockets

How to connect to a web socket.

docs.flutter.dev

 

현재 만들어진 웹소켓 서버가 없기 때문에 공식 사이트에서 제공되는 웹소켓 서버를 이용함

- 테스트 가능한 WebSocket 서버 링크: https://echo.websocket.org/.ws

 

websocket

Pause Messaging Resume Messaging Connect to Server Disconnect from Server Cancel Connection Attempt Send Message

echo.websocket.org


1. 변수에 WebSocket 서버 Connection 정보를 담음

final channel = WebSocketChannel.connect(
  //wss: ws에서 TLS/SSL을 사용한 암호화된 통신
  //wss: WebSocket Secure
  Uri.parse('wss://echo.websocket.events'),
);

 

2. StreamBuilder로 실시간으로 웹소켓 서버를 Listen함

StreamBuilder(
  stream: channel.stream,
  builder: (context, snapshot) {
    return Text(snapshot.hasData ? '${snapshot.data}' : '');
  },
)

 

3. 웹소켓 서버에 Data 보내기

channel.sink.add('Hello!');

 

4. 웹소켓 서버와 통신 닫기(Close)

channel.sink.close();

간단 예제(Http Request Upgrade 없이 웹소켓에 바로 통신)

import 'package:flutter/material.dart';
import 'package:web_socket_channel/io.dart';
import 'package:web_socket_channel/web_socket_channel.dart';

void main() {
  runApp(const MainApp());
}

class MainApp extends StatefulWidget {
  const MainApp({super.key});
  @override
  State<MainApp> createState() => _MainAppState();
}

class _MainAppState extends State<MainApp> {
  late final TextEditingController _textEditingController;
  // WebSocket 웹소켓 채널을 선언
  late final WebSocketChannel channel; 
  
  @override
  void initState() {
    // 텍스트 입력 컨트롤러를 초기화
    _textEditingController = TextEditingController(); 
    //WebSocket 웹소켓 서버 연결
    channel = IOWebSocketChannel.connect(
      Uri.parse('wss://echo.websocket.events')); 
    super.initState();
  }

  @override
  void dispose() {
    // 텍스트 입력 컨트롤러 해제
    _textEditingController.dispose(); 
    // WebSocket 채널 통신 닫기
    channel.sink.close(); 
    super.dispose();
  }

  void _onPressed(){
  // WebSocket 채널을 통해 메시지를 보내기
    channel.sink.add(_textEditingController.text); 
    // 텍스트 필드를 초기화
    _textEditingController.text = ''; 
  }

  @override
  Widget build(BuildContext context) {
    return  MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text("웹소켓 서버 송신 테스트"),),
        body: Center(
          child: SizedBox(
            height: 500,
            child: Column(
              children: [
                TextField(controller: _textEditingController,),
                // StreamBuilder로 WebSocket 스트림을 감시
                StreamBuilder(stream: channel.stream, builder: (context, snapshot) { 
                //수신할 데이터가 있으면 표시하고, 없으면 빈 문자열을 표시
                  return Text(snapshot.hasData ? '${snapshot.data}': '', 
                  style: const TextStyle(fontSize: 20),);
                },),
                // 버튼 클릭 시 _onPressed를 호출하여 웹소켓에 Text 송신
                TextButton(onPressed: _onPressed, child: const Text("Send")) 
              ],
            ),
          ),
        ),
      ),
    );
  }
}

웹소켓

반응형
Comments