Flutter - WebScoket

2023. 11. 7. 14:12·Flutter
728x90
반응형

1. 패키지 추가

웹소켓 관련 패키지를 사용하기 위해 pubspec.yaml의 dependencies 항목을 다음과 같이 수정한다.

dependencies:
  flutter:
    sdk: flutter

  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^0.1.2
  web_socket_channel: ^1.0.13

 

2. 라이브러리 import

웹소켓 관련 패키지를 사용하기 위해 다음과 같이 라이브러리들을 import 한다.

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

 

3. 웹소켓서버 연결 및 채널 생성

웹소켓서버와 연결을 맺고 그에 대한 응답으로 채널을 획득하는 방법은 다음과 같다.

  // 웹소켓 채널을 생성
  final WebSocketChannel channel =
      // 웹 서버에 접속 시도
      IOWebSocketChannel.connect('ws://echo.websocket.org');

 

4. 웹소켓서버로 메시지 전송

웹소켓서버로 메시지를 전송하기 위해서는 생성한 채널을 이용해서 sink.add 함수를 이용한다.

channel.sink.add(_controller.text);

 

5. 웹소켓서버로부터 메시지 수신 처리

// Stream을 처리하기 위한 StreamBuilder 추가
            StreamBuilder(
              // 채널의 스트림을 stream 항목에 설정. widget을 통해 MyHomePage의 필드에 접근 가능
              stream: widget.channel.stream,
              // 채널 stream에 변화가 발생하면 빌더 호출
              builder: (context, snapshot) {
                return Padding(
                  padding: const EdgeInsets.symmetric(vertical: 24.0),
                  // 수신 데이터가 존재할 경우 해당 데이터를 텍스트로 출력
                  child: Text(snapshot.hasData ? '${snapshot.data}' : ''),
                );
              },
            )

웹서버로부터 수신된 응답메시지는 channel.stream으로 전달되고 stream을 통해 접근이 가능하다. stream을 처리하기 위해선 StreamBuilder 클래스를 이용한다. StreamBuilder에 stream 항목에 channel.stream을 설정하면 서버로부터 데이터가 수신될 때마다 builder가 호출된다.

 

6. 연결 종료

웹소켓서버와의 연결을 종료하기 위해서는 채널을 이용해서 sink.close 함수를 이용한다.

channel.sink.close();

 

전체 소스코드는 다음과 같다.

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final title = 'WebSocket Demo';

    return MaterialApp(
      title: title,
      home: MyHomePage(title: title),
    );
  }
}

class MyHomePage extends StatefulWidget {
  final String title;

  // 웹소켓 채널을 생성
  final WebSocketChannel channel =
      // 웹 서버에 접속 시도
      IOWebSocketChannel.connect('ws://echo.websocket.org');

  MyHomePage({Key key, @required this.title}) : super(key: key);

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  // 상태 변화가 일어나는 필드
  TextEditingController _controller = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      // 앱바에 타이틀 텍스트 설정. widget을 통해 MyHomePage의 필드에 접근 가능
      appBar: AppBar(title: Text(widget.title)),
      body: Padding(
        padding: const EdgeInsets.all(20.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Form(
              child: TextFormField(
                // 컨트롤러 항목에 _controller 설정
                controller: _controller,
                decoration: InputDecoration(labelText: 'Send a message'),
              ),
            ),
            // Stream을 처리하기 위한 StreamBuilder 추가
            StreamBuilder(
              // 채널의 스트림을 stream 항목에 설정. widget을 통해 MyHomePage의 필드에 접근 가능
              stream: widget.channel.stream,
              // 채널 stream에 변화가 발생하면 빌더 호출
              builder: (context, snapshot) {
                return Padding(
                  padding: const EdgeInsets.symmetric(vertical: 24.0),
                  // 수신 데이터가 존재할 경우 해당 데이터를 텍스트로 출력
                  child: Text(snapshot.hasData ? '${snapshot.data}' : ''),
                );
              },
            )
          ],
        ),
      ),
      // 플로팅 버튼이 눌리면 _sendMessage 함수 호출
      floatingActionButton: FloatingActionButton(
          onPressed: _sendMessage,
          tooltip: 'Send message',
          child: Icon(Icons.send)),
    );
  }

  // 플로팅 버튼이 눌리면 호출
  void _sendMessage() {
    // TextFormField에 입력된 텍스트가 존재하면
    if (_controller.text.isNotEmpty) {
      // 해당 텍스트를 서버로 전송. widget을 통해 MyHomePage의 필드에 접근 가능
      widget.channel.sink.add(_controller.text);
    }
  }

  // 상태 클래스가 종료될 때 호출
  @override
  void dispose() {
    // 채널을 닫음
    widget.channel.sink.close();
    super.dispose();
  }
}

 

소스코드를 살펴보면,

서버로부터 응답 메시지가 수신될 때마다 페이지를 다시 구성해야 하므로 StatefulWidget와 State를 상속하는 클래스를 통해 앱을 구성해야 한다. MyHomePage 클래스에서 웹소켓 서버와 연결을 맺고 채널을 필드에 저장한다.

서버로 데이터를 전송하기 위해서 Form 위젯에 TextFormField를 등록하였고 이 폼필드에 TextEditingController를 등록하여 플로팅버튼이 눌릴 때마다 폼필드의 입력된 텍스트를 웹소켓 서버로 전송한다. 또한 StreamBuilder 클래스를 통해서 서버로부터 데이터가 수신될 때마다 화면에 새로운 텍스트를 출력한다.

웹소켓통신 방식은 Http 통신과 달리 연결지향적이므로 페이지가 종료될 때 채널을 종료해야 한다. 이를 위해 dispose 메소드를 재정의한다.

728x90
반응형
LIST

'Flutter' 카테고리의 다른 글

Flutter - 화페 & 숫자  (1) 2023.11.08
Flutter - 날짜 & 시간  (1) 2023.11.08
Flutter - JWT  (2) 2023.11.07
Flutter - 동시성 , 병렬성 , 콜백함수  (1) 2023.11.07
Flutter - Generators (제너레이터)  (0) 2023.11.07
'Flutter' 카테고리의 다른 글
  • Flutter - 화페 & 숫자
  • Flutter - 날짜 & 시간
  • Flutter - JWT
  • Flutter - 동시성 , 병렬성 , 콜백함수
Mr. Joo
Mr. Joo
  • Mr. Joo
    삽질의 시작
    Mr. Joo
  • 전체
    오늘
    어제
    • 분류 전체보기 (214) N
      • Flutter (70)
      • Android (9)
      • Swift (4)
      • React (11)
      • 인공지능 (4)
      • CS (10)
      • 개발 뉴스 (103) N
      • IT 기기 (1)
      • 알면 유용한 정보 (2)
  • 인기 글

  • 태그

    앱개발
    기술 뉴스
    Dart 기초
    오늘의 기술 뉴스
    개발
    개발 뉴스
    오늘의 이슈
    앱
    기술
    react
    뉴스 모음
    앱 개발
    이슈
    개발 이슈
    Flutter
    오늘의 개발 뉴스
    플러터
    오늘의 뉴스
    뉴스
    DART
  • 최근 댓글

  • 최근 글

  • 250x250
    반응형
  • hELLO· Designed By정상우.v4.10.3
Mr. Joo
Flutter - WebScoket
상단으로

티스토리툴바