일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- Row
- Flutter Example
- ListView.builder
- flutter
- Networking
- navigator
- Scaffold
- sqlite
- Row Widget
- Column Widget
- Cached Image
- listview
- node.js
- InkWell
- Load Image
- WillPopScope
- Flutter 예제
- Flutter 강좌
- Image.network
- Flutter Tutorial
- MainAxisAlignment
- FutureBuilder
- AppBar
- 반석천
- ListTile
- Snackbar
- CrossAxisAlignment
- Hello World
- HTTP
- Flutter 앱 배포
- Today
- Total
꿈꾸는 시스템 디자이너
Flutter 강좌 - [Networking] 웹소켓(WebScoket) 사용법 | StreamBuilder 본문
Flutter 강좌 - [Networking] 웹소켓(WebScoket) 사용법 | StreamBuilder
독행소년 2019. 7. 10. 00:29Flutter 강좌 목록 : https://here4you.tistory.com/120
지난 강좌에서는 Http 프로토콜을 이용해서 온라인상의 데이터를 수신하고 처리하는 방법에 대해서 알아봤다. 이번 강좌에서는 웹소켓(WebSocket)의 사용법에 대해서 알아본다.
우선 Http와 웹소켓의 차이에 대해서 생각해 보자.
서버와 통신을 하는 앱을 개발하고자 할 때 사용할 수 있는 통신 방식은 Http 통신 혹은 소켓 통신이다. 거의 대부분의 경우 이 두 종류 중 하나를 이용하거나 필요에 따라 두 종류를 동시에 사용하기도 한다.
Http 통신 방식은 연결 지향성이 없는 통신 방식이다. 클라이언트는 서버로 요청 메시지를 전달하고, 서버로부터 해당 응답 메시지를 수신하면 서버-클라이언트간 통신은 종료된다. 통신 관련 제어 포인트가 적기 때문에 개발이 쉽다. 단점은 모든 Http 통신은 클라이언에서 시작하고 클라이언트로부터 응답을 수신하는 동기식 방식만 가능하다. 다시 말해 서버가 필요에 의해 클라이언트에게 요청 메시지를 전송할 수 없다.
소켓 통신 방식은 연결 지향성 통신 방식이다. 서버-클라이언트간 연결이 맺어지면 어느 누구든 상대방에게 메시지를 전송할 수 있다. 단점은 Http 통신 방식이 비해 상대적으로 제어 포인트가 많기 때문에 개발이 어렵다는 점이다.
통신 대상의 차이점에 대해서도 생각해 보자
Http 통신은 웹서버와 통신을 하고, 소켓 통신은 소켓 서버와 통신을 한다. 만약 Http 통신과 소켓 통신을 동시에 이용하는 앱을 개발하고자 한다면 웹서버와 소켓서버를 모두 개발해야하는 부담이 발생한다. 두 서버간의 협업도 큰 골치거리가 된다.
하지만 웹소켓 기술의 출현으로 이제는 웹서버에서도 소켓통신이 가능해졌다. 이번 강좌에서는 이 웹소켓의 사용법에 대해서 알아본다.
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 메소드를 재정의한다.
또한 StatefulWidget 위젯으로 앱을 구성할 때 State 클래스내에서 widget을 이용하면 StatefulWidget을 참조할 수 있다. 상기 코드의 line 42, 58, 84, 92가 그에 해당한다.
앱의 실행화면은 다음과 같다.
본 강좌는 Flutter 공식 사이트의 문서를 참고하여 작성되었습니다.
https://flutter.dev/docs/cookbook/networking/web-sockets
Flutter Code Examples 강좌를 추천합니다.
- 제 블로그에서 Flutter Code Examples 프로젝트를 시작합니다.
- Flutter의 다양한 예제를 소스코드와 실행화면으로 제공합니다.
- 또한 모든 예제는 Flutter Code Examples 앱을 통해 테스트 가능합니다.
Flutter Code Examples 강좌로 메뉴로 이동
'Development > Flutter' 카테고리의 다른 글
Flutter 강좌 - 채팅앱 UI 만들기 | Building Beautiful UIs with Flutter (2) | 2019.07.11 |
---|---|
Flutter 강좌 - [Persistence] Shared Preferences 사용법 (1) | 2019.07.10 |
Flutter 강좌 - [Networking] 백그라운드에서 JSON 데이터 파싱하는 방법 | 정크(Jank) 방지법 (1) | 2019.07.09 |
Flutter 강좌 - [Networking] 인터넷에서 데이터 가져오는 방법 (6) | 2019.07.08 |
Flutter 강좌 - [List] 아이템의 수가 아주 많을 경우의 리스트뷰 사용법 (0) | 2019.07.05 |