<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: MinBapE</title>
    <description>The latest articles on DEV Community by MinBapE (@min38).</description>
    <link>https://dev.to/min38</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3610445%2Ffd5a6542-8e0c-4d02-b0ca-cf82a6aa9da2.png</url>
      <title>DEV Community: MinBapE</title>
      <link>https://dev.to/min38</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/min38"/>
    <language>en</language>
    <item>
      <title>[C++ 2D Arena Shooter Server #2] Packet Structure</title>
      <dc:creator>MinBapE</dc:creator>
      <pubDate>Sat, 16 May 2026 08:15:57 +0000</pubDate>
      <link>https://dev.to/min38/c-2d-arena-shooter-server-2-packet-structure-19a8</link>
      <guid>https://dev.to/min38/c-2d-arena-shooter-server-2-packet-structure-19a8</guid>
      <description>&lt;h2&gt;
  
  
  What I did today
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Designing the packet header
&lt;/h3&gt;

&lt;p&gt;I defined the format for data exchanged between the client and server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PacketType&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;uint16_t&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ENTER_GAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="cp"&gt;#pragma pack(push, 1)
&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;PacketHeader&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;PacketType&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;uint16_t&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// payload size, not including the header&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="cp"&gt;#pragma pack(pop)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The reason I applied &lt;code&gt;#pragma pack(1)&lt;/code&gt; to &lt;code&gt;PacketHeader&lt;/code&gt; is that compilers insert padding between struct members by default. For example, if a &lt;code&gt;uint8_t&lt;/code&gt; is followed by a &lt;code&gt;uint32_t&lt;/code&gt;, the compiler may insert 3 bytes of padding in between. If the struct is transmitted over the network in that state, the layout will differ depending on the compiler settings on each side. Since packet headers must align at the byte level, I used &lt;code&gt;#pragma pack(1)&lt;/code&gt; to eliminate the padding.&lt;/p&gt;

&lt;p&gt;The same reasoning applies to &lt;code&gt;PacketType&lt;/code&gt;. A plain &lt;code&gt;enum&lt;/code&gt; has an implementation-defined size that can vary by compiler, so I explicitly fixed it to 2 bytes using &lt;code&gt;enum class PacketType : uint16_t&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The resulting format is always 4 bytes for the header (2 for type, 2 for size), followed by &lt;code&gt;size&lt;/code&gt; bytes of payload.&lt;/p&gt;




&lt;h3&gt;
  
  
  PacketBuffer: serialization utility
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;PacketBuffer&lt;/code&gt; is the class responsible for reading and writing packet data at the byte level.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;static_assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;is_trivially_copyable_v&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"T must be trivially copyable"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;constexpr&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;is_arithmetic_v&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;to_le&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;reinterpret_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;_buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;static_assert(std::is_trivially_copyable_v&amp;lt;T&amp;gt;)&lt;/code&gt; is a compile-time safety check. If someone accidentally passes a type like &lt;code&gt;std::string&lt;/code&gt;, which internally holds a pointer, the code will fail to compile rather than silently producing garbage bytes at runtime.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;reinterpret_cast&amp;lt;const char*&amp;gt;(&amp;amp;value)&lt;/code&gt; reinterprets the address of the value as a byte pointer, giving a byte-level view of T's memory regardless of its type. The subsequent &lt;code&gt;_buffer.insert&lt;/code&gt; copies exactly &lt;code&gt;sizeof(T)&lt;/code&gt; bytes to the end of the buffer. This is equivalent to &lt;code&gt;memcpy&lt;/code&gt;, but integrated directly into the &lt;code&gt;std::vector&lt;/code&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  Endian handling
&lt;/h3&gt;

&lt;p&gt;When communicating over a network, there is no guarantee that both sides use the same byte order. I chose little-endian as the wire format for this project. On x86 and ARM, which are already little-endian, no actual byte swapping occurs. However, the code is written to handle big-endian environments correctly as well.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="n"&gt;detail&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;to_le&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cp"&gt;#if defined(__BYTE_ORDER__) &amp;amp;&amp;amp; __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
&lt;/span&gt;        &lt;span class="c1"&gt;// byte swapping only happens on big-endian machines&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="cp"&gt;#else
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// no-op on x86/ARM&lt;/span&gt;
    &lt;span class="cp"&gt;#endif
&lt;/span&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because the branching is done with &lt;code&gt;if constexpr&lt;/code&gt; at compile time, there is no runtime overhead.&lt;/p&gt;




&lt;h3&gt;
  
  
  Data models: Vector3, PlayerSnapshot, MatchSnapshot
&lt;/h3&gt;

&lt;p&gt;I defined the basic game data structures for player positions and state.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;Vector3&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;PlayerSnapshot&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;uint32_t&lt;/span&gt; &lt;span class="n"&gt;playerId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;Vector3&lt;/span&gt;  &lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;float&lt;/span&gt;    &lt;span class="n"&gt;yaw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pitch&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int32_t&lt;/span&gt;  &lt;span class="n"&gt;hp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;bool&lt;/span&gt;     &lt;span class="n"&gt;isAlive&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;Serialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PacketBuffer&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;PlayerSnapshot&lt;/span&gt; &lt;span class="n"&gt;Deserialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PacketBuffer&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;PlayerSnapshot&lt;/code&gt; is the DTO sent to the client. It is conceptually different from a &lt;code&gt;Player&lt;/code&gt; class that would hold authoritative server state — &lt;code&gt;PlayerSnapshot&lt;/code&gt; exists solely to serialize that state for transmission. I defined it at this stage because I wanted to test the packet format before implementing the game loop. The fields may change once the game loop is in place.&lt;/p&gt;

&lt;p&gt;The reason &lt;code&gt;Serialize&lt;/code&gt; writes each &lt;code&gt;Vector3&lt;/code&gt; field individually rather than the whole struct at once is explained in the debugging section below.&lt;/p&gt;




&lt;h3&gt;
  
  
  Session packet parsing: TCP framing
&lt;/h3&gt;

&lt;p&gt;The original &lt;code&gt;Session::handle()&lt;/code&gt; was a simple echo loop that sent received data back as-is. I replaced it with actual packet parsing.&lt;/p&gt;

&lt;p&gt;TCP is a stream protocol, which means a single &lt;code&gt;recv&lt;/code&gt; call does not guarantee that exactly one packet has arrived. Multiple packets may arrive together, or a single packet may arrive split across multiple calls. To handle this, I accumulate received bytes into &lt;code&gt;_recvBuf&lt;/code&gt; and process complete packets one at a time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;Session&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;RECV_BUFFER_SIZE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="kt"&gt;ssize_t&lt;/span&gt; &lt;span class="n"&gt;bytesRead&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;bytesRead&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;recv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_clientFd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_recvBuf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_recvBuf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;bytesRead&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;processPackets&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;Session&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;processPackets&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;constexpr&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;HEADER_SIZE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PacketHeader&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_recvBuf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;HEADER_SIZE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;PacketBuffer&lt;/span&gt; &lt;span class="n"&gt;headerBuf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_recvBuf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;HEADER_SIZE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;rawType&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;headerBuf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Read&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;uint16_t&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;payloadLen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;headerBuf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Read&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;uint16_t&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_recvBuf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;HEADER_SIZE&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;payloadLen&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// payload not fully received yet, wait for more data&lt;/span&gt;

        &lt;span class="n"&gt;PacketBuffer&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_recvBuf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;HEADER_SIZE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payloadLen&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;_recvBuf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;erase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_recvBuf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;_recvBuf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;HEADER_SIZE&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;payloadLen&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;_dispatcher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;static_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;PacketType&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rawType&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reading the header through &lt;code&gt;PacketBuffer::Read&lt;/code&gt; rather than a raw &lt;code&gt;memcpy&lt;/code&gt; ensures that endian conversion is applied consistently. Reading raw bytes on a big-endian machine would produce flipped type and size values.&lt;/p&gt;




&lt;h3&gt;
  
  
  PacketDispatcher: packet router
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;PacketDispatcher&lt;/code&gt; looks up the handler registered for a given packet type and calls it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PacketDispatcher&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;public:&lt;/span&gt;
    &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="n"&gt;Handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Session&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PacketBuffer&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;registerHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PacketType&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Handler&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Session&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PacketType&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PacketBuffer&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nl"&gt;private:&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;unordered_map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;uint16_t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_handlers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I used &lt;code&gt;uint16_t&lt;/code&gt; as the map key instead of &lt;code&gt;PacketType&lt;/code&gt; because the C++ standard does not explicitly require a &lt;code&gt;std::hash&lt;/code&gt; specialization for &lt;code&gt;enum class&lt;/code&gt;, and behavior can vary across compilers.&lt;/p&gt;

&lt;p&gt;Handlers are owned by &lt;code&gt;TcpListener&lt;/code&gt; and registered before the accept loop starts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;TcpListener&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;registerHandlers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;_dispatcher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;registerHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PacketType&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ENTER_GAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[](&lt;/span&gt;&lt;span class="n"&gt;Session&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PacketBuffer&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;nickname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MAX_NICKNAME_LEN&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"[ENTER_GAME] nickname="&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;nickname&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Session&lt;/code&gt; receives a &lt;code&gt;PacketDispatcher&amp;amp;&lt;/code&gt; in its constructor and stores it as a member. This makes the dependency explicit: a Session cannot function without a dispatcher.&lt;/p&gt;




&lt;h2&gt;
  
  
  Next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Session Manager: tracking connected clients and broadcasting to all sessions&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Advice and feedback are welcome.&lt;/p&gt;

</description>
      <category>backend</category>
      <category>cpp</category>
      <category>gamedev</category>
      <category>networking</category>
    </item>
    <item>
      <title>[Lime #2] How To Search Music</title>
      <dc:creator>MinBapE</dc:creator>
      <pubDate>Mon, 11 May 2026 13:57:28 +0000</pubDate>
      <link>https://dev.to/min38/lime-2-how-to-search-music-2mi1</link>
      <guid>https://dev.to/min38/lime-2-how-to-search-music-2mi1</guid>
      <description>&lt;h2&gt;
  
  
  What I worked on
&lt;/h2&gt;

&lt;p&gt;I designed and implemented the music search pipeline for Lime.&lt;/p&gt;

&lt;p&gt;Music search sounds simple. Take a query, return results.&lt;/p&gt;

&lt;p&gt;But there was more to think about than expected.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Users should be able to search for music that isn't in Lime's internal DB yet&lt;/li&gt;
&lt;li&gt;Calling external APIs on every search request is slow and costly&lt;/li&gt;
&lt;li&gt;If an external API fails, search shouldn't break entirely&lt;/li&gt;
&lt;li&gt;Saving every external result directly to the DB would pollute it with data nobody cares about&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To satisfy these constraints, I split search into two separate flows.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The search API returns internal DB results and cached candidates first.&lt;br&gt;&lt;br&gt;
External provider searches are handled asynchronously through background Jobs.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Internal DB search for Artists, Albums, and Tracks&lt;/li&gt;
&lt;li&gt;SearchCandidate model and candidate caching&lt;/li&gt;
&lt;li&gt;SearchJob enqueueing and ExternalSearchWorker (background processing)&lt;/li&gt;
&lt;li&gt;External provider interface with MusicBrainz and Spotify implementations&lt;/li&gt;
&lt;li&gt;Per-provider Rate Limiter&lt;/li&gt;
&lt;li&gt;Merging internal DB results with external candidates, with deduplication&lt;/li&gt;
&lt;li&gt;SearchCandidate → Artist / Album / Track Import API&lt;/li&gt;
&lt;li&gt;ExternalMusicIds (cross-platform ID linking)&lt;/li&gt;
&lt;li&gt;ExternalGenreTags (storing provider genre tags as-is)&lt;/li&gt;
&lt;li&gt;Graceful degradation when providers fail&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The full flow
&lt;/h2&gt;

&lt;p&gt;When a user types a search query, here's what happens.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /search?keyword=radiohead

1. Normalize the keyword
2. Search internal DB for Artists, Albums, Tracks (parallel)
3. Query SearchCandidate cache for candidates (parallel)
4. Enqueue SearchJobs per external provider (async — does not block)
5. Merge internal results with cached candidates
6. Return response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key point is that &lt;strong&gt;Step 4 does not block the response&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The user gets internal results and previously cached candidates immediately.&lt;br&gt;&lt;br&gt;
Background Jobs handle the external search, and the next request will see those results.&lt;/p&gt;

&lt;p&gt;The API looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET  /search?keyword=...
POST /search/import/{candidateId}
GET  /search/albums/{albumId}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  SearchCandidate: not permanent data, just candidates
&lt;/h2&gt;

&lt;p&gt;My first instinct was to save external provider results directly into the Artist, Album, and Track tables.&lt;/p&gt;

&lt;p&gt;But thinking it through, that's a problem.&lt;/p&gt;

&lt;p&gt;A user searching "radiohead" shouldn't cause dozens of MusicBrainz albums to become permanent Lime records.&lt;br&gt;&lt;br&gt;
Only music the user actually wants to review should become permanent data.&lt;/p&gt;

&lt;p&gt;So external search results are first stored as &lt;code&gt;SearchCandidate&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SearchCandidate
  - provider          (MusicBrainz, Spotify...)
  - providerEntityId  (the provider's own ID for this entity)
  - resultType        (Artist, Album, Track)
  - title
  - artistName
  - coverImageUrl
  - releaseDate
  - expiresAt         (cache TTL: 24 hours)
  - rawJson           (original response payload)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;expiresAt&lt;/code&gt; exists because this is a cache.&lt;br&gt;&lt;br&gt;
After 24 hours, results are treated as stale and re-fetched on the next search.&lt;/p&gt;

&lt;p&gt;Only when a user picks a specific candidate does it get promoted to permanent data.&lt;/p&gt;


&lt;h2&gt;
  
  
  SearchJob: decoupling external search from the request
&lt;/h2&gt;

&lt;p&gt;If the search API called external providers directly, two problems would follow.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;External APIs like MusicBrainz have rate limits (1 request per second)&lt;/li&gt;
&lt;li&gt;A slow or failing external API would make the entire search endpoint slow&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So I moved external search into &lt;code&gt;SearchJob&lt;/code&gt; entries and let a background &lt;code&gt;ExternalSearchWorker&lt;/code&gt; process them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SearchJob
  - normalizedQuery  (normalized search term)
  - provider         (MusicBrainz, Spotify...)
  - resultType       (Artist, Album, Track)
  - status           (Pending, Running, Completed, Failed)
  - startedAt
  - completedAt
  - failedReason
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a Job with the same &lt;code&gt;(normalizedQuery, provider, resultType)&lt;/code&gt; already exists, a duplicate isn't created.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ExternalSearchWorker&lt;/code&gt; runs every 5 seconds.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Fetch Pending Jobs
2. Mark each Job as Running
3. Call the corresponding provider
4. Save results as SearchCandidates
5. Mark the Job as Completed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Provider abstraction and Rate Limiter
&lt;/h2&gt;

&lt;p&gt;Just like OAuth providers were abstracted behind an interface in the auth feature, external music sources follow the same pattern.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;internal&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IExternalMusicProvider&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;ProviderName&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IReadOnlyList&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ExternalProviderResult&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;SearchArtistsAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IReadOnlyList&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ExternalProviderResult&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;SearchAlbumsAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IReadOnlyList&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ExternalProviderResult&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;SearchTracksAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IReadOnlyList&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;GenreTagResult&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;LookupTagsAsync&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromResult&lt;/span&gt;&lt;span class="p"&gt;(...);&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ReleaseDetailResult&lt;/span&gt;&lt;span class="p"&gt;?&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;LookupReleaseDetailAsync&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromResult&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ReleaseDetailResult&lt;/span&gt;&lt;span class="p"&gt;?&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;LookupTagsAsync&lt;/code&gt; and &lt;code&gt;LookupReleaseDetailAsync&lt;/code&gt; have default implementations that return empty results.&lt;br&gt;&lt;br&gt;
Not every provider needs to support genre tag lookups or detailed metadata fetching.&lt;/p&gt;

&lt;p&gt;Adding Apple Music later means creating an &lt;code&gt;AppleProvider&lt;/code&gt; and registering it with DI.&lt;br&gt;&lt;br&gt;
&lt;code&gt;ExternalSearchWorker&lt;/code&gt; looks up providers by name, so it's open for extension without modification.&lt;/p&gt;
&lt;h3&gt;
  
  
  Rate Limiter
&lt;/h3&gt;

&lt;p&gt;MusicBrainz allows 1 request per second.&lt;br&gt;&lt;br&gt;
Exceed that and you get 429 responses.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ProviderRateLimiter&lt;/code&gt; uses a &lt;code&gt;SemaphoreSlim&lt;/code&gt; to enforce the minimum interval between calls.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;internal&lt;/span&gt; &lt;span class="k"&gt;sealed&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProviderRateLimiter&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IDisposable&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;SemaphoreSlim&lt;/span&gt; &lt;span class="n"&gt;_semaphore&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;TimeSpan&lt;/span&gt; &lt;span class="n"&gt;_minInterval&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;_lastAcquired&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MinValue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;WaitAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_semaphore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WaitAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;elapsed&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UtcNow&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;_lastAcquired&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elapsed&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;_minInterval&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_minInterval&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;elapsed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="n"&gt;_lastAcquired&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UtcNow&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;finally&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;_semaphore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Release&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each provider can have its own rate limit policy, managed by a singleton &lt;code&gt;ProviderRateLimiterRegistry&lt;/code&gt; keyed by provider name.&lt;/p&gt;




&lt;h2&gt;
  
  
  Merging search results
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;SearchMerger&lt;/code&gt; combines internal DB results with SearchCandidate results.&lt;/p&gt;

&lt;p&gt;The rules are straightforward.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Internal DB results go in first
2. External candidates are appended (up to 10 total per type) if not already present
3. Duplicates are detected by title + artist name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using &lt;code&gt;ExternalMusicIds&lt;/code&gt; for deduplication would be more precise, but title-based comparison is sufficient for now.&lt;/p&gt;

&lt;p&gt;Internal DB results always come first.&lt;br&gt;&lt;br&gt;
If the same album exists in both internal and external results, only the internal one stays.&lt;/p&gt;


&lt;h2&gt;
  
  
  Import: promoting a candidate to permanent data
&lt;/h2&gt;

&lt;p&gt;When a user selects a candidate, the client calls &lt;code&gt;POST /search/import/{candidateId}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This promotes a &lt;code&gt;SearchCandidate&lt;/code&gt; into Lime's permanent &lt;code&gt;Artist&lt;/code&gt;, &lt;code&gt;Album&lt;/code&gt;, or &lt;code&gt;Track&lt;/code&gt; records.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Look up the SearchCandidate by candidateId
2. Check ExternalMusicIds to see if it's already been imported
3. If yes, return the existing internal ID (prevent duplicate imports)
4. If no, find or create Artist → Album → Track in order
5. Save the platform ID in ExternalMusicIds
6. Save genre tags in ExternalGenreTags
7. If it's an album, enqueue a metadata enrichment Job
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"Find or create" is the important phrase here.&lt;/p&gt;

&lt;p&gt;The same artist or album might already exist in Lime.&lt;br&gt;&lt;br&gt;
The service searches by name first, and only creates a new record if nothing matches.&lt;/p&gt;

&lt;p&gt;For example, when importing a Radiohead album, if Radiohead already exists in Lime, the import links to that existing artist rather than creating a duplicate.&lt;/p&gt;


&lt;h2&gt;
  
  
  ExternalMusicIds: linking platform IDs
&lt;/h2&gt;

&lt;p&gt;This table connects MusicBrainz album IDs with Lime's internal Album IDs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ExternalMusicId
  - provider          (MusicBrainz, Spotify...)
  - providerEntityId  (the provider's ID for this entity)
  - entityType        (Artist, Album, Track)
  - internalId        (Lime's internal ID)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thanks to this table, when the same album is later fetched from Spotify, it can be linked to the existing Lime record instead of creating a duplicate.&lt;/p&gt;

&lt;p&gt;It's the connective tissue that solves the problem: same music, different ID on every platform.&lt;/p&gt;

&lt;p&gt;Duplicate imports are also prevented here.&lt;br&gt;&lt;br&gt;
If the same &lt;code&gt;(provider, providerEntityId, entityType)&lt;/code&gt; already exists, the existing internal ID is returned as-is.&lt;/p&gt;


&lt;h2&gt;
  
  
  ExternalGenreTags: store genres verbatim
&lt;/h2&gt;

&lt;p&gt;Lime doesn't try to define its own canonical genre taxonomy.&lt;/p&gt;

&lt;p&gt;If MusicBrainz says "alternative rock", that's what gets stored.&lt;br&gt;&lt;br&gt;
If Spotify says "indie", "indie" gets stored.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ExternalGenreTag
  - entityType     (Artist, Album, Track)
  - entityId       (Lime's internal ID)
  - provider       (MusicBrainz, Spotify...)
  - tagName        (house, alternative rock, ambient...)
  - sourceLevel    (Artist, Album, Track, ReleaseGroup, Video)
  - providerEntityId
  - fetchedAt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same &lt;code&gt;(entity, provider, tagName)&lt;/code&gt; combination is never stored twice.&lt;/p&gt;

&lt;p&gt;On the frontend, the plan is to display genres with their source: "MusicBrainz: alternative rock, indie".&lt;/p&gt;




&lt;h2&gt;
  
  
  The tricky part: when do external results become permanent?
&lt;/h2&gt;

&lt;p&gt;The question I thought about the most during this work was:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When and how should external search results become permanent data?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The options I considered were:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A. Save immediately when search results come in
B. Save when the user selects something (synchronous in the search API)
C. Keep in cache only; promote to permanent data on selection
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A is simple to implement, but useless data accumulates fast.&lt;br&gt;&lt;br&gt;
B means the search API has to wait for external API responses before it can reply.&lt;br&gt;&lt;br&gt;
C is what I went with.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SearchCandidate&lt;/code&gt; is a cache. After 24 hours it's stale.&lt;br&gt;&lt;br&gt;
Only when a user decides "I want to review this album" does it get promoted to permanent data.&lt;/p&gt;

&lt;p&gt;Search stays fast. Data promotion happens after selection.&lt;br&gt;&lt;br&gt;
That separation is the core of this design.&lt;/p&gt;


&lt;h2&gt;
  
  
  A provider failure is not a search failure
&lt;/h2&gt;

&lt;p&gt;MusicBrainz being unavailable shouldn't break search.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ExternalSearchWorker&lt;/code&gt; handles provider failures by case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ProviderRateLimitException   -&amp;gt; mark Job Failed ("Rate limit exceeded")
ProviderUnavailableException -&amp;gt; mark Job Failed ("Provider unavailable")
any other exception          -&amp;gt; mark Job Failed (exception message)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All failures are recorded at the Job level.&lt;br&gt;&lt;br&gt;
The search response communicates this via an &lt;code&gt;externalSearchStatus&lt;/code&gt; field.&lt;/p&gt;

&lt;p&gt;From the user's perspective, internal DB results and cached candidates are always returned first.&lt;br&gt;&lt;br&gt;
If external search failed, the status is visible in the response.&lt;/p&gt;


&lt;h2&gt;
  
  
  Album enrichment
&lt;/h2&gt;

&lt;p&gt;When an album is imported, detailed metadata — cover image, tracklist, genres — isn't fetched immediately.&lt;/p&gt;

&lt;p&gt;Trying to fetch everything at import time would slow down that API call.&lt;br&gt;&lt;br&gt;
So immediately after import, an enrichment Job is enqueued for &lt;code&gt;AlbumEnrichmentWorker&lt;/code&gt; to process.&lt;/p&gt;

&lt;p&gt;Enrichment includes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Fetching cover art from Cover Art Archive
- Filling in release date
- Saving tracklist and track numbers
- Collecting genre tags per provider
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Search stays fast. Details come after selection.&lt;br&gt;&lt;br&gt;
This same principle showed up in both search and enrichment.&lt;/p&gt;


&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;This work established the core search pipeline for Lime.&lt;/p&gt;

&lt;p&gt;Here's the full picture:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Search API
  -&amp;gt; Internal DB search (parallel)
  -&amp;gt; Cached external candidates (parallel)
  -&amp;gt; Enqueue external SearchJobs (async, non-blocking)
  -&amp;gt; Merge results + deduplicate + cap at 10 per type

Background Worker
  -&amp;gt; Process SearchJobs
  -&amp;gt; Call provider (rate-limited)
  -&amp;gt; Save results as SearchCandidates

Import API
  -&amp;gt; SearchCandidate → Artist, Album, Track
  -&amp;gt; Link ExternalMusicIds
  -&amp;gt; Save ExternalGenreTags
  -&amp;gt; Enqueue enrichment Job for albums
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The search pipeline turned out to be more than "take a query, return results".&lt;/p&gt;

&lt;p&gt;Thinking through response latency, API rate limits, data consistency, and provider failure handling made the flow considerably longer than expected.&lt;/p&gt;

&lt;p&gt;Next up is wiring the review feature into this search foundation.&lt;br&gt;&lt;br&gt;
Leaving a rating on an imported track — that's what Lime is for.&lt;/p&gt;

</description>
      <category>dotnet</category>
    </item>
    <item>
      <title>[Lime #1] OAuth Login</title>
      <dc:creator>MinBapE</dc:creator>
      <pubDate>Fri, 08 May 2026 17:52:14 +0000</pubDate>
      <link>https://dev.to/min38/lime-1-oauth-login-33ae</link>
      <guid>https://dev.to/min38/lime-1-oauth-login-33ae</guid>
      <description>&lt;h2&gt;
  
  
  Today's Work
&lt;/h2&gt;

&lt;p&gt;I decided on and implemented the login flow for Lime v1.&lt;/p&gt;

&lt;p&gt;At first, I considered supporting both OAuth login and email/password sign-up. However, building email sign-up properly would bring in many additional features, such as password hashing, email verification, and password recovery.&lt;/p&gt;

&lt;p&gt;At this stage, I wanted to move quickly and focus on the core product. So for v1, I decided to support &lt;strong&gt;only Google and Discord OAuth&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In Lime v1, users do not sign up with an email and password.&lt;br&gt;&lt;br&gt;
They log in with a Google or Discord account, and the backend automatically creates Lime's &lt;code&gt;User&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After a successful login, the backend issues a &lt;code&gt;JWT Access Token&lt;/code&gt; and a &lt;code&gt;Refresh Token&lt;/code&gt; for our service.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Google OAuth login&lt;/li&gt;
&lt;li&gt;Discord OAuth login&lt;/li&gt;
&lt;li&gt;OAuth callback handling&lt;/li&gt;
&lt;li&gt;Automatic Lime &lt;code&gt;User&lt;/code&gt; creation on first login&lt;/li&gt;
&lt;li&gt;Linking OAuth accounts to existing users&lt;/li&gt;
&lt;li&gt;JWT Access Token issuance&lt;/li&gt;
&lt;li&gt;Refresh Token issuance and storage&lt;/li&gt;
&lt;li&gt;Refresh Token rotation&lt;/li&gt;
&lt;li&gt;Logout&lt;/li&gt;
&lt;li&gt;Handling OAuth failure and cancellation cases&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Overall Flow
&lt;/h2&gt;

&lt;p&gt;At first, I thought OAuth was simply about adding a "social login" button.&lt;br&gt;&lt;br&gt;
But the actual flow was longer than I expected.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Frontend
  -&amp;gt; Backend: /auth/google/start
  -&amp;gt; Google OAuth Page
  -&amp;gt; Backend: /auth/google/callback?code=...&amp;amp;state=...
  -&amp;gt; Google UserInfo API
  -&amp;gt; Create or find Lime User
  -&amp;gt; Issue JWT Access Token + Refresh Token
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I designed the APIs like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET  /auth/{provider}/start
GET  /auth/{provider}/callback
POST /auth/refresh
POST /auth/signout
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Currently, there are two supported providers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;google
discord
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Splitting It with VSA
&lt;/h2&gt;

&lt;p&gt;This project is built with Vertical Slice Architecture, not around MVC Controllers.&lt;/p&gt;

&lt;p&gt;So I did not put all authentication logic into one large controller. Instead, I split it by feature flow.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Features/Auth
  StartOAuthLogin
  HandleOAuthCallback
  RefreshSession
  SignOut
  OAuth
  Users
  Sessions
  Cookies
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first, having more files made it look more complicated.&lt;/p&gt;

&lt;p&gt;But OAuth mixes several responsibilities.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Redirecting to the provider&lt;/li&gt;
&lt;li&gt;Handling the callback&lt;/li&gt;
&lt;li&gt;Finding or creating a user&lt;/li&gt;
&lt;li&gt;Issuing tokens&lt;/li&gt;
&lt;li&gt;Writing cookies&lt;/li&gt;
&lt;li&gt;Handling failure cases&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Putting all of this into one file would be faster at first, but it would probably become harder to read later.&lt;br&gt;&lt;br&gt;
So this time, I chose to split the code by flow.&lt;/p&gt;


&lt;h2&gt;
  
  
  Provider Abstraction
&lt;/h2&gt;

&lt;p&gt;Google and Discord have similar OAuth flows, but they use different URLs and return different userinfo response formats.&lt;/p&gt;

&lt;p&gt;So I created a common interface.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;internal&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IOAuthProvider&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;BuildAuthorizeUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;redirectUri&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;OAuthUserInfo&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;ExchangeAndFetchAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;redirectUri&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each provider has its own implementation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GoogleOAuthProvider
DiscordOAuthProvider
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The callback endpoint finds and uses the correct provider based on the provider name.&lt;/p&gt;

&lt;p&gt;If I add Apple login later, I can extend this by adding an &lt;code&gt;AppleOAuthProvider&lt;/code&gt; and registering it in DI.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Most Confusing Part: Cookies and State
&lt;/h2&gt;

&lt;p&gt;The most confusing part of this work was cookies.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Cookies are used by the browser, so why am I creating cookies in backend OAuth code?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At first, I could not fully understand this.&lt;/p&gt;

&lt;p&gt;But OAuth is a flow that goes through browser redirects.&lt;br&gt;&lt;br&gt;
Because of that, the backend needs a way to temporarily remember values between requests.&lt;/p&gt;

&lt;p&gt;A typical example is &lt;code&gt;state&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Where &lt;code&gt;state&lt;/code&gt; Is Stored
&lt;/h3&gt;

&lt;p&gt;When OAuth starts, the backend creates a random &lt;code&gt;state&lt;/code&gt; value.&lt;br&gt;&lt;br&gt;
Then it stores this value in two places.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. The query string of the provider authorize URL
2. A browser cookie
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the provider redirects back to the callback endpoint, it includes the &lt;code&gt;state&lt;/code&gt; value in the query string.&lt;br&gt;&lt;br&gt;
The backend compares the &lt;code&gt;state&lt;/code&gt; from the callback with the &lt;code&gt;state&lt;/code&gt; stored in the cookie.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Same      -&amp;gt; Valid OAuth flow
Different -&amp;gt; Reject
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is used to prevent CSRF attacks.&lt;/p&gt;

&lt;p&gt;In this implementation, I created temporary cookies for the OAuth flow.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lime_oauth_state   -&amp;gt; State value for CSRF protection
lime_oauth_return  -&amp;gt; Path to return to after successful login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since both values do not need to live for a long time, I made them short-lived cookies and deleted them after the callback was handled.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;code&gt;returnTo&lt;/code&gt; Should Not Be Trusted As-Is
&lt;/h2&gt;

&lt;p&gt;To send users back to the original page after a successful login, I accepted a &lt;code&gt;returnTo&lt;/code&gt; value.&lt;/p&gt;

&lt;p&gt;However, this value should not be trusted as-is.&lt;/p&gt;

&lt;p&gt;For example, redirecting directly to values like these can be dangerous.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://evil.com
//evil.com
\evil
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So I did not allow external URLs and only allowed internal paths.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/dashboard
/profile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is a small detail, but for a login feature, these details matter.&lt;/p&gt;




&lt;h2&gt;
  
  
  Linking Users and OAuth Accounts
&lt;/h2&gt;

&lt;p&gt;Lime has its own &lt;code&gt;User&lt;/code&gt;, and OAuth provider account information is stored in a separate table.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;users
user_oauth_accounts
refresh_tokens
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In OAuth login, the most reliable identifier is not the email address.&lt;br&gt;&lt;br&gt;
It is this combination.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;provider + providerUserId
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An email address can change, and whether it is verified depends on the provider.&lt;/p&gt;

&lt;p&gt;So during login, I first look for an existing OAuth account using &lt;code&gt;provider + providerUserId&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OAuth account already linked
  -&amp;gt; Log in as that User

OAuth account not linked
  -&amp;gt; If the email is verified, link it to an existing User
  -&amp;gt; Otherwise, create a new User
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first, it is easy to think, "If the email is the same, isn't it the same user?"&lt;br&gt;&lt;br&gt;
But in authentication, whether the email is verified matters.&lt;/p&gt;


&lt;h2&gt;
  
  
  JWT and Refresh Tokens
&lt;/h2&gt;

&lt;p&gt;I did not use the OAuth provider's access token directly for Lime API authentication.&lt;/p&gt;

&lt;p&gt;Google or Discord access tokens are meant for calling the provider's APIs.&lt;br&gt;&lt;br&gt;
The token used to call Lime APIs should be issued by our own service.&lt;/p&gt;

&lt;p&gt;After a successful login, I issue two tokens.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Token&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Access Token&lt;/td&gt;
&lt;td&gt;Authenticate Lime API requests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Refresh Token&lt;/td&gt;
&lt;td&gt;Reissue Access Tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The Access Token is a JWT.&lt;br&gt;&lt;br&gt;
It contains minimal claims such as the user ID, email, and name, and it has a short lifetime.&lt;/p&gt;

&lt;p&gt;The Refresh Token is a random string and is stored in the database.&lt;br&gt;&lt;br&gt;
However, I do not store the raw token. I only store its SHA-256 hash.&lt;/p&gt;

&lt;p&gt;When a Refresh Token is used, the existing token is revoked and a new one is issued.&lt;br&gt;&lt;br&gt;
This is called refresh token rotation.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Keep the Access Token short-lived and the Refresh Token longer-lived.&lt;br&gt;&lt;br&gt;
But make sure the Refresh Token can be controlled through the database.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That was the basic direction for this implementation.&lt;/p&gt;


&lt;h2&gt;
  
  
  Storing Tokens in Cookies
&lt;/h2&gt;

&lt;p&gt;In this implementation, both the Access Token and Refresh Token are stored in HttpOnly cookies.&lt;/p&gt;

&lt;p&gt;Storing tokens in localStorage is also possible, but considering XSS, HttpOnly cookies can be a safer choice.&lt;/p&gt;

&lt;p&gt;HttpOnly cookies cannot be read by JavaScript.&lt;/p&gt;

&lt;p&gt;However, when using cookies, CSRF also needs to be considered.&lt;br&gt;&lt;br&gt;
So I explicitly configured options such as &lt;code&gt;SameSite&lt;/code&gt;, &lt;code&gt;Secure&lt;/code&gt;, and &lt;code&gt;Path&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Also, ASP.NET Core's JWT Bearer authentication looks for the token in the Authorization header by default.&lt;/p&gt;

&lt;p&gt;Since I store the access token in a cookie, I configured the authentication middleware to read the token from the cookie.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If this part is missed, tokens may be issued successfully, but APIs that require authentication will still treat the request as unauthenticated.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  Response Format
&lt;/h2&gt;

&lt;p&gt;I also defined a response format to align with the frontend.&lt;/p&gt;

&lt;p&gt;Instead of returning a human-readable &lt;code&gt;message&lt;/code&gt; in failure responses, I decided to return a stable &lt;code&gt;code&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"INVALID_REFRESH_TOKEN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The frontend can use this &lt;code&gt;code&lt;/code&gt; to decide what message to show to the user.&lt;/p&gt;

&lt;p&gt;This keeps localization and UI wording changes separate from the backend.&lt;/p&gt;

&lt;p&gt;I also handled the OAuth cancellation case separately.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OAUTH_CANCELLED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a user cancels on the provider's authentication page, it is closer to a normal failure flow than a system error.&lt;br&gt;&lt;br&gt;
So I separated it from ordinary missing-parameter cases.&lt;/p&gt;


&lt;h2&gt;
  
  
  What I Learned About Configuration
&lt;/h2&gt;

&lt;p&gt;I also ran into an issue while binding configuration with &lt;code&gt;IOptions&amp;lt;AuthOptions&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The path the code expected was different from the actual structure in &lt;code&gt;appsettings.json&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Expected by code: Auth:Jwt:SigningKey
Actual setting:   Jwt:SigningKey
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even when a value is empty, it is not always obvious at first.&lt;br&gt;&lt;br&gt;
This is especially important for &lt;code&gt;Jwt:SigningKey&lt;/code&gt;, because if it is empty, the backend cannot create or validate JWTs.&lt;/p&gt;

&lt;p&gt;One thing I learned from this is that configuration values are just as important as code.&lt;/p&gt;

&lt;p&gt;OAuth Client ID/Secret, JWT SigningKey, and database connection settings live outside the code, but they are core parts of making the feature actually work.&lt;/p&gt;




&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;With this work, the authentication foundation for Lime v1 is now in place.&lt;/p&gt;

&lt;p&gt;What I built was not just a "Google login button."&lt;/p&gt;

&lt;p&gt;In practice, all of these pieces had to work together.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OAuth redirect flow&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;state&lt;/code&gt; for CSRF protection&lt;/li&gt;
&lt;li&gt;Temporary OAuth cookies&lt;/li&gt;
&lt;li&gt;Safe &lt;code&gt;returnTo&lt;/code&gt; handling&lt;/li&gt;
&lt;li&gt;Fetching user information from the provider&lt;/li&gt;
&lt;li&gt;Automatic Lime &lt;code&gt;User&lt;/code&gt; creation&lt;/li&gt;
&lt;li&gt;Linking OAuth accounts&lt;/li&gt;
&lt;li&gt;JWT Access Token issuance&lt;/li&gt;
&lt;li&gt;Refresh Token storage and rotation&lt;/li&gt;
&lt;li&gt;Logout&lt;/li&gt;
&lt;li&gt;Response codes aligned with the frontend&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;OAuth requires more surrounding design than I expected.&lt;/p&gt;

&lt;p&gt;The successful login path may look simple, but for a real service, user mapping, token storage, cookie security, and failure cases all need to be considered together.&lt;/p&gt;

&lt;p&gt;Next, I plan to apply this authentication middleware to protected APIs and align the frontend behavior around these response codes.&lt;/p&gt;

</description>
      <category>oauth</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>[C++ 2D Arena Shooter Server #1] Setting Up the TCP Server</title>
      <dc:creator>MinBapE</dc:creator>
      <pubDate>Wed, 06 May 2026 15:14:28 +0000</pubDate>
      <link>https://dev.to/min38/dd-building-tunehouse-1-aspnet-core-project-setup-7ed</link>
      <guid>https://dev.to/min38/dd-building-tunehouse-1-aspnet-core-project-setup-7ed</guid>
      <description>&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;I started this project because I wanted to build a C++ game server as part of my portfolio. The goal is not just to make something that runs, but also to document the design decisions and the debugging process along the way. Ideally, I want to be able to answer questions like “Why did you implement it this way?” in an interview.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I did today
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Set up the directory structure
&lt;/h3&gt;

&lt;p&gt;First, I separated &lt;code&gt;include&lt;/code&gt; and &lt;code&gt;src&lt;/code&gt;, then divided the code into &lt;code&gt;network&lt;/code&gt; and &lt;code&gt;server&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cpp-2d-arena-shooter-server/
├── include/
│   ├── common/
│   │   └── pch.h
│   ├── network/
│   │   ├── tcp_listener.h
│   │   └── session.h
│   └── server/
│       └── game_server.h
├── src/
│   ├── network/
│   │   ├── tcp_listener.cpp
│   │   └── session.cpp
│   ├── server/
│   │   └── game_server.cpp
│   └── main.cpp
└── CMakeLists.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Decided to start with thread-per-client
&lt;/h3&gt;

&lt;p&gt;I do want to try &lt;code&gt;epoll&lt;/code&gt; later, but for now I decided that it makes more sense to build the basic structure first. Since this is an arena shooter and each room will have at most around 16 players, the number of threads should not explode.&lt;/p&gt;

&lt;p&gt;Also, replacing the thread-per-client model with &lt;code&gt;epoll&lt;/code&gt; later can become a meaningful part of the commit history. From a portfolio perspective, showing that transition may actually be a good thing.&lt;/p&gt;
&lt;h3&gt;
  
  
  Passing the entire Session to a thread after accept
&lt;/h3&gt;

&lt;p&gt;Whenever a new connection is accepted, I create a &lt;code&gt;Session&lt;/code&gt; and move a &lt;code&gt;unique_ptr&lt;/code&gt; into the thread.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_unique&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Session&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clientSocket&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kr"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Session&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="n"&gt;detach&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If I pass a raw pointer, it becomes unclear who should delete it. If I create it on the stack, it may be destroyed before the thread starts using it. So I chose &lt;code&gt;unique_ptr&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;By moving it into the thread, the ownership is transferred to the thread. This makes it clear in the code that “this Session is now owned by this thread.”&lt;/p&gt;

&lt;p&gt;With this approach, when the thread finishes, the &lt;code&gt;Session&lt;/code&gt; destructor is called automatically. Since the destructor calls &lt;code&gt;disconnect()&lt;/code&gt;, I do not need to manage the file descriptor separately.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;Session&lt;/span&gt;&lt;span class="o"&gt;::~&lt;/span&gt;&lt;span class="n"&gt;Session&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;disconnect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// The destructor automatically closes the fd&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Debugging notes
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Called SO_REUSEADDR before socket()
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;_serverSocket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;setsockopt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_serverSocket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...);&lt;/span&gt; &lt;span class="c1"&gt;// fd is still -1 here&lt;/span&gt;
&lt;span class="n"&gt;_serverSocket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;(...);&lt;/span&gt;    &lt;span class="c1"&gt;// the socket is created after that&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Every time I restarted the server, I got an “Address already in use” error. After debugging, I found that I was calling &lt;code&gt;setsockopt&lt;/code&gt; before calling &lt;code&gt;socket()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In other words, I was trying to set an option on an fd with the value &lt;code&gt;-1&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Double close
&lt;/h3&gt;

&lt;p&gt;When &lt;code&gt;bind&lt;/code&gt; or &lt;code&gt;listen&lt;/code&gt; failed, I called &lt;code&gt;close&lt;/code&gt; and returned immediately. But I forgot to reset &lt;code&gt;_serverSocket&lt;/code&gt; to &lt;code&gt;-1&lt;/code&gt;, so the destructor tried to close an already closed fd again.&lt;/p&gt;

&lt;p&gt;If the OS had already reused that fd, this could accidentally close an unrelated fd.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_serverSocket&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;_serverSocket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// This was missing&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Uninitialized sockaddr_in
&lt;/h3&gt;

&lt;p&gt;I had declared &lt;code&gt;sockaddr_in serverAddr;&lt;/code&gt; without initialization, so some padding bytes contained garbage values. This was fixed by initializing it with &lt;code&gt;{}&lt;/code&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  Next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Design the packet structure&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;Advice and feedback are welcome.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/min-38" rel="noopener noreferrer"&gt;
        min-38
      &lt;/a&gt; / &lt;a href="https://github.com/min-38/cpp-2d-arena-shooter-server" rel="noopener noreferrer"&gt;
        cpp-2d-arena-shooter-server
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;cpp-2d-arena-shooter-server&lt;/h1&gt;

&lt;/div&gt;

&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/min-38/cpp-2d-arena-shooter-server" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


</description>
      <category>cpp</category>
      <category>network</category>
      <category>server</category>
    </item>
    <item>
      <title>Docker and Kubernetes</title>
      <dc:creator>MinBapE</dc:creator>
      <pubDate>Mon, 05 Jan 2026 13:35:30 +0000</pubDate>
      <link>https://dev.to/min38/docker-and-kubernetes-3mbm</link>
      <guid>https://dev.to/min38/docker-and-kubernetes-3mbm</guid>
      <description>&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;Last year, I participated in an external activity with the theme "Development of Container Monitoring Visualization Dashboard in Docker and Kubernetes Environment." To preserve the fundamental concepts of Docker and Kubernetes that I learned at that time, I'm writing this article in the way I understood them.&lt;/p&gt;




&lt;h3&gt;
  
  
  What is Docker?
&lt;/h3&gt;

&lt;p&gt;When you run nginx on a server or execute a .sh script, from the operating system's perspective, it's just running a process. Docker is similar - running a container ultimately means executing some process. The difference isn't in how the process runs, but in the environment the process perceives. &lt;strong&gt;In Docker, processes operate within an isolated environment (filesystem, network, process list, etc.).&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1) Why was it adopted?&lt;/strong&gt;&lt;br&gt;
The biggest advantage of Docker is that it reduces problems arising from different execution environments across servers. Even programs that build well locally often fail to run when moved to a server due to library dependency conflicts or version differences. With Docker, you can bundle applications with their required dependencies for deployment, significantly reducing trial and error from these environmental differences.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2) Definition&lt;/strong&gt;&lt;br&gt;
To properly explain Docker, it's a platform that allows you to package and run applications in units called Containers. Containers share the operating system kernel while separating the filesystem, network, and process space to run processes in an isolated environment.&lt;br&gt;
Below are key terms for understanding Docker:&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Image&lt;/strong&gt;: An execution template containing files/dependencies/configurations needed for execution = Package&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Container&lt;/strong&gt;: An actually running instance based on an image = Process&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Registry&lt;/strong&gt;: A repository for storing or distributing images (e.g., Docker Hub, Amazon ECR, Google Container Registry, etc.)&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;In summary, Docker is a tool that creates identical execution environments as images, allowing you to run containers the same way anywhere.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3) Differences from Virtual Machines&lt;/strong&gt;&lt;br&gt;
Both VMs and Docker provide isolated execution environments, but they differ in their isolation method and weight.&lt;br&gt;
Unlike Containers, VMs virtualize the entire operating system including the guest OS on top of a hypervisor. It's a structure that puts an entire OS on top of the application. This difference typically results in the following characteristics:&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Resource Usage&lt;/strong&gt;: VMs are relatively heavy as they include the OS, while Containers are lightweight.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Startup Speed&lt;/strong&gt;: VMs require a boot process, but Containers execute closer to process execution, running much faster.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Isolation Level&lt;/strong&gt;: VMs have stronger isolation as they're separated at the OS level, while Containers have thinner isolation boundaries compared to VMs as they share the kernel.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;In summary, VMs are like virtual computers including the OS, while Containers are closer to isolated process execution that shares the kernel.&lt;br&gt;
When you need a different OS environment, VMs are advantageous, and when you want to deploy programs quickly and consistently on the same kernel basis, Containers are beneficial.&lt;/p&gt;




&lt;h3&gt;
  
  
  What is Kubernetes?
&lt;/h3&gt;

&lt;p&gt;If Docker provides the unit for creating and running Containers, Kubernetes (abbreviated as k8s) is a system for managing those Containers from an operational perspective. Its purpose is to automate problems that arise when services grow and Containers multiply (deployment, failures, scaling, networking, etc.).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1) The Inconvenience of Docker Operations&lt;/strong&gt;&lt;br&gt;
With Docker alone, running and stopping Containers isn't difficult. However, as services grow and the number of Containers increases, operational aspects become cumbersome. For example, it's not easy to consistently manage tasks like automatically recovering when a Container terminates abnormally (self-healing), scaling to multiple instances in response to traffic increases, and replacing without downtime during deployment using only Docker commands. Eventually, these operational tasks are managed by scripts or people directly, and as scale grows, management complexity rapidly increases.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2) Kubernetes Core Concepts&lt;/strong&gt;&lt;br&gt;
Kubernetes operates around several core objects:&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pod&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;The minimum unit for running Containers in Kubernetes&lt;/li&gt;
&lt;li&gt;Usually manages one Container or bundles several closely related Containers together.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deployment&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;An object that maintains Pods at the desired count and manages version updates (rolling update method that replaces with new versions without shutting down the service)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Service&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;An object that provides a fixed access point because Pods can have their IPs changed when replaced or restarted&lt;/li&gt;
&lt;li&gt;Also serves as internal load balancing.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Node&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;The physical server or virtual machine where Pods actually run&lt;/li&gt;
&lt;li&gt;Multiple nodes together form a Cluster (a unit that bundles and operates multiple servers as one).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Control Plane&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;The management area that stores the Cluster's state and decides which Pods to place on which Nodes&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;The core of Kubernetes isn't directly manipulating Containers, but managing to maintain the desired state once you declare it. If you define goals like 'n Pods should be running' or 'this Service should always be accessible', Kubernetes adjusts accordingly.&lt;/p&gt;




&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Docker&lt;/strong&gt; is a tool that packages applications and execution environments as Images and allows you to run Containers based on them in a consistent manner.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kubernetes&lt;/strong&gt; is a Container orchestration system designed to automate operational issues like deployment/recovery/scaling/networking when multiple Containers come together to form a service.&lt;/p&gt;

&lt;p&gt;Using Docker + Kubernetes together, you can create consistent execution environments with Docker and operate those environments stably and efficiently with Kubernetes. Developers only need to prepare code and images, and Kubernetes automates the rest of the operational burden. This combination has become the standard for modern cloud-native application development and operations.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>kubernetes</category>
      <category>devops</category>
    </item>
    <item>
      <title>const and constexpr</title>
      <dc:creator>MinBapE</dc:creator>
      <pubDate>Mon, 24 Nov 2025 15:08:57 +0000</pubDate>
      <link>https://dev.to/min38/const-and-constexpr-3fen</link>
      <guid>https://dev.to/min38/const-and-constexpr-3fen</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;While working on a personal project, I learned about &lt;code&gt;constexpr&lt;/code&gt;. I understood the difference between &lt;code&gt;const&lt;/code&gt; and &lt;code&gt;constexpr&lt;/code&gt;. However, I wondered why &lt;code&gt;constexpr&lt;/code&gt; is necessary when &lt;code&gt;const&lt;/code&gt; seems sufficient. I want to share what I found in this article.&lt;/p&gt;




&lt;h2&gt;
  
  
  const
&lt;/h2&gt;

&lt;p&gt;A keyword that promises the compiler that a value cannot be changed.&lt;br&gt;
Once initialized, the value cannot be modified.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;MAX_USERS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;MAX_USERS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Compilation error!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Characteristics&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The initialization value can be known at compile time or at runtime.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cin&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Valid&lt;/span&gt;
&lt;span class="c1"&gt;// Constant B is determined at runtime, but cannot be changed afterwards.&lt;/span&gt;
&lt;span class="c1"&gt;// The value doesn't need to be known at compile time, but once set, it cannot be changed.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;It becomes more powerful when used with references and pointers.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;ptr1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;        &lt;span class="c1"&gt;// Cannot change the pointed value&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;ptr2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;        &lt;span class="c1"&gt;// Cannot change the pointer itself&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;ptr3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Cannot change both&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;When &lt;code&gt;const&lt;/code&gt; is added to a class member function, the function promises not to change the object's state.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;private:&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nl"&gt;public:&lt;/span&gt;
    &lt;span class="c1"&gt;// Does not modify member variables&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="c1"&gt;// age = 30;  // Error occurs&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setAge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;newAge&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newAge&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Valid&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Limitations&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;If a member variable is declared as &lt;code&gt;mutable&lt;/code&gt;, it can be modified even in &lt;code&gt;const&lt;/code&gt; member functions.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;const&lt;/code&gt; can be forcibly removed using &lt;code&gt;const_cast&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  constexpr
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;constexpr&lt;/code&gt; is short for "constant expression".&lt;br&gt;
Unlike &lt;code&gt;const&lt;/code&gt;, it is a keyword that guarantees the compiler that the value is determined at compile time.&lt;br&gt;
It was first introduced in C++11, and most restrictions have been lifted through version updates.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;constexpr&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;        &lt;span class="c1"&gt;// Initialized to 1 at compile time&lt;/span&gt;
&lt;span class="k"&gt;constexpr&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Calculated to 4 at compile time&lt;/span&gt;
&lt;span class="k"&gt;constexpr&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;C&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Calculated to 16 at compile time&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The critical difference from &lt;code&gt;const&lt;/code&gt; is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cin&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;      &lt;span class="c1"&gt;// Valid -&amp;gt; because it's determined at runtime&lt;/span&gt;
&lt;span class="k"&gt;constexpr&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;// Error occurs&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Reasons to Use&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Performance is improved as complex calculations can be completed at compile time through compile-time computation.&lt;/li&gt;
&lt;li&gt;In C++, array sizes and template arguments must be compile-time constants.&lt;/li&gt;
&lt;li&gt;Incorrect calculations can be caught before execution.&lt;/li&gt;
&lt;li&gt;The compiler can perform more verification.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 1. Performance improvement&lt;/span&gt;
&lt;span class="k"&gt;constexpr&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;constexpr&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Zero calculation cost at runtime&lt;/span&gt;

&lt;span class="c1"&gt;// 2. Array size&lt;/span&gt;
&lt;span class="k"&gt;constexpr&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;SIZE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;  &lt;span class="c1"&gt;// OK&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getSize&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;  &lt;span class="c1"&gt;// Error in most cases&lt;/span&gt;

&lt;span class="c1"&gt;// 3. Compile-time verification&lt;/span&gt;
&lt;span class="k"&gt;constexpr&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;divide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="s"&gt;"error"&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;constexpr&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;divide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Compilation error occurs&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  When to Use const vs constexpr?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;When to use const&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use when the value can be known at runtime, such as user input, configuration values read from files.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;const&lt;/code&gt; to express the intention not to modify arguments passed to a function.&lt;/li&gt;
&lt;li&gt;Member functions that do not change the object's state should be declared as &lt;code&gt;const&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;When to use constexpr&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;C++ array sizes must be compile-time constants.&lt;/li&gt;
&lt;li&gt;Template parameters must be determined at compile time.&lt;/li&gt;
&lt;li&gt;Use when you want to pre-calculate complex computations.&lt;/li&gt;
&lt;li&gt;Use in &lt;code&gt;switch&lt;/code&gt; statement &lt;code&gt;case&lt;/code&gt; labels, &lt;code&gt;static_assert&lt;/code&gt;, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Situation&lt;/th&gt;
&lt;th&gt;const&lt;/th&gt;
&lt;th&gt;constexpr&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;User input value&lt;/td&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Array size&lt;/td&gt;
&lt;td&gt;△&lt;/td&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Template argument&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Function parameter&lt;/td&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compile-time calculation&lt;/td&gt;
&lt;td&gt;△&lt;/td&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;const&lt;/code&gt; is a promise of immutability, and &lt;code&gt;constexpr&lt;/code&gt; is a guarantee of compile-time calculation.&lt;br&gt;
&lt;code&gt;const&lt;/code&gt; can accept runtime values, but &lt;code&gt;constexpr&lt;/code&gt; is determined only at compile time.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>cpp</category>
      <category>learning</category>
    </item>
    <item>
      <title>TCP Variable-Length Packet Handling</title>
      <dc:creator>MinBapE</dc:creator>
      <pubDate>Sat, 22 Nov 2025 13:41:43 +0000</pubDate>
      <link>https://dev.to/min38/tcp-variable-length-packet-handling-pc</link>
      <guid>https://dev.to/min38/tcp-variable-length-packet-handling-pc</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;While developing a Socket Chatting program, I encountered a question: how should I handle messages that exceed the predefined buffer size?&lt;br&gt;
This article documents my solution to this problem.&lt;/p&gt;


&lt;h2&gt;
  
  
  Packet Boundary Problem
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Client&lt;/span&gt;
&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;packet1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Send 10 bytes&lt;/span&gt;
&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;packet2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Send 20 bytes&lt;/span&gt;

&lt;span class="c1"&gt;// Server&lt;/span&gt;
&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;recv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;What will the value of &lt;code&gt;bytes&lt;/code&gt; be? 10? 20?&lt;br&gt;
The answer is: &lt;strong&gt;"We can't know."&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The size of data received from the client is unpredictable.&lt;br&gt;
&lt;code&gt;recv()&lt;/code&gt; can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Receive all 30 bytes at once&lt;/li&gt;
&lt;li&gt;Receive 10 bytes and 20 bytes separately&lt;/li&gt;
&lt;li&gt;Split into 15 bytes twice&lt;/li&gt;
&lt;li&gt;Even split into 7 bytes, 13 bytes, and 10 bytes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is called the &lt;strong&gt;Packet Boundary Problem&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  TCP is a Stream Protocol
&lt;/h2&gt;

&lt;p&gt;Unlike UDP, TCP transmits data in byte units rather than message units.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Hello"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"World"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a client sends a 5-byte string twice as shown above, we might think the server will receive it twice as well. However, TCP can &lt;strong&gt;merge them into a single stream&lt;/strong&gt;, resulting in receiving a 10-byte string all at once.&lt;/p&gt;

&lt;p&gt;This happens due to the following reasons:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Nagle's Algorithm
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A mechanism to improve TCP/IP network efficiency by reducing the number of packets to be transmitted.&lt;/li&gt;
&lt;li&gt;Small data is buffered and sent together to prevent inefficiency where headers (40 bytes) are larger than data (1 byte).&lt;/li&gt;
&lt;li&gt;Operating systems use this because &lt;strong&gt;Congestion Control&lt;/strong&gt; across the entire network takes priority over individual program speed.&lt;/li&gt;
&lt;li&gt;While you can reduce latency by disabling Nagle with &lt;code&gt;TCP_NODELAY&lt;/code&gt;, this doesn't change TCP's fundamental stream-based nature, so packet boundary handling on the receiving side remains essential.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;  &lt;span class="n"&gt;setsockopt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IPPROTO_TCP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TCP_NODELAY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Network Layer
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MTU (Maximum Transmission Unit)&lt;/strong&gt;: Network transmission size is typically limited to &lt;strong&gt;1500 bytes&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Large data is split into multiple IP packets for transmission. Depending on network conditions, packets may not arrive in order or may be lost, but the TCP protocol reassembles them to guarantee order.

&lt;ul&gt;
&lt;li&gt;However, during this reassembly process, data may accumulate or be split in the buffer, making data boundaries ambiguous at recv time.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. &lt;code&gt;recv()&lt;/code&gt; Call Timing
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;recv()&lt;/code&gt; returns as much data as is currently available, from a minimum of 1 byte to the maximum requested size.&lt;/li&gt;
&lt;li&gt;The amount of data received varies depending on &lt;strong&gt;when&lt;/strong&gt; &lt;code&gt;recv()&lt;/code&gt; is called.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Header + Payload Structure
&lt;/h3&gt;

&lt;p&gt;I solved this by including size information in the header.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#pragma pack(push, 1)  // Remove structure padding
&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;PacketHeader&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;PacketType&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// 2 bytes - Packet type&lt;/span&gt;
    &lt;span class="kt"&gt;uint16_t&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;     &lt;span class="c1"&gt;// 2 bytes - Payload size&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;Packet&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;PacketHeader&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;                 &lt;span class="c1"&gt;// 4 bytes (fixed)&lt;/span&gt;
    &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;MAX_PAYLOAD_SIZE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;      &lt;span class="c1"&gt;// Variable (actual data)&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="cp"&gt;#pragma pack(pop)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both server and client can first read the header to determine the payload size. The packet is wrapped with &lt;code&gt;#pragma pack(push, 1)&lt;/code&gt; to process it once the payload is completely accumulated to that size.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Sending&lt;/strong&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;send_packet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Packet&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Convert to network byte order&lt;/span&gt;
    &lt;span class="n"&gt;Packet&lt;/span&gt; &lt;span class="n"&gt;send_packet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;send_packet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;htons&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;send_packet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;htons&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="cm"&gt;/*
        htons() = Host TO Network Short (2-byte conversion)
        - Converts to network format regardless of current system
          -&amp;gt; Solves the problem of different byte ordering across CPUs
    */&lt;/span&gt;

    &lt;span class="c1"&gt;// Cast data for transmission&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;reinterpret_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;send_packet&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;total_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PacketHeader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;sent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Loop until all data is sent&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sent&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;total_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;ssize_t&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;sent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                        &lt;span class="n"&gt;total_size&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;sent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                        &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errno&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;EAGAIN&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;errno&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;EWOULDBLOCK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Temporary error, retry&lt;/span&gt;

            &lt;span class="n"&gt;perror&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"send failed"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Add sent size&lt;/span&gt;
        &lt;span class="n"&gt;sent&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;Receiving&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;We need to create an accumulation buffer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;ClientInfo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;recv_buffer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Accumulation buffer&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is necessary because when packets are split during transmission, they must be stored sequentially in this buffer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;receive_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ClientInfo&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;clients&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4096&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="kt"&gt;ssize_t&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;recv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Connection closed or error&lt;/span&gt;

    &lt;span class="c1"&gt;// Accumulate into existing buffer&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;recv_buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;recv_buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;temp&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;parse_packets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ClientInfo&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;clients&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="c1"&gt;// Continue processing while complete packets exist&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;recv_buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PacketHeader&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Read header first&lt;/span&gt;
        &lt;span class="n"&gt;PacketHeader&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
            &lt;span class="k"&gt;reinterpret_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;PacketHeader&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;recv_buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

        &lt;span class="kt"&gt;uint16_t&lt;/span&gt; &lt;span class="n"&gt;payload_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ntohs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;packet_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PacketHeader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;payload_size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Check if complete packet has arrived; if not, wait for next recv()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;recv_buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;packet_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Extract complete packet&lt;/span&gt;
        &lt;span class="n"&gt;Packet&lt;/span&gt; &lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;memcpy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;recv_buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;packet_size&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Endian conversion (network → host)&lt;/span&gt;
        &lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ntohs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;payload_size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Process packet&lt;/span&gt;
        &lt;span class="n"&gt;handle_packet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Remove processed packet&lt;/span&gt;
        &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;recv_buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;erase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;recv_buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;recv_buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;packet_size&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Source Code
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/min-38/cpp-socket-chat/tree/main/server/src/network" rel="noopener noreferrer"&gt;Socket Chatting Program&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Tags
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;#cpp&lt;/code&gt; &lt;code&gt;#networking&lt;/code&gt; &lt;code&gt;#tcp&lt;/code&gt; &lt;code&gt;#sockets&lt;/code&gt; &lt;code&gt;#systemsprogramming&lt;/code&gt;&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>networking</category>
    </item>
    <item>
      <title>Mutex and Lock Guard in C++</title>
      <dc:creator>MinBapE</dc:creator>
      <pubDate>Thu, 20 Nov 2025 01:53:59 +0000</pubDate>
      <link>https://dev.to/min38/mutex-and-lock-guard-in-c-17i9</link>
      <guid>https://dev.to/min38/mutex-and-lock-guard-in-c-17i9</guid>
      <description>&lt;h3&gt;
  
  
  &lt;strong&gt;Mutex (Mutual Exclusion)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Mutex is a synchronization object that controls access to shared resources in a multithreaded environment.&lt;br&gt;
It is used to prevent Race Conditions that can occur when multiple threads access the same resource simultaneously.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code Example&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;mutex&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;thread&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt; &lt;span class="n"&gt;mtx&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;100000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;mtx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Critical Section&lt;/span&gt;
        &lt;span class="n"&gt;mtx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unlock&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kr"&gt;thread&lt;/span&gt; &lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kr"&gt;thread&lt;/span&gt; &lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"Counter: "&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key Methods&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;lock()&lt;/code&gt; 

&lt;ul&gt;
&lt;li&gt;Locks the mutex in a blocking manner.&lt;/li&gt;
&lt;li&gt;If another thread has already acquired the lock, it waits until it is released.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;unlock()&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;Releases the acquired lock.&lt;/li&gt;
&lt;li&gt;Calling this from a thread that hasn't acquired the lock results in undefined behavior.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;try_lock()&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;Attempts to lock in a non-blocking manner, returning true on success and false immediately on failure.&lt;/li&gt;
&lt;li&gt;Allows performing other tasks without waiting to acquire the lock.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;As shown in the example code above, the code region between &lt;code&gt;lock()&lt;/code&gt; and &lt;code&gt;unlock()&lt;/code&gt; (Critical Section) can only be executed by one thread at a time.&lt;br&gt;
However, if an exception occurs or an early return happens before calling &lt;code&gt;unlock()&lt;/code&gt;, a deadlock will occur.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mutex for Special Situations&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;recursive_mutex&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;A mutex that allows the same thread to acquire the lock multiple times.&lt;/li&gt;
&lt;li&gt;Must call &lt;code&gt;unlock()&lt;/code&gt; as many times as the lock was acquired to fully release it.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;timed_mutex&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;A mutex that allows specifying a timeout.&lt;/li&gt;
&lt;li&gt;Provides &lt;code&gt;try_lock_for()&lt;/code&gt; and &lt;code&gt;try_lock_until()&lt;/code&gt; methods.
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;timed_mutex&lt;/span&gt; &lt;span class="n"&gt;tmtx&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tmtx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;try_lock_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;chrono&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Successfully acquired lock within 1 second&lt;/span&gt;
        &lt;span class="c1"&gt;// Critical Section&lt;/span&gt;
        &lt;span class="n"&gt;tmtx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unlock&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Timeout occurred&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;shared_mutex&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;Implements a Reader-Writer Lock.&lt;/li&gt;
&lt;li&gt;Supported from C++17.&lt;/li&gt;
&lt;li&gt;Multiple threads can perform read operations simultaneously, but write operations are performed exclusively.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Lock Guard&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Manually managing lock() and unlock() is dangerous. The solution to this problem is the RAII (Resource Acquisition Is Initialization) pattern. It acquires resources in the constructor and releases them in the destructor, utilizing C++'s stack unwinding mechanism to ensure resources are safely released even when exceptions occur.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;lock guard&lt;/code&gt; is one of the classes provided by the C++ standard library that helps reduce mistakes in mutex management.&lt;br&gt;
When using &lt;code&gt;lock guard&lt;/code&gt;, the mutex is automatically locked, and when the scope is exited, the lock_guard's destructor is called to automatically release the mutex.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;lock_guard&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;The most basic RAII-based mutex wrapper.&lt;/li&gt;
&lt;li&gt;Automatically calls lock() on construction and unlock() on destruction.&lt;/li&gt;
&lt;li&gt;The simplest with minimal overhead.&lt;/li&gt;
&lt;li&gt;Acquires the lock immediately upon creation.&lt;/li&gt;
&lt;li&gt;Cannot control when the lock is released.&lt;/li&gt;
&lt;li&gt;Cannot be copied or moved.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;mutex&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;thread&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt; &lt;span class="n"&gt;mtx&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;100000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;lock_guard&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mtx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Lock on creation&lt;/span&gt;
        &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="c1"&gt;// Automatically unlocks when leaving scope&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;safe_function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;lock_guard&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mtx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;some_condition&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;process_data&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;// Unlock guaranteed even if exception occurs&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;unique_lock&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Provides various features including deferred locking, condition variable integration, and ownership transfer.&lt;/li&gt;
&lt;li&gt;Can manually call &lt;code&gt;lock()&lt;/code&gt;/&lt;code&gt;unlock()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Essential for use with condition variables like &lt;code&gt;condition_variable&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Movable but not copyable.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt; &lt;span class="n"&gt;mtx&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;flexible_function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;unique_lock&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mtx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;defer_lock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Deferred locking&lt;/span&gt;
    &lt;span class="n"&gt;prepare_data&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;// Manually lock at the needed point&lt;/span&gt;
    &lt;span class="n"&gt;modify_shared_data&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unlock&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;// Can manually release&lt;/span&gt;
    &lt;span class="n"&gt;cleanup&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Other tasks without lock&lt;/span&gt;

    &lt;span class="c1"&gt;// Automatically unlocks if still locked when scope ends&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Use with condition variables (most common case)&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;condition_variable&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt; &lt;span class="n"&gt;mtx&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;condition_variable&lt;/span&gt; &lt;span class="n"&gt;cv&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;ready&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;wait_for_signal&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;unique_lock&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mtx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;cv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ready&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;  &lt;span class="c1"&gt;// unique_lock required&lt;/span&gt;
    &lt;span class="n"&gt;process_data&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;scoped_lock&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Supported from C++17.&lt;/li&gt;
&lt;li&gt;Used to prevent deadlocks when locking multiple mutexes simultaneously.&lt;/li&gt;
&lt;li&gt;Uses the &lt;code&gt;std::lock()&lt;/code&gt; algorithm internally.&lt;/li&gt;
&lt;li&gt;Identical to &lt;code&gt;lock_guard&lt;/code&gt; for a single mutex.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt; &lt;span class="n"&gt;mtx1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mtx2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Code that can cause deadlock&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;thread1&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;lock_guard&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;lock1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mtx1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;lock_guard&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;lock2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mtx2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Order issue&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;thread2&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;lock_guard&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;lock2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mtx2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;lock_guard&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;lock1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mtx1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Opposite order!&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Prevent deadlock with scoped_lock&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;safe_thread1&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;scoped_lock&lt;/span&gt; &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mtx1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mtx2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Uses deadlock avoidance algorithm&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;safe_thread2&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;scoped_lock&lt;/span&gt; &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mtx2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mtx1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Safe regardless of order&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lock Guard is a method for safely managing mutexes using the RAII pattern.&lt;br&gt;
Since locks are automatically released even in exception or early return situations, it is much safer than manually managing &lt;code&gt;lock()&lt;/code&gt;/&lt;code&gt;unlock()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In most cases, lock_guard is sufficient, and &lt;code&gt;unique_lock&lt;/code&gt; or &lt;code&gt;scoped_lock&lt;/code&gt; should only be used in special situations.&lt;br&gt;
Proper use of these can prevent many bugs that can occur in multithreaded programming.&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>programming</category>
      <category>systemprogramming</category>
      <category>multithread</category>
    </item>
    <item>
      <title>Smart Pointers</title>
      <dc:creator>MinBapE</dc:creator>
      <pubDate>Fri, 14 Nov 2025 18:15:40 +0000</pubDate>
      <link>https://dev.to/min38/smart-pointers-in-c-managing-memory-safely-41ck</link>
      <guid>https://dev.to/min38/smart-pointers-in-c-managing-memory-safely-41ck</guid>
      <description>&lt;h3&gt;
  
  
  &lt;strong&gt;Memory Management in C/C++&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Unlike languages such as Java that automatically manage memory through a &lt;code&gt;Garbage Collector&lt;/code&gt;, C/C++ requires developers to manually allocate and deallocate memory. This means special attention must be paid to memory management. For example, C uses &lt;code&gt;malloc&lt;/code&gt; and &lt;code&gt;free&lt;/code&gt; to acquire and release memory, while C++ uses &lt;code&gt;new&lt;/code&gt; and &lt;code&gt;delete&lt;/code&gt; for the same purpose. While this characteristic allows for greater program efficiency, it also introduces risks such as memory leaks and incorrect deallocation. As a result, C/C++ programmers must always be mindful of memory usage, which is one of the key characteristics of these languages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 1. Memory Leak&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;memoryLeakExample&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// No delete -&amp;gt; Memory leak&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// 2. Null Pointer Issue&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;nullPointerExample&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;nullptr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Crash!&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// 3. Dangling Pointer Issue&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;danglingPointerExample&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Accessing already freed memory&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;strong&gt;Smart Pointer&lt;/strong&gt;
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Template classes provided in C++ for safe dynamic memory management&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Smart pointers wrap raw pointers and automatically manage memory according to the RAII (Resource Acquisition Is Initialization) principle. Memory is allocated when a Smart Pointer object is created, and automatically deallocated when the destructor is called as it goes out of scope. This prevents memory leaks without developers explicitly calling delete.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Types&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unique Ptr&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Has exclusive ownership.&lt;/li&gt;
&lt;li&gt;Cannot be copied, only &lt;code&gt;move&lt;/code&gt; operations are allowed.&lt;/li&gt;
&lt;li&gt;Has almost no overhead and performs nearly identical to raw pointers.
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;uniquePtrExample&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;unique_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ptr1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_unique&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="c1"&gt;// std::unique_ptr&amp;lt;int&amp;gt; ptr2 = ptr1;  // Compilation error&lt;/span&gt;
      &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;unique_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ptr2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ptr1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Only move allowed&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Shared Ptr&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Multiple objects can share a single resource.&lt;/li&gt;
&lt;li&gt;Internally tracks the number of owners through &lt;code&gt;Reference Counting&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Memory is deallocated when the last shared_ptr is destroyed.&lt;/li&gt;
&lt;li&gt;Has slight performance overhead due to &lt;code&gt;Reference Counting&lt;/code&gt; management.&lt;/li&gt;
&lt;li&gt;Circular references with &lt;code&gt;Shared Ptr&lt;/code&gt; can cause memory leaks, in which case &lt;code&gt;Weak Ptr&lt;/code&gt; should be used.
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;sharedPtrExample&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;shared_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ptr1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_shared&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;shared_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ptr2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ptr1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Copy allowed&lt;/span&gt;
      &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;ptr1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;use_count&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;// 2&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Weak Ptr&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Used together with &lt;code&gt;Shared Ptr&lt;/code&gt;, it's a pointer that only references objects without ownership.&lt;/li&gt;
&lt;li&gt;Does not increment &lt;code&gt;Reference Counting&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Used to resolve circular reference issues between &lt;code&gt;Shared Ptr&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;lock()&lt;/code&gt; returns a &lt;code&gt;Shared Ptr&lt;/code&gt; if the object is still alive, or &lt;code&gt;nullptr&lt;/code&gt; if already destroyed.
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;weakPtrExample&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;shared_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;shared&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_shared&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;weak_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;weak&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;shared&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// No reference count increment&lt;/span&gt;

      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;weak&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  &lt;span class="c1"&gt;// Convert to shared_ptr&lt;/span&gt;
          &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Smart pointers are essential tools for modern C++ programming. They help prevent common memory management issues while maintaining the performance characteristics that make C++ powerful. By understanding and using &lt;code&gt;unique_ptr&lt;/code&gt;, &lt;code&gt;shared_ptr&lt;/code&gt;, and &lt;code&gt;weak_ptr&lt;/code&gt; appropriately, you can write safer and more maintainable code.&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>programming</category>
      <category>memory</category>
    </item>
    <item>
      <title>I/O Multiplexing</title>
      <dc:creator>MinBapE</dc:creator>
      <pubDate>Fri, 14 Nov 2025 06:33:34 +0000</pubDate>
      <link>https://dev.to/min38/io-multiplexing-3lho</link>
      <guid>https://dev.to/min38/io-multiplexing-3lho</guid>
      <description>&lt;h3&gt;
  
  
  &lt;strong&gt;Blocking I/O&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Blocking I/O is a method where the program stops and waits until an I/O operation completes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;socket_fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Blocks here&lt;/span&gt;
&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Data received: %s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// Won't execute until data arrives&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the &lt;code&gt;read&lt;/code&gt; function is called, the program waits until data arrives. This means if no data comes, it just keeps waiting indefinitely. In a single-threaded environment, if one socket is blocked, other sockets cannot be processed.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Problems with Thread per Connection&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The approach of allocating one thread per client is intuitive and simple to implement, but it has several critical issues in production environments.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;handleClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;client_fd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client_fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Blocking&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client_fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;client_fd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;server_fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...);&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kr"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handleClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;client_fd&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;detach&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Issues&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Thread Resource Waste&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each thread spends most of its time in an I/O waiting state (Blocking).&lt;/li&gt;
&lt;li&gt;Actual data processing time is often less than 1% of the entire lifecycle.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Context Switching Overhead&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;As the number of threads increases, context switching frequency grows exponentially.&lt;/li&gt;
&lt;li&gt;Costs incurred during context switching:&lt;/li&gt;
&lt;li&gt;Saving/restoring register state&lt;/li&gt;
&lt;li&gt;Cache invalidation (increased cache misses)&lt;/li&gt;
&lt;li&gt;TLB (Translation Lookaside Buffer) flush&lt;/li&gt;
&lt;li&gt;A significant portion of CPU time is consumed by switching rather than actual work.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Memory Exhaustion&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each thread requires independent stack memory.&lt;/li&gt;
&lt;li&gt;In large-scale services, memory shortage can lead to system instability.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Thread Creation/Deletion Cost&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OS-level overhead during thread creation:&lt;/li&gt;
&lt;li&gt;Kernel resource allocation&lt;/li&gt;
&lt;li&gt;Stack memory allocation and initialization&lt;/li&gt;
&lt;li&gt;TLS (Thread Local Storage) setup&lt;/li&gt;
&lt;li&gt;Scheduler registration&lt;/li&gt;
&lt;li&gt;Accumulated costs become significant in environments with frequent connections.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Scalability Limits&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;C10K Problem: Difficulty handling more than 10,000 simultaneous connections&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;I/O Multiplexing&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;I/O Multiplexing is a technique where a single process manages multiple file descriptors simultaneously. The program monitors file descriptors to determine what type of I/O events (read, write, exceptions, etc.) have occurred and whether each file descriptor is in a ready state. Methods for implementing I/O Multiplexing include select, poll, and epoll.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;How I/O Multiplexing Works&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;A single thread registers multiple file descriptors.&lt;/li&gt;
&lt;li&gt;The OS kernel monitors the state of registered file descriptors.&lt;/li&gt;
&lt;li&gt;When an I/O operation becomes possible, the application is notified.&lt;/li&gt;
&lt;li&gt;The application performs I/O operations in a non-blocking manner only on ready file descriptors.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;I/O Multiplexing Implementation Methods&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. select&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Used to handle multiple files in a single thread.&lt;/li&gt;
&lt;li&gt;Uses an array that stores up to 1024 file descriptors, and searches for target file descriptors using sequential search, causing performance degradation as the number of file descriptors increases.&lt;/li&gt;
&lt;li&gt;Compatible with older systems, but inefficient for modern requirements.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. poll&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unlike select, which was limited to a maximum of 1024 FDs, poll can inspect an unlimited number of file descriptors.&lt;/li&gt;
&lt;li&gt;Still uses sequential search, so performance degrades as the number of file descriptors increases, similar to select.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. epoll&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Supported only on Linux&lt;/li&gt;
&lt;li&gt;Supports kernel-level multiplexing to overcome select's limitations.&lt;/li&gt;
&lt;li&gt;Manages file descriptor state in the kernel and directly notifies state changes.

&lt;ul&gt;
&lt;li&gt;Returns the list of changed file descriptors itself rather than just the count, eliminating the need to loop through files like select and poll, making it efficient.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Calling epoll_wait eliminates the need to pass monitoring target information every time.&lt;/li&gt;

&lt;li&gt;Two modes:

&lt;ul&gt;
&lt;li&gt;Level-Triggered: Continuously generates events while data remains in the input buffer. Keeps notifying as long as data exists.&lt;/li&gt;
&lt;li&gt;Edge-Triggered: Generates an event only at the moment data enters the input buffer.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;4. IOCP (I/O Completion Port)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An API that efficiently processes large volumes of non-blocking sockets in Windows environments.&lt;/li&gt;
&lt;li&gt;Features:

&lt;ul&gt;
&lt;li&gt;Suitable for building high-performance servers.&lt;/li&gt;
&lt;li&gt;Efficiently manages multiple worker threads.&lt;/li&gt;
&lt;li&gt;Processes through notifications when I/O operations complete.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;5. kqueue&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An event notification mechanism used in BSD-family operating systems like FreeBSD and macOS.&lt;/li&gt;
&lt;li&gt;Features:

&lt;ul&gt;
&lt;li&gt;Can monitor various events including sockets, files, and timers.&lt;/li&gt;
&lt;li&gt;Efficiently manages asynchronous I/O events.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;epoll vs IOCP vs kqueue&lt;/strong&gt;
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Item&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;epoll&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;IOCP&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;kqueue&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Supported OS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Linux&lt;/td&gt;
&lt;td&gt;Windows&lt;/td&gt;
&lt;td&gt;FreeBSD, macOS, etc.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Purpose&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Large-scale network I/O processing&lt;/td&gt;
&lt;td&gt;Asynchronous I/O processing&lt;/td&gt;
&lt;td&gt;Event-based I/O processing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Operation Method&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Event-based asynchronous I/O processing&lt;/td&gt;
&lt;td&gt;Notification queue for completed tasks&lt;/td&gt;
&lt;td&gt;Event registration followed by notification&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Event Management&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;epoll_wait()&lt;/td&gt;
&lt;td&gt;GetQueuedCompletionStatus()&lt;/td&gt;
&lt;td&gt;kevent()&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Handling Unit&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;File Descriptor&lt;/td&gt;
&lt;td&gt;I/O Handle&lt;/td&gt;
&lt;td&gt;File Descriptor, socket, etc.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Performance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Optimized for large-scale client connections&lt;/td&gt;
&lt;td&gt;CPU core-based optimization&lt;/td&gt;
&lt;td&gt;Efficient with diverse event management&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Features&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Edge-triggered, Level-triggered support&lt;br&gt;Simple API&lt;br&gt;Scalable&lt;/td&gt;
&lt;td&gt;Notification from work queue after I/O completion&lt;br&gt;Suitable for high-performance servers&lt;br&gt;Thread pool based&lt;/td&gt;
&lt;td&gt;File I/O, timer, and other event support&lt;br&gt;Multiplexing capable&lt;br&gt;Flexible structure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Advantages&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;High scalability&lt;br&gt;Can handle many connections&lt;/td&gt;
&lt;td&gt;Optimized CPU utilization through thread pool management&lt;br&gt;Suitable for large-scale task processing&lt;/td&gt;
&lt;td&gt;Integrated management of multiple event sources&lt;br&gt;Flexible and powerful functionality&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>cpp</category>
      <category>networking</category>
      <category>systemsprogramming</category>
    </item>
    <item>
      <title>Thread Pool</title>
      <dc:creator>MinBapE</dc:creator>
      <pubDate>Thu, 13 Nov 2025 18:55:51 +0000</pubDate>
      <link>https://dev.to/min38/thread-pool-3ema</link>
      <guid>https://dev.to/min38/thread-pool-3ema</guid>
      <description>&lt;h3&gt;
  
  
  1. The Problem with Creating Threads Per Request
&lt;/h3&gt;

&lt;p&gt;Ever implemented a server that creates a new thread for every request and destroys it when done? This approach has some critical issues you might not immediately notice.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Performance Issues&lt;/strong&gt;&lt;br&gt;
Thread creation is an expensive operation. The OS has to allocate stack memory, set up execution context, and handle various initialization overhead.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Resource Exhaustion&lt;/strong&gt;&lt;br&gt;
When thousands of concurrent requests hit your server, an equal number of threads get created. Memory gets exhausted rapidly, and your system becomes unresponsive.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Thread Pool solves this elegantly.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  2. Thread Pool
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Thread Pool&lt;/strong&gt; addresses these problems cleanly.&lt;/p&gt;

&lt;p&gt;The core idea is simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pre-create&lt;/strong&gt; threads and keep them waiting&lt;/li&gt;
&lt;li&gt;Assign work to idle threads when requests come in&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reuse&lt;/strong&gt; threads instead of destroying them after work completes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Benefits&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Performance Boost&lt;/strong&gt;: Eliminates thread creation overhead&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resource Control&lt;/strong&gt;: Pool size limits concurrent thread count&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stability&lt;/strong&gt;: Thread count stays bounded even during traffic spikes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Think of it like a restaurant: instead of hiring a chef every time a customer orders, you keep N chefs on staff and distribute orders among them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Architecture&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A Thread Pool consists of 3 main components:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Worker Threads&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;N pre-created threads&lt;/li&gt;
&lt;li&gt;Stay alive, waiting for work&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Task Queue&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Queue where pending tasks wait&lt;/li&gt;
&lt;li&gt;Must be thread-safe (multiple threads access it)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Work Distribution Logic&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Idle threads fetch tasks from the queue&lt;/li&gt;
&lt;li&gt;After completing work, they loop back to check the queue&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fae1luzlmovi6jxxr45ps.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fae1luzlmovi6jxxr45ps.jpeg" alt="Thread Pool Architecture" width="800" height="349"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Code Example
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Using a Thread Pool&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Create Thread Pool&lt;/span&gt;
&lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;num_threads&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kr"&gt;thread&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;hardware_concurrency&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// CPU core count&lt;/span&gt;
&lt;span class="n"&gt;ThreadPool&lt;/span&gt; &lt;span class="nf"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_threads&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Insert tasks into queue&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;enqueue&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;processRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// Pool internally maintains only N threads while processing 1000 tasks&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Basic Thread Pool Structure&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ThreadPool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;public:&lt;/span&gt;
    &lt;span class="n"&gt;ThreadPool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;ThreadPool&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Add task to queue&lt;/span&gt;
    &lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;F&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;enqueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nl"&gt;private:&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kr"&gt;thread&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;workers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;           &lt;span class="c1"&gt;// Worker threads&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="c1"&gt;// Task queue&lt;/span&gt;

    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt; &lt;span class="n"&gt;queue_mutex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;                     &lt;span class="c1"&gt;// Protects queue&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;condition_variable&lt;/span&gt; &lt;span class="n"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;          &lt;span class="c1"&gt;// Wait/notify threads&lt;/span&gt;
    &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>cpp</category>
      <category>systemsprogramming</category>
    </item>
  </channel>
</rss>
