<?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.us-east-2.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>OSPF - Open Shortest Path First</title>
      <dc:creator>MinBapE</dc:creator>
      <pubDate>Fri, 07 Aug 2026 04:44:18 +0000</pubDate>
      <link>https://dev.to/min38/ospf-open-shortest-path-first-3bfa</link>
      <guid>https://dev.to/min38/ospf-open-shortest-path-first-3bfa</guid>
      <description>&lt;h3&gt;
  
  
  1. OSPF Characteristics
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A Link State routing protocol&lt;/li&gt;
&lt;li&gt;Supports large networks, converges very fast&lt;/li&gt;
&lt;li&gt;Messages are sent by multicast&lt;/li&gt;
&lt;li&gt;An open standard, so it runs on every vendor's equipment&lt;/li&gt;
&lt;li&gt;Uses Dijkstra's SPF (Shortest Path First) algorithm to pick the best path&lt;/li&gt;
&lt;li&gt;Administrative Distance 110&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;IGP comparison&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;RIP&lt;/th&gt;
&lt;th&gt;EIGRP&lt;/th&gt;
&lt;th&gt;OSPF&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Scalability&lt;/td&gt;
&lt;td&gt;Low, small networks and labs&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Standard&lt;/td&gt;
&lt;td&gt;open&lt;/td&gt;
&lt;td&gt;Originally Cisco proprietary, now open but thin support elsewhere&lt;/td&gt;
&lt;td&gt;open, supported everywhere&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Production use&lt;/td&gt;
&lt;td&gt;Rarely&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Most common&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;What Link State means&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each router describes itself and its interfaces to its directly connected neighbours&lt;/li&gt;
&lt;li&gt;That information is passed from router to router &lt;strong&gt;unchanged&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;So every router ends up with the full picture of the network: every router, its interfaces, and what they connect to&lt;/li&gt;
&lt;li&gt;LSAs (Link State Advertisements) carry that information&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  2. OSPF Operations
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Discover neighbours&lt;/li&gt;
&lt;li&gt;Form adjacencies&lt;/li&gt;
&lt;li&gt;Flood the LSDB (Link State Database)&lt;/li&gt;
&lt;li&gt;Compute the Shortest Path&lt;/li&gt;
&lt;li&gt;Install the best routes in the routing table&lt;/li&gt;
&lt;li&gt;Respond to network changes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Packet types&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Hello&lt;/td&gt;
&lt;td&gt;Sent and listened for on OSPF-enabled interfaces to discover neighbours and form adjacencies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;DBD (Database Description)&lt;/td&gt;
&lt;td&gt;Tells a neighbour which networks this router knows about&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;LSR (Link State Request)&lt;/td&gt;
&lt;td&gt;Asks for the specific networks missing from a received DBD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;LSU (Link State Update)&lt;/td&gt;
&lt;td&gt;Carries the list of LSAs to be updated, used during flooding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;LSAck&lt;/td&gt;
&lt;td&gt;Acknowledges received LSAs&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;An LSA is not a packet type. It's the content carried inside an LSU.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;OSPF uses IP protocol number &lt;strong&gt;89&lt;/strong&gt; (6 = TCP, 17 = UDP).&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Basic Configuration
&lt;/h3&gt;

&lt;p&gt;Process ID&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cisco_ios"&gt;&lt;code&gt;&lt;span class="k"&gt;R1(config)#router&lt;/span&gt; ospf 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Locally significant only. It does not have to match the neighbour to form an adjacency&lt;/li&gt;
&lt;li&gt;Each instance has its own LSDB. Splitting one router across processes means routes won't cross between them&lt;/li&gt;
&lt;li&gt;In practice only one process is ever used&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The network command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cisco_ios"&gt;&lt;code&gt;&lt;span class="k"&gt;R1(config-router)#network&lt;/span&gt; &lt;span class="m"&gt;10.0.0.0&lt;/span&gt; &lt;span class="m"&gt;0.0.255.255&lt;/span&gt; area 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It means three things.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Find interfaces with an IP address inside this range&lt;/li&gt;
&lt;li&gt;Enable OSPF on them (send and listen for Hellos, peer with adjacent OSPF routers)&lt;/li&gt;
&lt;li&gt;Advertise the network and mask configured on those interfaces&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;The wildcard mask is the inverse of a subnet mask. Subtract each octet from 255 (&lt;code&gt;255.255.0.0&lt;/code&gt; = &lt;code&gt;0.0.255.255&lt;/code&gt;, &lt;code&gt;255.255.255.252&lt;/code&gt; = &lt;code&gt;0.0.0.3&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;It does not fall back to the classful boundary. Omit the wildcard mask and you get &lt;code&gt;% Incomplete command.&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;What gets advertised is the &lt;strong&gt;actual subnet on the interface&lt;/strong&gt;, not the range typed in the network command&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Verification&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;What it shows&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;`show run \&lt;/td&gt;
&lt;td&gt;section ospf`&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;show ip protocols&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Router ID, area count, advertised networks, AD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;show ip ospf interface brief&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Per-interface area, cost, state, neighbour count&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;show ip ospf neighbor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Neighbour ID, priority, state, dead time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;show ip ospf database&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The LSDB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;show ip route&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;O&lt;/code&gt; = OSPF, &lt;code&gt;O IA&lt;/code&gt; = inter area, &lt;code&gt;O E2&lt;/code&gt; = external&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  4. Router ID
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A 32 bit value identifying an OSPF router, written like an IP address&lt;/li&gt;
&lt;li&gt;Selection order: manually configured &amp;gt; highest IP of any loopback &amp;gt; highest IP of any other interface&lt;/li&gt;
&lt;li&gt;Loopbacks never go down, so the Router ID never changes&lt;/li&gt;
&lt;li&gt;Best practice: use a loopback or set it manually
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cisco_ios"&gt;&lt;code&gt;&lt;span class="k"&gt;R1(config-router)#router-id&lt;/span&gt; &lt;span class="m"&gt;2.2.2.2&lt;/span&gt;
&lt;span class="k"&gt;R1#clear&lt;/span&gt; ip ospf process
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A Router ID change only takes effect after the OSPF process restarts.&lt;/p&gt;




&lt;h3&gt;
  
  
  5. Passive Interfaces and Default Routes
&lt;/h3&gt;

&lt;p&gt;Passive interface&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stops sending Hellos out that interface. The network is still advertised&lt;/li&gt;
&lt;li&gt;Use it on interfaces with no routers behind them (user LANs, loopbacks) to cut pointless Hellos and reduce exposure
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cisco_ios"&gt;&lt;code&gt;&lt;span class="k"&gt;R1(config-router)#passive-interface&lt;/span&gt; default
&lt;span class="k"&gt;R1(config-router)#no&lt;/span&gt; passive-interface f0/0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Default route injection&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cisco_ios"&gt;&lt;code&gt;&lt;span class="k"&gt;R4(config)#ip&lt;/span&gt; route &lt;span class="m"&gt;0.0.0.0&lt;/span&gt; &lt;span class="m"&gt;0.0.0.0&lt;/span&gt; &lt;span class="m"&gt;203.0.113.2&lt;/span&gt;
&lt;span class="k"&gt;R4(config)#router&lt;/span&gt; ospf 1
&lt;span class="k"&gt;R4(config-router)#default-information&lt;/span&gt; originate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Other routers receive it as &lt;code&gt;O*E2 0.0.0.0/0&lt;/code&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  6. Areas
&lt;/h3&gt;

&lt;p&gt;Every router holding the full picture becomes a problem on large networks. Too many routes eat router memory, and one change makes every router reconverge, costing time and CPU.&lt;/p&gt;

&lt;p&gt;Areas are a hierarchical design that splits a large network into smaller pieces. Each router keeps &lt;strong&gt;full information about its own area&lt;/strong&gt; and only &lt;strong&gt;summary information about others&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Two-level hierarchy: a Transit area (backbone, area 0) and regular areas&lt;/li&gt;
&lt;li&gt;Area 0 generally holds no end users. By default all transit traffic goes through it&lt;/li&gt;
&lt;li&gt;Small networks don't need the hierarchy, everything can sit in area 0&lt;/li&gt;
&lt;li&gt;The area is set &lt;strong&gt;per interface&lt;/strong&gt; by the network command. Both sides must be in the same area to form an adjacency&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Router types&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Definition&lt;/th&gt;
&lt;th&gt;Route code&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Backbone Router&lt;/td&gt;
&lt;td&gt;All OSPF interfaces in area 0&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Normal Internal Router&lt;/td&gt;
&lt;td&gt;All OSPF interfaces in one normal area&lt;/td&gt;
&lt;td&gt;Same area shows as &lt;code&gt;O&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ABR (Area Border Router)&lt;/td&gt;
&lt;td&gt;Interfaces in multiple areas&lt;/td&gt;
&lt;td&gt;Other areas show as &lt;code&gt;O IA&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ASBR (Autonomous System Boundary Router)&lt;/td&gt;
&lt;td&gt;Redistributes an external protocol into OSPF&lt;/td&gt;
&lt;td&gt;External shows as &lt;code&gt;O E1&lt;/code&gt; / &lt;code&gt;O E2&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;ABR characteristics&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Separates LSA flooding zones&lt;/li&gt;
&lt;li&gt;Is the primary point for area address summarization&lt;/li&gt;
&lt;li&gt;Regularly acts as the source of default routes&lt;/li&gt;
&lt;li&gt;Maintains a separate LSDB for each connected area&lt;/li&gt;
&lt;li&gt;Ideal design is one ABR on the backbone plus one area, with three areas as the upper limit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Manual summarization&lt;/p&gt;

&lt;p&gt;ABRs do not summarize automatically. Without it, every route is flooded everywhere.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cisco_ios"&gt;&lt;code&gt;&lt;span class="k"&gt;R2(config-router)#area&lt;/span&gt; 0 range &lt;span class="m"&gt;10.1.0.0&lt;/span&gt; &lt;span class="m"&gt;255.255.0.0&lt;/span&gt;
&lt;span class="k"&gt;R2(config-router)#area&lt;/span&gt; 1 range &lt;span class="m"&gt;10.0.0.0&lt;/span&gt; &lt;span class="m"&gt;255.255.0.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  7. Cost Metric
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;OSPF picks the path with the lowest cost&lt;/li&gt;
&lt;li&gt;Total cost = sum of the &lt;strong&gt;outgoing interface&lt;/strong&gt; costs along the path&lt;/li&gt;
&lt;li&gt;For a destination in another area, the router picks the cheapest path to the ABR, and the ABR decides from there&lt;/li&gt;
&lt;li&gt;Set the cost the same on both ends of a link or you get asymmetric routing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Reference bandwidth&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Cost = Reference Bandwidth / Interface Bandwidth
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The default reference bandwidth is 100 Mbps&lt;/li&gt;
&lt;li&gt;FastEthernet = 100/100 = 1, T1 = 100/1.544 = 64&lt;/li&gt;
&lt;li&gt;Problem: everything at 100 Mbps or faster is cost 1. FastEthernet and 10 Gigabit rank equally&lt;/li&gt;
&lt;li&gt;Fix: raise the reference bandwidth, and set it &lt;strong&gt;identically on every router&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cisco_ios"&gt;&lt;code&gt;&lt;span class="k"&gt;R1(config-router)#auto-cost&lt;/span&gt; reference-bandwidth 100000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;speed vs clock rate vs bandwidth&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Applies to&lt;/th&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;speed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Ethernet&lt;/td&gt;
&lt;td&gt;Actual physical transmission rate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;clock rate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Serial&lt;/td&gt;
&lt;td&gt;Actual physical transmission rate (default 1.544 Mbps)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bandwidth&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;All&lt;/td&gt;
&lt;td&gt;No effect on physical rate. Only affects &lt;strong&gt;software policy&lt;/strong&gt;: OSPF/EIGRP path selection, QoS&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Manipulating the metric&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prefer &lt;code&gt;ip ospf cost&lt;/code&gt; over &lt;code&gt;bandwidth&lt;/code&gt;, because bandwidth affects features beyond OSPF such as QoS&lt;/li&gt;
&lt;li&gt;A manually configured cost overrides the value derived from the bandwidth
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cisco_ios"&gt;&lt;code&gt;&lt;span class="k"&gt;R1(config-if)#ip&lt;/span&gt; ospf cost 50
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  8. Adjacencies
&lt;/h3&gt;

&lt;p&gt;Hello packets&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sent out every OSPF-enabled interface (except passive ones)&lt;/li&gt;
&lt;li&gt;Multicast to &lt;code&gt;224.0.0.5&lt;/code&gt; (all OSPF routers)&lt;/li&gt;
&lt;li&gt;Every 10 seconds by default, Dead Interval defaults to 4x Hello = 40 seconds&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hello contents: Router ID, Hello and Dead Intervals, Neighbors list, Area ID, Router Priority, DR and BDR addresses, Authentication Flag, Stub Area Flag&lt;/p&gt;

&lt;p&gt;These must match for two routers to form an adjacency&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each must be in the other's Neighbor list&lt;/li&gt;
&lt;li&gt;Hello Interval, Dead Interval&lt;/li&gt;
&lt;li&gt;Area ID&lt;/li&gt;
&lt;li&gt;IP subnet&lt;/li&gt;
&lt;li&gt;Authentication Flag&lt;/li&gt;
&lt;li&gt;Stub Area Flag&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;MTU is not on that list. Mismatched MTU still forms neighbours, but they won't exchange routes. Default 1500 bytes, &lt;code&gt;mtu&lt;/code&gt; affects all packets and &lt;code&gt;ip mtu&lt;/code&gt; only IP packets.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Neighbor states&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;State&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Down&lt;/td&gt;
&lt;td&gt;No active neighbour detected&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;INIT&lt;/td&gt;
&lt;td&gt;A Hello was received from the neighbour&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;2-Way&lt;/td&gt;
&lt;td&gt;Own Router ID appears in the received Hello (DR/BDR elected here on multiaccess)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Exstart&lt;/td&gt;
&lt;td&gt;The higher Router ID becomes primary, roles determined&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Exchange&lt;/td&gt;
&lt;td&gt;DBD packets sent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Loading&lt;/td&gt;
&lt;td&gt;LSRs sent and LSUs received&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Full&lt;/td&gt;
&lt;td&gt;Fully adjacent&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  9. DR and BDR
&lt;/h3&gt;

&lt;p&gt;On point-to-point links a pair of routers simply forms a FULL adjacency. On a multiaccess segment like Ethernet there can be many routers, and having all of them form FULL adjacencies with each other is inefficient.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A DR (Designated Router) and BDR (Backup DR) are elected&lt;/li&gt;
&lt;li&gt;Highest priority becomes DR, second highest becomes BDR. Default priority 1, range 0-255, higher is better&lt;/li&gt;
&lt;li&gt;Highest Router ID breaks a tie&lt;/li&gt;
&lt;li&gt;Priority 0 removes a router from the election&lt;/li&gt;
&lt;li&gt;The election happens at the 2-Way stage. No election on point-to-point links
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cisco_ios"&gt;&lt;code&gt;&lt;span class="k"&gt;R1(config-if)#ip&lt;/span&gt; ospf priority 100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restart OSPF on the interface for it to take effect.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only the DR and BDR reach FULL with every router on the segment. The rest stay at 2-Way and never exchange routes directly&lt;/li&gt;
&lt;li&gt;On a link state change a router multicasts an LSU to &lt;code&gt;224.0.0.6&lt;/code&gt; (all designated routers), and the DR multicasts it on to &lt;code&gt;224.0.0.5&lt;/code&gt; (all OSPF routers)&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  10. Summary
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;OSPF is Link State, an open standard, AD 110, IP protocol number 89, uses Dijkstra's SPF&lt;/li&gt;
&lt;li&gt;LSAs propagate unchanged, so every router holds the full picture of its own area&lt;/li&gt;
&lt;li&gt;Process ID is local only, Router ID should come from a loopback or be set manually&lt;/li&gt;
&lt;li&gt;The network command takes a wildcard mask, and what's advertised is the interface's actual subnet&lt;/li&gt;
&lt;li&gt;Cost = Reference Bandwidth / Interface Bandwidth, summed over outgoing interfaces. Everything at 100 Mbps+ is cost 1, so raise the reference bandwidth identically on every router&lt;/li&gt;
&lt;li&gt;Adjacency must match on: Hello/Dead Intervals, Area ID, IP subnet, Authentication, Stub Flag. MTU mismatch still forms neighbours but blocks route exchange&lt;/li&gt;
&lt;li&gt;Neighbor states: Down, INIT, 2-Way, Exstart, Exchange, Loading, Full&lt;/li&gt;
&lt;li&gt;DR/BDR are elected on multiaccess segments only, at the 2-Way stage. Highest priority wins, then highest Router ID&lt;/li&gt;
&lt;li&gt;224.0.0.5 for Hellos and DR reflooding, 224.0.0.6 for sending to the DR&lt;/li&gt;
&lt;li&gt;ABRs don't summarize automatically. Use &lt;code&gt;area range&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>networking</category>
      <category>computerscience</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Hub &amp; Switch &amp; Router</title>
      <dc:creator>MinBapE</dc:creator>
      <pubDate>Wed, 05 Aug 2026 10:32:56 +0000</pubDate>
      <link>https://dev.to/min38/hub-switch-router-4g82</link>
      <guid>https://dev.to/min38/hub-switch-router-4g82</guid>
      <description>&lt;h3&gt;
  
  
  1. Hub vs Switch
&lt;/h3&gt;

&lt;p&gt;Both let LAN end hosts (PCs, servers, printers) plug in over Ethernet and talk to each other. The difference is the layer they operate at and how much they know.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Hub&lt;/th&gt;
&lt;th&gt;Switch&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Operates at&lt;/td&gt;
&lt;td&gt;Layer 1&lt;/td&gt;
&lt;td&gt;Layer 2 (and Layer 1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MAC addresses&lt;/td&gt;
&lt;td&gt;Not aware&lt;/td&gt;
&lt;td&gt;Aware&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Duplex&lt;/td&gt;
&lt;td&gt;half-duplex only&lt;/td&gt;
&lt;td&gt;full-duplex capable, always full in practice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Simultaneous send/receive&lt;/td&gt;
&lt;td&gt;No, one or the other&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Collision Domain&lt;/td&gt;
&lt;td&gt;All hosts share one&lt;/td&gt;
&lt;td&gt;Dedicated per port&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Collision Detection&lt;/td&gt;
&lt;td&gt;Required, CSMA/CD detects then retransmits&lt;/td&gt;
&lt;td&gt;Not required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frame handling&lt;/td&gt;
&lt;td&gt;Floods every port except the one it came in on&lt;/td&gt;
&lt;td&gt;Sends to the destination port only (once learned)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  2. How a Switch Works
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Behavior&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Learning&lt;/td&gt;
&lt;td&gt;On receiving a frame, record the &lt;strong&gt;Source MAC&lt;/strong&gt; from the Ethernet header against the receiving port in the MAC address table&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Forwarding&lt;/td&gt;
&lt;td&gt;If the &lt;strong&gt;Destination MAC&lt;/strong&gt; is in the table, send only out that port&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Flooding&lt;/td&gt;
&lt;td&gt;If the destination is a broadcast or an unknown unicast, send out every port except the one it arrived on&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;There are only two flooding conditions: broadcast, or unknown unicast.&lt;/p&gt;

&lt;p&gt;Sending only to the destination port helps both performance and security. The frame goes where it's needed, so other hosts don't spend cycles on it and never see traffic that isn't theirs. A hub does the opposite: it sprays every port, so every host has to process every frame.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Router
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Knows the paths to the various IP subnets on the network&lt;/li&gt;
&lt;li&gt;Sending traffic from one subnet to another always requires a router&lt;/li&gt;
&lt;li&gt;Operates at Layer 3 (also at Layers 2 and 1, and usually aware up to Layer 7)&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;&lt;/th&gt;
&lt;th&gt;Router&lt;/th&gt;
&lt;th&gt;Switch&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Aware at&lt;/td&gt;
&lt;td&gt;Layer 3&lt;/td&gt;
&lt;td&gt;Layer 2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Role&lt;/td&gt;
&lt;td&gt;Routing between different networks&lt;/td&gt;
&lt;td&gt;Switching between hosts on a LAN&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interfaces&lt;/td&gt;
&lt;td&gt;Varied: Ethernet, Serial, ISDN, ADSL&lt;/td&gt;
&lt;td&gt;Usually Ethernet only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Port count&lt;/td&gt;
&lt;td&gt;Few&lt;/td&gt;
&lt;td&gt;Many&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Broadcasts&lt;/td&gt;
&lt;td&gt;Not forwarded by default&lt;/td&gt;
&lt;td&gt;Forwarded&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Hosts in the same subnet (10.10.10.x) talk through a switch alone, but the moment another subnet (10.10.11.x) is involved a router is required.&lt;/p&gt;

&lt;p&gt;Layer 3 Switch&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Higher-end switches are Layer 3 aware and can route between IP subnets&lt;/li&gt;
&lt;li&gt;Interfaces are still Ethernet only, and port count is higher than a router's&lt;/li&gt;
&lt;li&gt;Typical build: a Layer 3 Switch routes between internal subnets, a router handles the WAN&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;A Layer 3 Switch is a switch with router functions.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  4. Summary
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Hub is L1, half-duplex, one collision domain, no MAC awareness → always floods&lt;/li&gt;
&lt;li&gt;Switch is L2, full-duplex, per-port collision domains, keeps a MAC address table&lt;/li&gt;
&lt;li&gt;Learning uses the Source MAC, forwarding uses the Destination MAC&lt;/li&gt;
&lt;li&gt;Flooding happens on broadcast or unknown unicast (out every port but the ingress one)&lt;/li&gt;
&lt;li&gt;Many MACs per port is fine, one MAC on many ports is not&lt;/li&gt;
&lt;li&gt;A router is required for inter-subnet traffic. Varied interfaces, few ports, no broadcast forwarding&lt;/li&gt;
&lt;li&gt;A Layer 3 Switch can route but has Ethernet interfaces only&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>networking</category>
      <category>computerscience</category>
      <category>beginners</category>
    </item>
    <item>
      <title>OSI 7 Layer</title>
      <dc:creator>MinBapE</dc:creator>
      <pubDate>Tue, 04 Aug 2026 07:40:46 +0000</pubDate>
      <link>https://dev.to/min38/osi-7-layer-597h</link>
      <guid>https://dev.to/min38/osi-7-layer-597h</guid>
      <description>&lt;h3&gt;
  
  
  1. What is the OSI 7 Layer Model?
&lt;/h3&gt;

&lt;p&gt;OSI (Open Systems Interconnection) is a reference model created by ISO. A framework that standardizes how computers communicate, split into 7 layers.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Each layer provides services to the layer above it, and receives services from the layer below it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Key Info&lt;/th&gt;
&lt;th&gt;Device&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Application&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Presentation&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Session&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Transport&lt;/td&gt;
&lt;td&gt;TCP/UDP, Port&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Network&lt;/td&gt;
&lt;td&gt;IP Address&lt;/td&gt;
&lt;td&gt;Router&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Data-Link&lt;/td&gt;
&lt;td&gt;Ethernet MAC Address&lt;/td&gt;
&lt;td&gt;Switch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Physical&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Hub&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;What layering gives&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No need to design a technology end to end. Each party owns one layer&lt;/li&gt;
&lt;li&gt;Open standards, so multi-vendor interoperability&lt;/li&gt;
&lt;li&gt;A problem can be narrowed to one layer, which makes troubleshooting easier&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Encapsulation&lt;/p&gt;

&lt;p&gt;The sender adds a header at each layer going 7 down to 1 (encapsulation), the receiver strips them going 1 up to 7 (de-encapsulation).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;L7   [ Data ]                                    Data
L4   [TCP][ Data ]                               Segment
L3   [IP][TCP][ Data ]                           Packet
L2   [Eth][IP][TCP][ Data ][FCS]                 Frame
L1   10110100 01011101 00101110 ...              bits
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  2. OSI vs TCP/IP Stack
&lt;/h3&gt;

&lt;p&gt;OSI is conceptual. The stack that actually moves data on production networks is TCP/IP, developed by ARPA under the US DoD in the 1960s. TCP/IP is layered too, but collapses OSI's 7 layers into 4.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;OSI Model&lt;/th&gt;
&lt;th&gt;TCP/IP Stack&lt;/th&gt;
&lt;th&gt;Definition&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Application / Presentation / Session&lt;/td&gt;
&lt;td&gt;Application&lt;/td&gt;
&lt;td&gt;Represents and encodes user data, controls dialog&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Transport&lt;/td&gt;
&lt;td&gt;Transport&lt;/td&gt;
&lt;td&gt;Supports communication between end devices across networks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Network&lt;/td&gt;
&lt;td&gt;Internet&lt;/td&gt;
&lt;td&gt;Logical addressing and best path determination&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data Link / Physical&lt;/td&gt;
&lt;td&gt;Link&lt;/td&gt;
&lt;td&gt;Controls the hardware devices and media that make up the network&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;PDU (Protocol Data Unit)&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;TCP/IP Layer&lt;/th&gt;
&lt;th&gt;PDU&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Application&lt;/td&gt;
&lt;td&gt;Data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Transport&lt;/td&gt;
&lt;td&gt;Segment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Internet&lt;/td&gt;
&lt;td&gt;Packet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Link&lt;/td&gt;
&lt;td&gt;Frame&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  3. Layers 7, 6, 5 (the Upper Layers)
&lt;/h3&gt;

&lt;p&gt;Layer 7 Application&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Provides network services to user applications&lt;/li&gt;
&lt;li&gt;Unlike the other layers, provides services to no OSI layer above it&lt;/li&gt;
&lt;li&gt;Verifies the availability of the communication partner&lt;/li&gt;
&lt;li&gt;Synchronizes and agrees on error recovery procedures and data integrity control&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Layer 6 Presentation&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ensures information from the sender's application layer is readable at the receiver's&lt;/li&gt;
&lt;li&gt;Converts data formats between different encoding schemes into a common format&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Layer 5 Session&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Establishes, manages and terminates sessions between two hosts&lt;/li&gt;
&lt;li&gt;Synchronizes dialog between presentation layers and manages data exchange&lt;/li&gt;
&lt;li&gt;A web server handles many users at once, so it tracks multiple communication processes separately&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  4. Layer 4 Transport
&lt;/h3&gt;

&lt;p&gt;The layer of TCP/UDP and port numbers. Splits data into segments, transmits and reassembles them between end devices.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Session Multiplexing: one host supports multiple sessions over a single link and manages each traffic stream separately. A server takes HTTP (80) and SMTP (25) traffic at once without the sessions mixing&lt;/li&gt;
&lt;li&gt;Flow Control: throttles the sender so data arrives only as fast as the receiver can handle&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Port numbers&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The destination port identifies the upper-layer protocol (HTTP = 80, SMTP = 25)&lt;/li&gt;
&lt;li&gt;The sender also puts a source port in the Layer 4 header&lt;/li&gt;
&lt;li&gt;What distinguishes and tracks a session is the source and destination port pair
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Sender   → Receiver   : DST 80,   SRC 1500
Receiver → Sender     : DST 1500, SRC 80     // ports swap on the reply
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;TCP vs UDP&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;TCP&lt;/th&gt;
&lt;th&gt;UDP&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Connection&lt;/td&gt;
&lt;td&gt;Connection oriented (3-way handshake)&lt;/td&gt;
&lt;td&gt;Not connection oriented&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sequencing&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reliability&lt;/td&gt;
&lt;td&gt;Yes (ACK + retransmit)&lt;/td&gt;
&lt;td&gt;No (no ACK)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Flow Control&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Header Size&lt;/td&gt;
&lt;td&gt;20 Bytes&lt;/td&gt;
&lt;td&gt;8 Bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;TCP 3-way handshake.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Sender                            Receiver
   |------------- SYN -------------&amp;gt;|
   |&amp;lt;----------- SYN-ACK -----------|
   |------------- ACK -------------&amp;gt;|
   |===== connection established ===|
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Full TCP / UDP header fields&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TCP header (20 Bytes)
  Source Port 16 | Destination Port 16 | Sequence Number 32
  Acknowledgment Number 32 | Header Length 4 | Reserved 6
  Code Bits 6 | Window 16 | Checksum 16 | Urgent 16
  (+ Options 0 or 32)

UDP header (8 Bytes)
  Source Port 16 | Destination Port 16 | Length 16 | Checksum 16
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Reliability needed means TCP. Real-time traffic that can't absorb TCP's overhead means UDP.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Protocol&lt;/th&gt;
&lt;th&gt;Applications (Port)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;TCP&lt;/td&gt;
&lt;td&gt;FTP(21), SSH(22), Telnet(23), HTTP(80), HTTPS(443)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UDP&lt;/td&gt;
&lt;td&gt;TFTP(69), SNMP(161)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Both&lt;/td&gt;
&lt;td&gt;DNS(53)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  5. Layer 3 Network
&lt;/h3&gt;

&lt;p&gt;Routing and QoS. IP is the main protocol and it's connectionless, so there are no acknowledgements at Layer 3. ICMP and IPSec are also Layer 3.&lt;/p&gt;

&lt;p&gt;The IP header is 20 bytes without options.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Size&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;TTL&lt;/td&gt;
&lt;td&gt;8 bit&lt;/td&gt;
&lt;td&gt;Decremented by every router, discarded at 0 (prevents infinite loops)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Protocol&lt;/td&gt;
&lt;td&gt;8 bit&lt;/td&gt;
&lt;td&gt;Identifies the upper-layer protocol (TCP=6, UDP=17)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Source / Destination IP&lt;/td&gt;
&lt;td&gt;32 bit each&lt;/td&gt;
&lt;td&gt;Ties directly to IPv4 address length&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Type of Service&lt;/td&gt;
&lt;td&gt;8 bit&lt;/td&gt;
&lt;td&gt;QoS priority marking&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Unicast / Broadcast / Multicast&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Destination&lt;/th&gt;
&lt;th&gt;Behavior&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Unicast&lt;/td&gt;
&lt;td&gt;A single host&lt;/td&gt;
&lt;td&gt;1:1. Reaching many hosts means a separate copy to each&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Broadcast&lt;/td&gt;
&lt;td&gt;All hosts in the subnet&lt;/td&gt;
&lt;td&gt;Switches forward it, routers do not&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multicast&lt;/td&gt;
&lt;td&gt;Interested hosts only&lt;/td&gt;
&lt;td&gt;One stream reaches only the hosts that want it. Routers can forward it&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Broadcasts not crossing a router = the router is the boundary of the broadcast domain.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Logical addressing&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;IP addressing is a logical addressing scheme implemented at Layer 3, used to divide a network into smaller subnets&lt;/li&gt;
&lt;li&gt;Subnetting improves performance and security and makes troubleshooting easier&lt;/li&gt;
&lt;li&gt;Layer 2 MAC addressing is one giant flat scheme with no hierarchy. Layer 2 has no logical separation between networks, that only happens at Layer 3&lt;/li&gt;
&lt;li&gt;A host uses the subnet mask to check whether the destination is in the same subnet. Same subnet goes directly through the switch, different goes via the router&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The addressing scheme itself (IP classes, mask math, CIDR, RFC 1918) is in a separate post.&lt;/p&gt;




&lt;h3&gt;
  
  
  6. Layer 2 Data-Link
&lt;/h3&gt;

&lt;p&gt;Where frames are encoded into and decoded from bits. Error detection and correction for the Physical Layer can be provided here. Ethernet is the Layer 2 medium on LANs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────┬─────────┬─────────┬──────────┬───────────────┬─────────┐
│ Preamble │ DST MAC │ SRC MAC │ Len/Type │     Data      │   FCS   │
│ 8 Bytes  │ 6 Bytes │ 6 Bytes │ 2 Bytes  │ 46~1500 Bytes │ 4 Bytes │
└──────────┴─────────┴─────────┴──────────┴───────────────┴─────────┘
                                                            trailer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Preamble: frame start synchronization&lt;/li&gt;
&lt;li&gt;Length / Ethertype: length, or upper-layer protocol type&lt;/li&gt;
&lt;li&gt;FCS: error detection. A trailer at the end of the frame, not part of the header&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;MAC address 6 Bytes = 48 bits. Data max 1500 Bytes = Ethernet's default MTU.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Some sources list the Preamble as 7 Bytes. That's IEEE 802.3 counting Preamble 7 Bytes and SFD (Start Frame Delimiter) 1 Byte separately, which adds up to the same 8 Bytes. Cisco material and Ethernet II fold the SFD into the Preamble and call it 8 Bytes.&lt;/p&gt;

&lt;p&gt;Preamble and SFD aren't counted in the frame size. The 64 to 1518 Byte Ethernet frame runs from DST MAC through FCS: &lt;code&gt;14 + 46 + 4 = 64&lt;/code&gt;, &lt;code&gt;14 + 1500 + 4 = 1518&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;MAC Address&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;First 24 bits&lt;/th&gt;
&lt;th&gt;Last 24 bits&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Name&lt;/td&gt;
&lt;td&gt;OUI (Organizationally Unique Identifier)&lt;/td&gt;
&lt;td&gt;Vendor Assigned&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Assigned by&lt;/td&gt;
&lt;td&gt;IEEE&lt;/td&gt;
&lt;td&gt;The manufacturer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Example (&lt;code&gt;00:50:56:C0:00:08&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;00:50:56&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;C0:00:08&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The OUI identifies the manufacturer of that Ethernet port. MAC addresses are burned into the NIC and globally unique.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;MAC is 48-bit, Layer 2, fixed at manufacture, flat. IP is 32-bit, Layer 3, assigned by an admin, hierarchical. Layer 2 has no logical separation between networks, that happens at Layer 3.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  7. Layer 1 Physical
&lt;/h3&gt;

&lt;p&gt;Puts a bit stream onto the network as electrical impulses, light or radio signals. The electrical and mechanical layer, defining cables, interface cards and physical specifications. Media are coaxial (unused now), twisted copper pair, fiber, wireless.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UTP (Unshielded Twisted Pair): most common for desktop PC to switch. RJ-45 connector, 100 m maximum&lt;/li&gt;
&lt;li&gt;Straight-Through: end device to switch (PC to Switch, Router to Switch)&lt;/li&gt;
&lt;li&gt;Crossover: same kind of device directly (PC to PC, Switch to Switch). Auto MDI-X handles this automatically on modern switches&lt;/li&gt;
&lt;li&gt;Fiber: for longer distance or higher bandwidth. Single Mode is higher bandwidth and longer reach but pricier, Multi Mode is cheaper&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  8. Summary
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;OSI is a conceptual 7-layer model, TCP/IP is the 4-layer stack in use. PDUs are Data, Segment, Packet, Frame&lt;/li&gt;
&lt;li&gt;Devices by layer: L3 Router, L2 Switch, L1 Hub&lt;/li&gt;
&lt;li&gt;L4 distinguishes sessions by port. Reliability means TCP (20 Bytes), low latency means UDP (8 Bytes)&lt;/li&gt;
&lt;li&gt;L3 divides networks with logical addressing. Broadcasts don't cross routers, so the router is the boundary of the broadcast domain&lt;/li&gt;
&lt;li&gt;L2 MAC is 48-bit, flat, fixed at manufacture. L3 IP is 32-bit, hierarchical, assigned by an admin&lt;/li&gt;
&lt;li&gt;Layers 5 to 7 are the app developer's territory, layers 1 to 4 the network engineer's&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>networking</category>
      <category>computerscience</category>
      <category>beginners</category>
    </item>
    <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>cpp</category>
      <category>programming</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>
      <category>tcp</category>
      <category>socket</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>
  </channel>
</rss>
