{"id":5722,"date":"2026-05-19T12:35:26","date_gmt":"2026-05-19T03:35:26","guid":{"rendered":"https:\/\/www.freelifemakers.org\/wordpress\/?p=5722"},"modified":"2026-05-19T12:42:45","modified_gmt":"2026-05-19T03:42:45","slug":"mediaserver-mini_mediaserver_1-code-description-handshake-1-1","status":"publish","type":"post","link":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/2026\/05\/19\/mediaserver-mini_mediaserver_1-code-description-handshake-1-1\/","title":{"rendered":"[Mediaserver]mini_Mediaserver_1-\ucf54\ub4dc\uc124\uba85\/code description-handshake-(1-1)"},"content":{"rendered":"\n<p>\ud83d\udc49\ud83c\udffb \uc544\ub798\ub294 RTMP \ud578\ub4dc \uc170\uc774\ud06c\uc5d0 \ub300\ud55c \uc124\uba85\uc785\ub2c8\ub2e4.<br>Below is an explanation of the RTMP handshake.<\/p>\n\n\n\n<p>\ud83d\udc49\ud83c\udffbRTMP \uc804\uccb4 \ud750\ub984 \/ RTMP full flow , RTMP\ud578\ub4dc \uc170\uc774\ud06c \/ RTMP Handshake<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>TCP \uc5f0\uacb0 \/ TCP connection<br>OBS \u2192server:1935 \uc5f0\uacb0<br>OBS \u2192 server:1935 connection<br><\/li>\n\n\n\n<li>RTMP \ud578\ub4dc\uc170\uc774\ud06c \/ RTMP Handshake<br>1)OBS \u2192 \uc11c\ubc84: C0+C1 1537\ubc14\uc774\ud2b8<br>OBS \u2192 Server: C0+C1 1537 bytes<br><br>2)\uc11c\ubc84 \u2192 OBS: S0+S1+S2 3073\ubc14\uc774\ud2b8<br>Server \u2192 OBS: S0+S1+S2 3073 bytes<br><br>3)OBS \u2192 \uc11c\ubc84: C2 1536\ubc14\uc774\ud2b8<br>OBS \u2192 Server: C2 1536 bytes &#8211;&gt; \uc5ec\uae30\uae4c\uc9c0 \/ Until here<\/li>\n<\/ol>\n\n\n\n<p>\ud83d\udc49\ud83c\udffb1.TCP \uc5f0\uacb0 \/ TCP connection<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># 1935 \uc5f0\uacb0 \/ 1935 connection,rtmp_server.cpp\nvoid RtmpServer::do_accept() {}<\/code><\/pre>\n\n\n\n<p>\ud83d\udc49\ud83c\udffb2.RTMP \ud578\ub4dc \uc170\uc774\ud06c \/ RTMP Handshake<\/p>\n\n\n\n<p>\u2714\ufe0f RTMP\ub294 Adobe\uac00 \ub9cc\ub4e0 \ud504\ub85c\ud1a0\ucf5c\ub85c C0C1 \u2192 S0S1S2 \u2192 C2 \uc21c\uc11c\ub97c \ubb34\uc870\uac74 \uc9c0\ucf1c\uc57c\ud569\ub2c8\ub2e4.<\/p>\n\n\n\n<p>\u2714\ufe0f \uc11c\ubc84\uc640 \ud074\ub77c\uc774\uc5b8\ud2b8 \uac04\uc758 \ud1b5\uc2e0\uc774 RTMP \ud504\ub85c\ud1a0\ucf5c\uc774 \ub9de\ub294\uc9c0 \ud655\uc778\ud558\uae30 \uc704\ud574\uc11c \ud578\ub4dc\uc170\uc774\ud06c \uacfc\uc815 \uc2e4\ud589\ud569\ub2c8\ub2e4.<br>The handshake process is executed to verify that the communication between the server and the client uses the RTMP protocol.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># OBS -&gt; Server\nvoid RtmpSession::do_handshake_c0c1() {}\nvoid RtmpSession::do_handshake_s0s1s2() {}\nvoid RtmpSession::do_handshake_c2() {}<\/code><\/pre>\n\n\n\n<p>\u2714\ufe0f void RtmpSession::do_handshake_c0c1(){}<\/p>\n\n\n\n<p>&#8212; \ud578\ub4dc\uc170\uc774\ud06c 1\ub2e8\uacc4\uc785\ub2c8\ub2e4. \/ This is step 1 of the handshake.<\/p>\n\n\n\n<p>&#8212; OBS\uac00 \ubcf4\ub0b8 C0+C1 \ubc1b\ub294 \ud568\uc218 \uc785\ub2c8\ub2e4.<br>This is a function that receives C0+C1 sent by OBS.<\/p>\n\n\n\n<p>&#8212; asio::async_read(socket_, asio::buffer(c0c1_, 1537) : <\/p>\n\n\n\n<p>1)RTMP \uaddc\uaca9 \/ RTMP standard:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>C0: 1\ubc14\uc774\ud2b8 = RTMP \ubc84\uc804. \ud56d\uc0c1&nbsp;<code>0x03<\/code>(16\uc9c4\uc218,10\uc9c4\uc218\ub85c\ub294 3)<br>C0: 1 byte = RTMP version. Always 0x03 (hexadecimal, 3 in decimal)<\/li>\n\n\n\n<li><\/li>\n\n\n\n<li>C1: 1536\ubc14\uc774\ud2b8 = time, zero, random \ub370\uc774\ud130<\/li>\n\n\n\n<li>C1: 1536 bytes = time, zero, random data<\/li>\n<\/ul>\n\n\n\n<p>2)C0 + C1 = 1537 byte<\/p>\n\n\n\n<p>3)\ubc84\uc804\uccb4\ud06c \uc131\uacf5\ud558\uba74 do_handshake_s0s1s2(); \uc2e4\ud589<br>If the version check is successful, execute do_handshake_s0s1s2();<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>void RtmpSession::do_handshake_c0c1() {\n\n    \/\/ RtmpSession\uc815\ubcf4 \ubcf5\uc0ac\n    \/\/ Copy RtmpSession information\n    \/\/\n    \/\/ auto self = shared_from_this();\n    \/\/ auto self = shared_from_this();\n    \/\/\n    \/\/ \uc544\ub798\ub294 shared_ptr \uac1d\uccb4\ub97c \ud558\ub098\ub354 \ub9cc\ub4e6\n    \/\/ The following creates another shared_ptr object\n    auto self(shared_from_this());\n\n    \/\/ OBS\uac00 \ubcf4\ub0b8 C0+C1 1537\ubc14\uc774\ud2b8\ub97c c0c1_ \ubc30\uc5f4\uc5d0 \uc800\uc7a5\n    \/\/ Store the 1537 bytes of C0+C1 sent by OBS in the c0c1_ array\n    asio::async_read(socket_, asio::buffer(c0c1_, 1537),\n        &#91;this, self](std::error_code ec, std::size_t) {\n            \/\/ \ud504\ub85c\ud1a0\ucf5c \ubc84\uc804 \uccb4\ud06c \/ Check protocol version\n            if (ec || c0c1_&#91;0]!= 0x03) return;\n            std::cout &lt;&lt; \"&#91;Handshake] C0C1 received\\n\";\n            do_handshake_s0s1s2();\n        });\n}<\/code><\/pre>\n\n\n\n<p>\u2714\ufe0f void RtmpSession::do_handshake_s0s1s2(){}<\/p>\n\n\n\n<p>&#8212; \ud578\ub4dc\uc170\uc774\ud06c 2\ub2e8\uacc4\uc785\ub2c8\ub2e4.<br>This is step 2 of the handshake.<\/p>\n\n\n\n<p>&#8212; OBS\uc5d0\uc11c \ubc1b\uc740 \uc815\ubcf4\ub97c \uc11c\ubc84\uc815\ubcf4\uc640 \ucde8\ud569\ud574\uc11c \ub2e4\uc2dc OBS\uc5d0\uac8c \ub3cc\ub824 \uc90d\ub2c8\ub2e4.<br>It combines the information received from OBS with server information and returns it to OBS.<\/p>\n\n\n\n<p>&#8212; 3073\ubc14\uc774\ud2b8\ub97c OBS\uc5d0 \uc804\uc1a1\ud558\uace0\ub098\uc11c do_handshake_c2();\ub97c \uc2e4\ud589\ud569\ub2c8\ub2e4.<br>After sending 3073 bytes to OBS, execute do_handshake_c2();.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td>\uc601\uc5ed\/Area<\/td><td>\ud06c\uae30\/Size<\/td><td>\uc778\ub371\uc2a4\/Index<\/td><td>\ub0b4\uc6a9\/Detail<\/td><td>\ucf54\ub4dc\/Code<\/td><\/tr><tr><td>S0<\/td><td>1byte<\/td><td>[0]<\/td><td>Version&nbsp;<code>0x03<\/code><\/td><td>s0s1s2_[0] = 0x03<\/td><\/tr><tr><td>S1<\/td><td>1536byte<\/td><td>[1\u223c1536]<\/td><td>\uc11c\ubc84 \ub370\uc774\ud130\/Server data<\/td><td><\/td><\/tr><tr><td>S1:time<\/td><td>4byte<\/td><td>[1\u223c4]<\/td><td>\uc11c\ubc84 \ud604\uc7ac\uc2dc\uac04\/Server Current time<\/td><td>memcpy(&amp;s0s1s2_[1], &amp;time, 4)<\/td><\/tr><tr><td>S1:zero<\/td><td>4byte<\/td><td>[5\u223c8]<\/td><td>0\uc73c\ub85c \ucc44\uc6c0 \/ Fill with zeros<\/td><td>memset(&amp;s0s1s2_[5], 0, 4)<\/td><\/tr><tr><td>S1:random<\/td><td>1528byte<\/td><td>[9\u223c1536]<\/td><td>\ub79c\ub364\uac12 \/ Random value<\/td><td>RAND_bytes(&amp;s0s1s2_[9], 1528)<\/td><\/tr><tr><td>S2<\/td><td>1536byte<\/td><td>[1537\u223c3072]<\/td><td>C1 \ubcf5\uc0ac\ubcf8 \/ C1 copy<\/td><td>memcpy(&amp;s0s1s2_[1537], &amp;c0c1_[1], 1536)<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \uc11c\ubc84 \u2192 OBS\ub85c S0+S1+S2 3073\ubc14\uc774\ud2b8 \ubcf4\ub0b4\ub294 \ud578\ub4dc\uc170\uc774\ud06c 2\ub2e8\uacc4\n\/\/ Handshake Step 2: Sending 3073 bytes (S0+S1+S2) from Server to OBS\nvoid RtmpSession::do_handshake_s0s1s2() {\n    \/\/ \uc138\uc158 \uc815\ubcf4 \uc720\uc9c0 \/ Maintain session information\n    auto self(shared_from_this());\n    s0s1s2_&#91;0] = 0x03; \/\/ \uc11c\ubc84\ubc84\uc804 03 \/ Server version 03\n\n    \/\/ \ud604\uc7ac\uc2dc\uac04 \ube45\uc5d4\ub514\uc548 \ubcc0\ud658,\ub124\ud2b8\uc6cc\ud06c \ubc14\uc774\ud2b8 \uc21c\uc11c = \ube45\uc5d4\ub514\uc548 \ubcc0\ud658,OBS\uac00 RTT \uacc4\uc0b0\ud560 \ub54c \uc500.\n    \/\/ Current time converted to Big Endian, Network Byte Order = Big Endian conversion,\n    \/\/ used by OBS when calculating RTT.\n    uint32_t time = htonl(static_cast&lt;uint32_t&gt;(::time(nullptr)));\n\n    \/\/ S1 \uccab 4\ubc14\uc774\ud2b8\uc5d0 \uc11c\ubc84 \ud604\uc7ac\uc2dc\uac04 \ub123\uc74c.\n    \/\/ Insert server current time into the first 4 bytes of S1.\n    std::memcpy(&amp;s0s1s2_&#91;1], &amp;time, 4);\n\n    \/\/ S1 4\u223c7\ubc14\uc774\ud2b8\ub294 \uaddc\uaca9\uc0c1 0\uc73c\ub85c \ucc44\uc6cc\uc57c \ud568.\n    \/\/ S1 bytes 4~7 must be filled with zeros according to the standard.\n    std::memset(&amp;s0s1s2_&#91;5], 0, 4);\n\n    \/\/ OpenSSL\ub85c \ub79c\ub364\uac12 \ucc44\uc6c0(RTMPE\uba74 \uacf5\uac1c \ud0a4 \uc5ed\ud560)\n    \/\/ Fill with random values \u200b\u200busing OpenSSL (acts as public key if RTMPE)\n    RAND_bytes(&amp;s0s1s2_&#91;9], 1528);\n\n    \/\/ &amp;s0s1s2_&#91;1537]\uc5d0 &amp;c0c1_&#91;1] \uc815\ubcf4\ub97c 1536\ubc14\uc774\ud2b8\ub9cc\ud07c \ubcf5\uc0ac\n    \/\/ Copy 1536 bytes of &amp;c0c1_&#91;1] information to &amp;s0s1s2_&#91;1537]\n    \/\/\n    \/\/ 1537 = S0+S1\uc774 1537\ubc14\uc774\ud2b8\n\n    \/\/ 1537 = S0+S1 is 1537 bytes\n    std::memcpy(&amp;s0s1s2_&#91;1537], &amp;c0c1_&#91;1], 1536);\n\n    \/\/ \uc804\uccb4 3073\ubc14\uc774\ud2b8\ub97c OBS\ub85c \uc804\uc1a1\n    \/\/ Send the entire 3073 bytes to OBS\n    asio::async_write(socket_, asio::buffer(s0s1s2_, 3073),\n        &#91;this, self](std::error_code ec, std::size_t) {\n            if (ec) return;\n            std::cout &lt;&lt; \"&#91;Handshake] S0S1S2 sent\\n\";\n            do_handshake_c2();\n        });\n}<\/code><\/pre>\n\n\n\n<p>\u2714\ufe0f void RtmpSession::do_handshake_c2() {}<\/p>\n\n\n\n<p>&#8212; \ud578\ub4dc\uc170\uc774\ud06c 3\ub2e8\uacc4\uc785\ub2c8\ub2e4.<br>This is step 3 of the handshake.<\/p>\n\n\n\n<p>&#8212; OBS\ub85c \ubd80\ud130 \ub450\ubc88\uc9f8\ub85c(C2) 1536\ubc14\uc774\ud2b8\ub97c \ubc1b\uc2b5\ub2c8\ub2e4.<br>Receive 1536 bytes for the second (C2) from OBS.<\/p>\n\n\n\n<p>&#8212; \uc644\uc804\ud788 \ub2e4 \ubc1b\uc73c\uba74 send_protocol_messages(); \ud568\uc218\ub97c \uc2e4\ud589\ud569\ub2c8\ub2e4.<br>Once everything is fully received, the send_protocol_messages(); function is executed.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\ud83d\udc49\ud83c\udffb \uc544\ub798\ub294 RTMP \ud578\ub4dc \uc170\uc774\ud06c\uc5d0 \ub300\ud55c \uc124\uba85\uc785\ub2c8\ub2e4.Below is an explanation of the RTMP handshake. \ud83d\udc49\ud83c\udffbRTMP \uc804\uccb4 \ud750\ub984 \/ RTMP full flow , RTMP\ud578\ub4dc \uc170\uc774\ud06c \/ RTMP Handshake \ud83d\udc49\ud83c\udffb1.TCP \uc5f0\uacb0 \/ TCP connection \ud83d\udc49\ud83c\udffb2.RTMP \ud578\ub4dc \uc170\uc774\ud06c \/ RTMP Handshake \u2714\ufe0f RTMP\ub294 Adobe\uac00 \ub9cc\ub4e0 \ud504\ub85c\ud1a0\ucf5c\ub85c C0C1 \u2192 S0S1S2 \u2192 C2 \uc21c\uc11c\ub97c \ubb34\uc870\uac74 \uc9c0\ucf1c\uc57c\ud569\ub2c8\ub2e4. \u2714\ufe0f \uc11c\ubc84\uc640 \ud074\ub77c\uc774\uc5b8\ud2b8 \uac04\uc758 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[23,1],"tags":[],"class_list":["post-5722","post","type-post","status-publish","format-standard","hentry","category-cpp","category-uncategorized","missing-thumbnail"],"_links":{"self":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/5722","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/comments?post=5722"}],"version-history":[{"count":3,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/5722\/revisions"}],"predecessor-version":[{"id":5726,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/5722\/revisions\/5726"}],"wp:attachment":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/media?parent=5722"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/categories?post=5722"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/tags?post=5722"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}