{"id":521,"date":"2021-12-05T17:14:46","date_gmt":"2021-12-05T08:14:46","guid":{"rendered":"http:\/\/practical.kr\/?p=521"},"modified":"2022-01-28T11:21:08","modified_gmt":"2022-01-28T02:21:08","slug":"webrtc-mqtt-flutter","status":"publish","type":"post","link":"http:\/\/practical.kr\/?p=521","title":{"rendered":"WebRTC, MQTT, Flutter"},"content":{"rendered":"\n<p>WebRTC\ub97c \uc774\uc6a9\ud55c \ud654\uc0c1\/\ub370\uc774\ud130 \ud1b5\uc2e0\uc740 \uae30\ubcf8\uc801\uc73c\ub85c \uc2dc\uadf8\ub110 \uc11c\ubc84\uac00 \ud544\uc694\ud558\ub2e4. \uc77c\ubc18\uc801\uc73c\ub85c Websocket\uc744 \ub9ce\uc774 \uc0ac\uc6a9\ud558\ub294\ub370 \uc11c\ubc84\ub294 \ud074\ub77c\uc774\uc5b8\ud2b8\uc5d0\uc11c \uc804\uc1a1\ub418\ub294 SDP, Candidate\ub97c \ub9b4\ub808\uc774 \ud558\uc5ec \ud074\ub77c\uc774\uc5b8\ud2b8\uac00 \uc5f0\uacb0\ud560 \uc0c1\ub300\ubc29\uc758 IP\uc640 Port \uc815\ubcf4\ub97c \uc8fc\uace0 \ubc1b\uc740 \ub2e4\uc74c \ubc1b\uc740 \uc815\ubcf4\ub97c \uc774\uc6a9\ud558\uc5ec P2p \uc811\uc18d\uc744 \uc2dc\ub3c4\ud55c\ub2e4.<\/p>\n\n\n\n<p class=\"has-large-font-size\">MQTT<\/p>\n\n\n\n<p>MQTT\ub294 \ubc1c\ud589\/\uad6c\ub3c5 \uae30\ubc18\uc73c\ub85c \uc77c\ub300\uc77c, \uc77c\ub300\ub2e4 \ub370\uc774\ud130 \ud1b5\uc2e0\uc5d0 \uc801\ud569\ud558\uace0 \uad6c\ub3c5 \ucc44\ub110\uc744 \ud2b8\ub9ac\uad6c\uc870\ub85c \uad6c\uc131 \ud560 \uc218 \uc788\uae30 \ub54c\ubb38\uc5d0 Websocket\uc5d0\uc11c \ucc44\ud305\ubc29-\uc11c\ube0c \ucc44\ud305\ubc29\uc744 \uad6c\ud604\ud558\ub294 \uae30\ub2a5\uc744 \uc544\uc8fc \uac04\ub2e8\ud558\uac8c \uad6c\ud604 \ud560 \uc218 \uc788\ub2e4. <\/p>\n\n\n\n<p class=\"has-large-font-size\">\uc544\uc774\ub514\uc5b4 &#8211; Mosquitto<\/p>\n\n\n\n<p> WebRTC \ud654\uc0c1\ud1b5\uc2e0\uc571\uc744 \ub9cc\ub4e4\uba70 \ucc98\uc74c\ubd80\ud130 \uc774 \uc0dd\uac01\uc744 \ud588\ub2e4. WebSocket\uc73c\ub85c \ucc44\ud305\ubc29\uc744 \ub9cc\ub4e4\uc9c0  \uc54a\uace0 MQTT\ub97c \uc774\uc6a9\ud558\uba74 \uc548\ub420\uae4c? Mosquitto \uc11c\ubc84\ub77c\uba74 \ubcf4\uc548\uc131 \ubb38\uc81c\ub3c4 \uc27d\uac8c \ud574\uacb0 \ud560 \uc218 \uc788\uace0 \uc131\ub2a5\ub3c4 \uc6b0\uc218\ud55c \uc2dc\uadf8\ub110 \uc11c\ubc84\ub85c \ud65c\uc6a9\ud560 \uc218 \uc788\uc9c0 \uc54a\uc744\uae4c? \uadf8\ub798\uc11c \ud55c\ubc88 \ud574\ubd24\ub2e4.<\/p>\n\n\n\n<p class=\"has-large-font-size\">Sample Code &#8211; Flutter<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/practical.kr\/wp-content\/uploads\/2021\/12\/1638688086230-1.jpg\" alt=\"\uc774 \uc774\ubbf8\uc9c0\ub294 \ub300\uccb4 \uc18d\uc131\uc774 \ube44\uc5b4\uc788\uc2b5\ub2c8\ub2e4. \uadf8 \ud30c\uc77c \uc774\ub984\uc740 1638688086230-1.jpg\uc785\ub2c8\ub2e4\" width=\"602\" height=\"451\"\/><\/figure><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>\uc544\ub798 \ub9c1\ud06c\uc758 \uc18c\uc2a4 \ucf54\ub4dc\ub294 \ud604\uc7ac \ub9cc\ub4e4\uace0 \uc788\ub294 CCTV\uad00\ub828\uc571\uc5d0\uc11c \uae30\ubcf8\uc801\uc778 \uae30\ub2a5\ub9cc \ucd94\ucd9c\ud574\uc11c Sample Project\ub97c \ub9cc\ub4e4\uc5c8\ub2e4. Flutter\ub85c \ub9cc\ub4e4\uc5b4\uc9c4 \uc624\ud508\uc18c\uc2a4\uc774\uba70  \uc624\ud508\ub41c Mosquitto \uc11c\ubc84\uc5d0 \uc811\uc18d\ud558\uc5ec \ub3d9\uc77c\ud55c \ud1a0\ud53d\uc744 \ubc1c\ud589\/\uad6c\ub3c5\ud558\uc5ec \uc2dc\uadf8\ub110\uc744 \uc8fc\uace0 \ubc1b\uc740\ud6c4 P2p\ub97c \uc5f0\uacb0\ud558\uc5ec \ud654\uc0c1\ud1b5\uc2e0\uc744 \uc2e4\ud589\ud55c\ub2e4. <\/p>\n\n\n\n<p><strong>\uacb0\ub860\uc801\uc73c\ub85c \uc774 \ud504\ub85c\uc81d\ud2b8\uc5d0\uc11c WebRTC \ud1b5\uc2e0\uc744 \ud558\uae30 \uc704\ud55c \uc2dc\uadf8\ub110 \uc11c\ubc84\ub294 \ub9cc\ub4e4\uc9c0\uc54a\uc558\ub2e4.<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\uc18c\uc2a4\ub2e4\uc6b4\ub85c\ub4dc \ub9c1\ud06c\n\n<a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/bipark\/webrtc_mqtt_flutter_phone\" target=\"_blank\">https:\/\/github.com\/bipark\/webrtc_mqtt_flutter_phone<\/a><\/code><\/pre>\n\n\n\n<p>P2p\uc5f0\uacb0\uc744 \uc704\ud574 Google Stun \uc11c\ubc84\ub97c \uc0ac\uc6a9\ud558\uba70 3G, LTE\uc5d0\uc11c \uc5f0\uacb0\uc774 \ub418\uc9c0 \uc54a\uc744\uc218\ub3c4 \uc788\ub2e4. Stun \uc11c\ubc84\ub97c \ud1b5\ud55c P2p \uc5f0\uacb0\uc774 \ubd88\uac00\ub2a5\ud55c \uacbd\uc6b0\ub294 Turn \uc11c\ubc84\ub97c \uac1c\ubcc4\uc801\uc73c\ub85c \uc124\uce58\ud558\uace0 \uc6b4\uc601\ud574\uc57c \ud558\ub294\ub370 \uc624\ud508\uc18c\uc2a4\uc778 Coturn\uc744 \ud65c\uc6a9\ud558\uc5ec \uc6b4\uc6a9\uc774 \uac00\ub2a5\ud558\ub2e4.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class MQTTManager {\n  MqttServerClient? _client;\n\n  MQTTManager(String clientId) {\n    _client = MqttServerClient(\"test.mosquitto.org\", clientId);\n    _client!.autoReconnect = true;\n    _client!.logging(on: false);\n    _client!.keepAlivePeriod = 20;\n  }\n\n  Future&amp;lt;void&amp;gt; connect(String topic) async {\n    try {\n      await _client!.connect();\n    } on Exception catch (e) {\n      print('EXAMPLE::client exception - $e');\n    }\n    _client!.subscribe(topic, MqttQos.atMostOnce);\n  }\n\n  void publishMessage(String topic ,String message) {\n    try {\n      final builder1 = MqttClientPayloadBuilder();\n      builder1.addString(message);\n      _client!.publishMessage(topic, MqttQos.atLeastOnce, builder1.payload!);\n    } on Exception catch (e) {\n      print('EXAMPLE::client exception - $e');\n    }\n  }\n\n  void subscribeTopic(String topic) {\n    _client!.subscribe(topic, MqttQos.atMostOnce);\n  }\n\n  void unSubscribeTopic(String topic) {\n    _client!.unsubscribe(topic);\n  }\n\n  void disconnect() {\n    _client!.disconnect();\n  }\n\n  get client =&amp;gt; _client;\n}<\/pre>\n\n\n\n<p>WebRTC\uc640 \uad00\ub828\ud55c \ucf54\ub4dc\ub294 \uc2dc\uadf8\ub110 \uae30\ub2a5\uc5d0 \ub530\ub978 \ub9ce\uc740 \ucf54\ub4dc\ub4e4\uc774 \uc694\uad6c\ub418\uc9c0\ub9cc \uc148\ud50c\uc5d0\uc11c\ub294 \uac00\uc7a5 \uae30\ubcf8\uc801\uc778 \ud1b5\uc2e0 \uae30\ub2a5\ub9cc\uc744 \uad6c\ud604 \ud588\ub2e4. <\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">  _mqtt = MQTTManager(_clientId);\n  await _mqtt!.connect(_topic);\n  \n  ...\n  var desc = await _localPc!.createOffer(offerSdpConstraints);\n  await _localPc!.setLocalDescription(desc);\n  _sendData(\"offer\", desc.sdp);\n  \n  ...\n  void _sendData(event, data) {\n    var request = Map();\n    request[\"command\"] = \"signal\";\n    request[\"clientid\"] = _clientId;\n    request[\"type\"] = event;\n    request[\"data\"] = data;\n    _mqtt!.publishMessage(_topic, jsonEncode(request).toString());\n  }\n<\/pre>\n\n\n\n<p>\ubc15\ubcd1\uc77c, 2021.12.5, rtlink.park@gmail.com<\/p>\n","protected":false},"excerpt":{"rendered":"<p>WebRTC\ub97c \uc774\uc6a9\ud55c \ud654\uc0c1\/\ub370\uc774\ud130 \ud1b5\uc2e0\uc740 \uae30\ubcf8\uc801\uc73c\ub85c \uc2dc\uadf8\ub110 \uc11c\ubc84\uac00 \ud544\uc694\ud558\ub2e4. \uc77c\ubc18\uc801\uc73c\ub85c Websocket\uc744 \ub9ce\uc774 \uc0ac\uc6a9\ud558\ub294\ub370 \uc11c\ubc84\ub294 \ud074\ub77c\uc774\uc5b8\ud2b8\uc5d0\uc11c \uc804\uc1a1\ub418\ub294 SDP, Candidate\ub97c \ub9b4\ub808\uc774 \ud558\uc5ec \ud074\ub77c\uc774\uc5b8\ud2b8\uac00 \uc5f0\uacb0\ud560 \uc0c1\ub300\ubc29\uc758 IP\uc640 Port \uc815\ubcf4\ub97c \uc8fc\uace0 \ubc1b\uc740 \ub2e4\uc74c \ubc1b\uc740 \uc815\ubcf4\ub97c \uc774\uc6a9\ud558\uc5ec P2p \uc811\uc18d\uc744 \uc2dc\ub3c4\ud55c\ub2e4. MQTT MQTT\ub294 \ubc1c\ud589\/\uad6c\ub3c5 \uae30\ubc18\uc73c\ub85c \uc77c\ub300\uc77c, \uc77c\ub300\ub2e4 \ub370\uc774\ud130 \ud1b5\uc2e0\uc5d0 \uc801\ud569\ud558\uace0 \uad6c\ub3c5 \ucc44\ub110\uc744 \ud2b8\ub9ac\uad6c\uc870\ub85c \uad6c\uc131 \ud560 \uc218 \uc788\uae30 \ub54c\ubb38\uc5d0 Websocket\uc5d0\uc11c \ucc44\ud305\ubc29-\uc11c\ube0c \ucc44\ud305\ubc29\uc744 \uad6c\ud604\ud558\ub294<\/p>\n<div class=\"more-link\">\n\t\t\t\t <a href=\"http:\/\/practical.kr\/?p=521\" class=\"link-btn theme-btn\"><span>Read More <\/span> <i class=\"fa fa-caret-right\"><\/i><\/a>\n\t\t\t<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[12,34,19,44],"tags":[42,45,43],"class_list":["post-521","post","type-post","status-publish","format-standard","hentry","category-flutter","category-mqtt","category-opensource","category-webrtc","tag-mqtt","tag-opensource","tag-webrtc"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"http:\/\/practical.kr\/index.php?rest_route=\/wp\/v2\/posts\/521","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/practical.kr\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/practical.kr\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/practical.kr\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/practical.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=521"}],"version-history":[{"count":13,"href":"http:\/\/practical.kr\/index.php?rest_route=\/wp\/v2\/posts\/521\/revisions"}],"predecessor-version":[{"id":537,"href":"http:\/\/practical.kr\/index.php?rest_route=\/wp\/v2\/posts\/521\/revisions\/537"}],"wp:attachment":[{"href":"http:\/\/practical.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=521"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/practical.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=521"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/practical.kr\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=521"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}