{"id":13327,"date":"2023-01-02T11:22:06","date_gmt":"2023-01-02T02:22:06","guid":{"rendered":"http:\/\/www.gisdeveloper.co.kr\/?p=13327"},"modified":"2023-01-02T11:32:04","modified_gmt":"2023-01-02T02:32:04","slug":"webrtc-%ec%bd%94%eb%93%9c-%ec%a0%95%eb%a6%ac","status":"publish","type":"post","link":"http:\/\/www.gisdeveloper.co.kr\/?p=13327","title":{"rendered":"WebRTC \ucf54\ub4dc \uc815\ub9ac"},"content":{"rendered":"<p>WebRTC\ub294 P2P\uc774\uba70 \uc6f9\uc5d0\uc11c 1:1\ub85c \uc5f0\uacb0\ud558\uc5ec \uc11c\ub85c \ub370\uc774\ud130\ub97c \uc2e4\uc2dc\uac04\uc73c\ub85c \uc8fc\uace0 \ubc1b\ub294 \uc6f9 \ud45c\uc900\uae30\uc220\uc785\ub2c8\ub2e4. \ucd94\ud6c4 \uc801\uc6a9\uc744 \uc704\ud574 \uad00\ub828 \ucf54\ub4dc\ub97c \uc815\ub9ac\ud569\ub2c8\ub2e4.<\/p>\n<p>\uba3c\uc800 \uac1c\ub150\ub3c4\ub294 \ub2e4\uc74c\uacfc \uac19\uc2b5\ub2c8\ub2e4. (\uc544\ub798 \uadf8\ub9bc\uc740 WebRTC\uc5d0 \ub300\ud55c \uc774\ud574\ub97c \ub3d5\uae30 \uc704\ud574 \uc81c\uac00 \uc791\uc131\ud55c \uac83\uc73c\ub85c \uc798\ubabb \ud45c\uae30\ub41c \ubd80\ubd84\uc774 \uc788\uc744 \uc218 \uc788\uc2b5\ub2c8\ub2e4.)<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.gisdeveloper.co.kr\/wp-content\/uploads\/2023\/01\/webrtc.jpg\" alt=\"\" width=\"1621\" height=\"822\" class=\"alignnone size-full wp-image-13328\" \/><\/p>\n<p>\uc77c\ub2e8 \ucb49 \ub9d0\ub85c \uc124\uba85\ud558\uba74.. \uba3c\uc800 \ub370\uc774\ud130\ub97c \uc8fc\uace0 \ubc1b\uc744 \ucc44\ub110\uc744 \uc0dd\uc131\ud558\uace0 \ucc44\ub110\uc744 \uc0dd\uc131\ud55c Peer\uac00 \uc81c\uc548(Offer) \uac1d\uccb4\ub97c \ub9cc\ub4e4\uc5b4 \ub2e4\ub978 Peer\uc5d0\uac8c \uc804\ub2ec\ud569\ub2c8\ub2e4. \uadf8\ub7fc \ud53c\uc5b4\ub294 \uc81c\uc548\uacfc \ud568\uaed8 \ubc1b\uc740 \ucc44\ub110\uc744 \ud655\uc778\ud558\uace0 \uc751\ub2f5(Answer) \uac1d\uccb4\ub97c \uc0dd\uc131\ud574 \uc804\ub2ec\ud569\ub2c8\ub2e4. \uadf8\ub7ec\uba74 \uc774 \ub450 Peer\ub4e4\uc740 icecandidate\ub77c\ub294 \uc774\ubca4\ud2b8\uac00 \ubc1c\uc0dd\ud558\uac8c\ub418\uace0 Candidate \uac1d\uccb4\ub97c \uc11c\ub85c \uc8fc\uace0 \ubc1b\uc544 \uc124\uc815\ud568\uc73c\ub85c\uc368 \ub450 Peer \uac04\uc758 \uc5f0\uacb0\uc774 \uc774\ub8e8\uc5b4 \uc9d1\ub2c8\ub2e4. \uc774\ub807\uac8c \uc5f0\uacb0\uc774 \uc774\ub8e8\uc5b4\uc9c0\uba74 \uc55e\uc11c \uc5b8\uae09\ud55c \ucc44\ub110\uc744 \ud1b5\ud574 \uba54\uc138\uc9c0\ub97c \uc2e4\uc2dc\uac04\uc73c\ub85c \uc8fc\uace0 \ubc1b\uc744 \uc218 \uc788\uc2b5\ub2c8\ub2e4. \uc704\uc758 \uadf8\ub9bc\uc744 \ubcf4\uba74 Peer\uac04\uc758 \uc5f0\uacb0\uc744 \uc704\ud574 Offer, Answer, Candidate \uc815\ubcf4\ub97c \uad50\ud658\ud558\uae30 \uc704\ud574 \ubcc4\ub3c4\uc758 \uc11c\ubc84\uac00 \ud544\uc694\ud55c \uac83\uc744 \ubcfc \uc218 \uc788\uc2b5\ub2c8\ub2e4. \ud558\uc9c0\ub9cc WebRTC\uc758 \ud575\uc2ec\uc740 \uc11c\ubc84\uc5c6\uc774 Peer \uac04\uc758 \ub370\uc774\ud130 \uc804\uc1a1\uc774\ubbc0\ub85c \uc77c\ub2e8 \uc5f0\uacb0\uc774 \ub418\uba74 \ub354 \uc774\uc0c1 \uc11c\ubc84\ub294 \ud544\uc694\uce58 \uc54a\uc2b5\ub2c8\ub2e4.<\/p>\n<p>\uc6f9 \ud45c\uc900 \uae30\uc220\uc774 \uc9c0\ud5a5\ud558\ub294 \ub9e4\uc6b0 \uc2ec\ud50c\ud55c API \uad6c\uc870\uc5d0 \ub9de\uac8c \ucf54\ub4dc\uac00 \ub2e8\uc21c\ud55c\ub370\uc694. \uc11c\ubc84, \ud074\ub77c\uc774\uc5b8\ud2b8 \ucf54\ub4dc\uac00 \ub9e4\uc6b0 \uc9e7\uc73c\ubbc0\ub85c \uc804\uccb4 \ucf54\ub4dc\ub97c \ub0a8\uae41\ub2c8\ub2e4. \uba3c\uc800 \ud074\ub77c\uc774\uc5b8\ud2b8\uc5d0 \ub300\ud55c \ucf54\ub4dc\ub294 \ub2e4\uc74c\uacfc \uac19\uc2b5\ub2c8\ub2e4.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\">\r\nconst socket = io();\r\nconst roomName = \"room1\";\r\n\r\nlet peerConnection;\r\nlet dataChannel;\r\n\r\ndocument.querySelector(\"form\").addEventListener(\"submit\", (event) => {\r\n    event.preventDefault();\r\n\r\n    if(dataChannel) {\r\n        const value = document.querySelector(\"form input\").value\r\n        dataChannel.send(value);\r\n    }\r\n});\r\n\r\nfunction onReady() {\r\n    peerConnection = new RTCPeerConnection({\r\n        iceServers: [{ urls: [\r\n            \"stun:stun.l.google.com:19302\",\r\n            \"stun:stun1.l.google.com:19302\",\r\n            \"stun:stun2.l.google.com:19302\",\r\n            \"stun:stun3.l.google.com:19302\",\r\n            \"stun:stun4.l.google.com:19302\",\r\n        ]\r\n    }]});\r\n\r\n    peerConnection.addEventListener(\"icecandidate\", (event) => {\r\n        socket.emit(\"ice\", event.candidate, roomName);\r\n    });\r\n}\r\n\r\nwindow.onload = () => {\r\n    socket.emit(\"join\", roomName, onReady);\r\n}\r\n\r\nfunction onMessage(msg) {\r\n    const ul = document.querySelector(\"ul\");\r\n    const li = document.createElement(\"li\");\r\n    li.innerText = msg;\r\n    ul.append(li);\r\n}\r\n\r\nsocket.on(\"welcome\", async () => {\r\n    dataChannel = peerConnection.createDataChannel(\"chat\");\r\n    dataChannel.addEventListener(\"message\", (event) => {\r\n        onMessage(event.data);\r\n    });\r\n\r\n    const offer = await peerConnection.createOffer();\r\n    peerConnection.setLocalDescription(offer);\r\n    socket.emit(\"offer\", offer, roomName);\r\n});\r\n\r\nsocket.on(\"offer\", async (offer) => { \r\n    peerConnection.addEventListener(\"datachannel\", (event) => {\r\n        dataChannel = event.channel;\r\n        dataChannel.addEventListener(\"message\", (event)=> {\r\n            onMessage(event.data);\r\n        });\r\n    })\r\n\r\n    peerConnection.setRemoteDescription(offer);\r\n    const answer = await peerConnection.createAnswer();\r\n    peerConnection.setLocalDescription(answer);\r\n    socket.emit(\"answer\", answer, roomName);\r\n});\r\n\r\nsocket.on(\"answer\", (answer) => {\r\n    peerConnection.setRemoteDescription(answer);\r\n});\r\n\r\nsocket.on(\"ice\", (ice) => {\r\n    peerConnection.addIceCandidate(ice);\r\n});\r\n<\/pre>\n<p>\uc11c\ubc84\ub2e8\uc758 \ucf54\ub4dc\ub294 \ub2e4\uc74c\uacfc \uac19\uc2b5\ub2c8\ub2e4.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\">\r\nimport http from \"http\"\r\nimport express from \"express\";\r\nimport SocketIO from \"socket.io\";\r\n\r\nconst app = express();\r\n\r\napp.set(\"view engine\", \"pug\");\r\napp.set(\"views\", __dirname + \"\/views\");\r\napp.use(\"\/public\", express.static(__dirname + \"\/public\"));\r\napp.get(\"\/\", (_, res) => res.render(\"home\"));\r\n\r\nconst httpServer = http.createServer(app);\r\nconst wsServer = SocketIO(httpServer);\r\n\r\nconst port = 3000;\r\nconst handleListen = () => console.log(`Listening on http:\/\/localhost:${port}`)\r\nhttpServer.listen(port, handleListen);\r\n\r\nwsServer.on(\"connection\", socket => {\r\n    socket.on(\"join\", (roomName, done) => {\r\n        socket.join(roomName);\r\n        done();\r\n        socket.to(roomName).emit(\"welcome\");\r\n    });\r\n\r\n    socket.on(\"offer\", (offer, roomName) => {\r\n        socket.to(roomName).emit(\"offer\", offer);\r\n    });\r\n\r\n    socket.on(\"answer\", (answer, roomName) => {\r\n        socket.to(roomName).emit(\"answer\", answer);\r\n    });\r\n\r\n    socket.on(\"ice\", (ice, roomName) => {\r\n        socket.to(roomName).emit(\"ice\", ice);\r\n    })\r\n});\r\n<\/pre>\n<p>\uc774\uc6a9\ud55c \uae30\uc220\uc740 JS, Node.JS, Express, Socket.IO, Pug\uc785\ub2c8\ub2e4.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>WebRTC\ub294 P2P\uc774\uba70 \uc6f9\uc5d0\uc11c 1:1\ub85c \uc5f0\uacb0\ud558\uc5ec \uc11c\ub85c \ub370\uc774\ud130\ub97c \uc2e4\uc2dc\uac04\uc73c\ub85c \uc8fc\uace0 \ubc1b\ub294 \uc6f9 \ud45c\uc900\uae30\uc220\uc785\ub2c8\ub2e4. \ucd94\ud6c4 \uc801\uc6a9\uc744 \uc704\ud574 \uad00\ub828 \ucf54\ub4dc\ub97c \uc815\ub9ac\ud569\ub2c8\ub2e4. \uba3c\uc800 \uac1c\ub150\ub3c4\ub294 \ub2e4\uc74c\uacfc \uac19\uc2b5\ub2c8\ub2e4. (\uc544\ub798 \uadf8\ub9bc\uc740 WebRTC\uc5d0 \ub300\ud55c \uc774\ud574\ub97c \ub3d5\uae30 \uc704\ud574 \uc81c\uac00 \uc791\uc131\ud55c \uac83\uc73c\ub85c \uc798\ubabb \ud45c\uae30\ub41c \ubd80\ubd84\uc774 \uc788\uc744 \uc218 \uc788\uc2b5\ub2c8\ub2e4.) \uc77c\ub2e8 \ucb49 \ub9d0\ub85c \uc124\uba85\ud558\uba74.. \uba3c\uc800 \ub370\uc774\ud130\ub97c \uc8fc\uace0 \ubc1b\uc744 \ucc44\ub110\uc744 \uc0dd\uc131\ud558\uace0 \ucc44\ub110\uc744 \uc0dd\uc131\ud55c Peer\uac00 \uc81c\uc548(Offer) \uac1d\uccb4\ub97c \ub9cc\ub4e4\uc5b4 \ub2e4\ub978 &hellip; <\/p>\n<p class=\"link-more\"><a href=\"http:\/\/www.gisdeveloper.co.kr\/?p=13327\" class=\"more-link\">\ub354 \ubcf4\uae30<span class=\"screen-reader-text\"> &#8220;WebRTC \ucf54\ub4dc \uc815\ub9ac&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-13327","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=\/wp\/v2\/posts\/13327","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=13327"}],"version-history":[{"count":6,"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=\/wp\/v2\/posts\/13327\/revisions"}],"predecessor-version":[{"id":13337,"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=\/wp\/v2\/posts\/13327\/revisions\/13337"}],"wp:attachment":[{"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=13327"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=13327"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=13327"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}