{"id":4549,"date":"2023-09-05T19:06:53","date_gmt":"2023-09-06T02:06:53","guid":{"rendered":"https:\/\/ioflood.com\/blog\/?p=4549"},"modified":"2024-02-05T13:26:26","modified_gmt":"2024-02-05T20:26:26","slug":"python-socket","status":"publish","type":"post","link":"https:\/\/ioflood.com\/blog\/python-socket\/","title":{"rendered":"Python Socket Programming Guide (With Examples)"},"content":{"rendered":"<div class=\"wp-block-image\">\n<figure class=\"alignright size-full is-resized\"><img decoding=\"async\" src=\"https:\/\/ioflood.com\/blog\/wp-content\/uploads\/2023\/09\/Socket-programming-in-Python-network-connections-data-transmission-code-300x300.jpg\" alt=\"Socket programming in Python network connections data transmission code\" width=\"300\" height=\"300\" title=\"\"><\/figure>\n<\/div>\n<p>Are you finding it challenging to get a grip on Python sockets? Think of Python sockets like a virtual postman. They are the key to enabling communication between two nodes on a network.<\/p>\n<p>Whether you are a beginner just dipping your toes into the world of Python sockets or an advanced user looking to refine your skills, this guide is designed for you.<\/p>\n<p><strong>We will walk you through everything you need to know about Python sockets, from the basic to the advanced usage.<\/strong> By the end of this guide, you will have a solid understanding of Python sockets and how to use them effectively in your projects.<\/p>\n<h2>TL;DR: What is a Python Socket?<\/h2>\n<blockquote><p>\n  A Python socket is a module in Python that provides a way for two computers to communicate. It&#8217;s like a virtual postman, delivering messages between two nodes on a network.\n<\/p><\/blockquote>\n<p>Here&#8217;s a simple example of a Python socket:<\/p>\n<pre><code class=\"language-python line-numbers\">import socket\ns = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\ns.connect(('localhost', 12345))\n\n# Output:\n# Establishes a connection to the server at localhost on port 12345\n<\/code><\/pre>\n<p>In this example, we first import the socket module. We then create a socket object <code>s<\/code> using the <code>socket()<\/code> function. The arguments <code>socket.AF_INET<\/code> and <code>socket.SOCK_STREAM<\/code> specify the address family and socket type. Finally, we use the <code>connect()<\/code> method to establish a connection to the server at &#8216;localhost&#8217; on port 12345.<\/p>\n<blockquote><p>\n  This is a basic way to use a Python socket, but there&#8217;s much more to learn about network communication in Python. Continue reading for more detailed information and advanced usage scenarios.\n<\/p><\/blockquote>\n<h2>Python Sockets: Basic Usage<\/h2>\n<p>Python sockets are a powerful tool for network communication. Let&#8217;s start with the basics: creating a socket, connecting to a server, and sending and receiving data.<\/p>\n<h3>Creating a Socket<\/h3>\n<p>The first step is to import the socket module and create a socket object. Here&#8217;s how you do it:<\/p>\n<pre><code class=\"language-python line-numbers\">import socket\ns = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n<\/code><\/pre>\n<p>In this code, <code>socket.AF_INET<\/code> specifies that we are using IPv4, and <code>socket.SOCK_STREAM<\/code> indicates that we are using TCP. The <code>socket()<\/code> function returns a socket object <code>s<\/code>.<\/p>\n<h3>Connecting to a Server<\/h3>\n<p>Next, we need to connect to a server. We do this using the <code>connect()<\/code> method of the socket object, as shown in this example:<\/p>\n<pre><code class=\"language-python line-numbers\">s.connect(('localhost', 12345))\n<\/code><\/pre>\n<p>Here, &#8216;localhost&#8217; is the server name, and 12345 is the port number. The <code>connect()<\/code> method establishes a TCP client-server connection.<\/p>\n<h3>Sending and Receiving Data<\/h3>\n<p>Once the connection is established, we can send and receive data using the <code>send()<\/code> and <code>recv()<\/code> methods. Here&#8217;s an example:<\/p>\n<pre><code class=\"language-python line-numbers\">s.send(b'Hello, Server!')\nmessage = s.recv(1024)\nprint('Received from server: ', message)\n\n# Output:\n# Received from server:  b'Hello, Client!'\n<\/code><\/pre>\n<p>In this code, <code>s.send(b'Hello, Server!')<\/code> sends a message to the server. The <code>b<\/code> before the string converts it to bytes, because the <code>send()<\/code> method requires data in bytes. The <code>recv(1024)<\/code> method receives data from the server. The argument 1024 is the maximum amount of data to be received at once.<\/p>\n<p>Python sockets are relatively easy to use and offer a high degree of control over network communication. However, they can be tricky for beginners. Error handling is essential, especially for network issues such as connection errors and timeouts. Also, remember to always close the socket when you&#8217;re done using it to free up resources.<\/p>\n<pre><code class=\"language-python line-numbers\">s.close()\n<\/code><\/pre>\n<p>This command closes the socket and releases the resources.<\/p>\n<h2>Advanced Python Sockets: Server Creation and Multi-Connections<\/h2>\n<p>As you become more comfortable with Python sockets, you can start exploring more complex uses. This includes creating a server, handling multiple connections, and working with non-blocking sockets.<\/p>\n<h3>Creating a Server<\/h3>\n<p>Let&#8217;s start by creating a basic server that can accept connections from clients. Here&#8217;s an example:<\/p>\n<pre><code class=\"language-python line-numbers\">import socket\n\ns = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\ns.bind(('localhost', 12345))\ns.listen(5)\n\nprint('Server is listening')\n\nwhile True:\n    c, addr = s.accept()\n    print('Got connection from', addr)\n    c.send(b'Thank you for connecting')\n    c.close()\n\n# Output:\n# Server is listening\n# Got connection from ('127.0.0.1', 52617)\n# ...\n<\/code><\/pre>\n<p>In this code, the <code>bind()<\/code> method binds the server to the specified host and port. The <code>listen()<\/code> function enables the server to accept connections. The argument 5 is the maximum number of queued connections.<\/p>\n<p>The <code>accept()<\/code> method waits until a client connects to the server. It returns a new socket object <code>c<\/code> and the address <code>addr<\/code> of the client. The server then sends a message to the client and closes the connection.<\/p>\n<h3>Handling Multiple Connections<\/h3>\n<p>To handle multiple connections simultaneously, we can use threading. Here&#8217;s an example of a multithreaded server:<\/p>\n<pre><code class=\"language-python line-numbers\">import socket\nimport threading\n\ndef handle_client(c):\n    message = c.recv(1024)\n    print('Received:', message)\n    c.send(b'Echo:' + message)\n    c.close()\n\ns = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\ns.bind(('localhost', 12345))\ns.listen(5)\n\nwhile True:\n    c, addr = s.accept()\n    print('Got connection from', addr)\n    threading.Thread(target=handle_client, args=(c,)).start()\n\n# Output:\n# Got connection from ('127.0.0.1', 52617)\n# Received: b'Hello, Server!'\n# ...\n<\/code><\/pre>\n<p>In this code, we create a new thread for each connection. The <code>handle_client()<\/code> function receives a message from the client, prints it, sends an echo back to the client, and then closes the connection.<\/p>\n<h3>Non-Blocking Sockets<\/h3>\n<p>Python also supports non-blocking sockets. These sockets don&#8217;t wait for a <code>send()<\/code> or <code>recv()<\/code> operation to complete before continuing to execute the program. Here&#8217;s an example:<\/p>\n<pre><code class=\"language-python line-numbers\">import socket\n\ns = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\ns.setblocking(0)\n\ntry:\n    s.connect(('localhost', 12345))\nexcept BlockingIOError:\n    pass\n\n# ...\n<\/code><\/pre>\n<p>In this code, the <code>setblocking(0)<\/code> method makes the socket non-blocking. The <code>connect()<\/code> method will now return immediately, and any subsequent <code>send()<\/code> or <code>recv()<\/code> calls will raise an <code>BlockingIOError<\/code> if the operation would block.<\/p>\n<p>Advanced usage of Python sockets can open up a wide range of possibilities for network communication. However, it also requires careful error handling and understanding of networking concepts.<\/p>\n<h2>Exploring Alternative Approaches: Twisted and asyncio<\/h2>\n<p>While Python sockets are a powerful tool for network communication, there are also third-party libraries that offer alternative approaches. Two such libraries are Twisted and asyncio.<\/p>\n<h3>Twisted: An Event-Driven Networking Engine<\/h3>\n<p>Twisted is an event-driven networking engine for Python. It supports a multitude of protocols, and includes a web server, an email server, and more. Here&#8217;s an example of a simple echo server using Twisted:<\/p>\n<pre><code class=\"language-python line-numbers\">from twisted.internet import protocol, reactor\n\nclass Echo(protocol.Protocol):\n    def dataReceived(self, data):\n        self.transport.write(data)\n\nclass EchoFactory(protocol.Factory):\n    def buildProtocol(self, addr):\n        return Echo()\n\nreactor.listenTCP(12345, EchoFactory())\nreactor.run()\n\n# Output:\n# Echo server is running on port 12345\n<\/code><\/pre>\n<p>In this code, <code>Echo<\/code> is a protocol that echoes any data it receives. <code>EchoFactory<\/code> is a factory that produces <code>Echo<\/code> instances. The <code>reactor<\/code> handles the event loop, listens on TCP port 12345, and runs the server.<\/p>\n<p>One advantage of Twisted is its extensive support for various protocols. However, its learning curve is steep, and its code can be difficult to understand for beginners.<\/p>\n<h3>asyncio: Asynchronous I\/O, Event Loop, Coroutines and Tasks<\/h3>\n<p>asyncio is a library for writing single-threaded concurrent code using coroutines, multiplexing I\/O access over sockets and other resources, running network clients and servers, and other related primitives. Here&#8217;s an example of a simple echo server using asyncio:<\/p>\n<pre><code class=\"language-python line-numbers\">import asyncio\n\nasync def handle_echo(reader, writer):\n    data = await reader.read(100)\n    message = data.decode()\n    addr = writer.get_extra_info('peername')\n\n    print(f'Received {message} from {addr}')\n\n    print(f'Send: {message}')\n    writer.write(data)\n    await writer.drain()\n\n    writer.close()\n\nasync def main():\n    server = await asyncio.start_server(\n        handle_echo, '127.0.0.1', 12345)\n\n    addr = server.sockets[0].getsockname()\n    print(f'Serving on {addr}')\n\n    async with server:\n        await server.serve_forever()\n\nasyncio.run(main())\n\n# Output:\n# Serving on ('127.0.0.1', 12345)\n# Received Hello, Server! from ('127.0.0.1', 52617)\n# Send: Hello, Server!\n<\/code><\/pre>\n<p>In this code, <code>handle_echo<\/code> is a coroutine that reads from a client, echoes back the message, and then closes the connection. The <code>main<\/code> coroutine starts the server and runs it forever.<\/p>\n<p>One advantage of asyncio is its native support for asynchronous I\/O, which can lead to more efficient use of resources. However, it requires careful handling of coroutines and tasks, and can be complex to use correctly.<\/p>\n<p>Both Twisted and asyncio offer powerful alternatives to Python sockets for network communication. Your choice between them, and Python sockets, will depend on your specific needs and your comfort with each library&#8217;s style and requirements.<\/p>\n<h2>Troubleshooting Python Sockets: Common Issues and Solutions<\/h2>\n<p>Working with Python sockets can sometimes lead to unexpected issues. Let&#8217;s discuss some common problems you might encounter, along with their solutions and workarounds.<\/p>\n<h3>Handling Connection Errors<\/h3>\n<p>One common issue is handling connection errors. This can happen if the server is not running, or if the client and server are not properly configured to connect to each other. Here&#8217;s how you can handle such errors:<\/p>\n<pre><code class=\"language-python line-numbers\">import socket\n\ntry:\n    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n    s.connect(('localhost', 12345))\nexcept socket.error as e:\n    print('Got an error:', e)\n\n# Output:\n# Got an error: [Errno 111] Connection refused\n<\/code><\/pre>\n<p>In this code, we use a try\/except block to catch any socket errors that occur when trying to connect to the server. If a connection error occurs, the error message is printed to the console.<\/p>\n<h3>Dealing with Timeouts<\/h3>\n<p>Another common issue is dealing with timeouts. This can happen if the server takes too long to respond. Here&#8217;s how you can set a timeout for a socket:<\/p>\n<pre><code class=\"language-python line-numbers\">import socket\n\ns = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\ns.settimeout(5)\n\ntry:\n    s.connect(('localhost', 12345))\nexcept socket.timeout:\n    print('Connection timed out')\n\n# Output:\n# Connection timed out\n<\/code><\/pre>\n<p>In this code, the <code>settimeout(5)<\/code> method sets a timeout of 5 seconds for the socket. If the <code>connect()<\/code> method takes longer than 5 seconds, a <code>socket.timeout<\/code> error is raised.<\/p>\n<h3>Resolving Data Encoding Issues<\/h3>\n<p>When sending and receiving data, you might encounter issues with data encoding. This can happen if you try to send a string over a socket, which expects data in bytes. Here&#8217;s how you can encode a string to bytes before sending it, and decode it back to a string after receiving it:<\/p>\n<pre><code class=\"language-python line-numbers\">import socket\n\ns = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\ns.connect(('localhost', 12345))\n\nmessage = 'Hello, Server!'\ns.send(message.encode())\ndata = s.recv(1024)\nprint('Received:', data.decode())\n\n# Output:\n# Received: Hello, Client!\n<\/code><\/pre>\n<p>In this code, the <code>encode()<\/code> method converts the string to bytes before sending it, and the <code>decode()<\/code> method converts the received bytes back to a string.<\/p>\n<p>By understanding these common issues and their solutions, you can avoid many pitfalls when working with Python sockets. Remember, error handling is a crucial part of network programming.<\/p>\n<h2>Understanding Python Sockets: TCP\/IP, UDP, Ports, and IP Addresses<\/h2>\n<p>To fully grasp Python sockets, it&#8217;s essential to understand the underlying concepts, including TCP\/IP, UDP, ports, and IP addresses.<\/p>\n<h3>Decoding TCP\/IP<\/h3>\n<p>TCP\/IP is the foundational communication protocol of the internet. It stands for Transmission Control Protocol\/Internet Protocol. Python sockets use TCP\/IP to establish reliable connections and exchange data between nodes.<\/p>\n<pre><code class=\"language-python line-numbers\">import socket\n\ns = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n<\/code><\/pre>\n<p>In this example, <code>socket.AF_INET<\/code> refers to the address family ipv4, and <code>socket.SOCK_STREAM<\/code> means that it is a TCP socket.<\/p>\n<p>TCP is a connection-oriented protocol, which means it ensures data is delivered successfully from sender to receiver. It provides error checking and error recovery, which makes it reliable for network communication.<\/p>\n<h3>Unveiling UDP<\/h3>\n<p>UDP, or User Datagram Protocol, is another protocol used for network communication. Unlike TCP, UDP is connectionless, meaning it doesn&#8217;t establish a connection before sending data.<\/p>\n<pre><code class=\"language-python line-numbers\">import socket\n\ns = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)\n<\/code><\/pre>\n<p>In this example, <code>socket.SOCK_DGRAM<\/code> means that it is a UDP socket. UDP is faster than TCP as it doesn&#8217;t provide the reliability checks that TCP does. It&#8217;s often used for live broadcasts and online games.<\/p>\n<h3>Ports and IP Addresses<\/h3>\n<p>An IP address is a unique address that identifies a device on a network. A port is a virtual point where network connections start and end. Ports act as communication endpoints for each specific process or service.<\/p>\n<pre><code class=\"language-python line-numbers\">s.connect(('localhost', 12345))\n<\/code><\/pre>\n<p>In this example, &#8216;localhost&#8217; is the host (an alias for the IP address 127.0.0.1, which refers to the current device), and 12345 is the port number.<\/p>\n<p>Understanding these fundamental concepts will give you a solid foundation for working with Python sockets. It will also help you troubleshoot issues and better understand network communication.<\/p>\n<h2>Python Sockets: Real-World Applications and Further Exploration<\/h2>\n<p>Python sockets are more than just a programming concept; they have real-world applications that affect our daily life. They are used in various areas, from web servers to chat applications, and even IoT devices.<\/p>\n<h3>Python Sockets in Web Servers<\/h3>\n<p>Web servers use Python sockets to listen for incoming connections from clients (web browsers). When a client makes a request, the server processes it, sends a response back to the client, and then closes the connection.<\/p>\n<pre><code class=\"language-python line-numbers\">import socket\n\ns = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\ns.bind(('localhost', 80))\ns.listen(1)\n\nwhile True:\n    client_connection, client_address = s.accept()\n    request = client_connection.recv(1024)\n    print(request.decode())\n\n    http_response = b\"\"\"\\\nHTTP\/1.1 200 OK\n\nHello, World!\\\n\"\"\"\n    client_connection.sendall(http_response)\n    client_connection.close()\n\n# Output:\n# GET \/ HTTP\/1.1\n# Host: localhost\n# ...\n<\/code><\/pre>\n<p>In this example, the server listens on port 80 (the standard port for HTTP), accepts incoming connections, prints the client&#8217;s request, sends a response, and then closes the connection.<\/p>\n<h3>Python Sockets in Chat Applications<\/h3>\n<p>Chat applications use Python sockets to facilitate real-time communication between users. The server listens for messages from clients and broadcasts them to all connected clients.<\/p>\n<h3>Exploring Related Concepts: Multithreading and Encryption<\/h3>\n<p>As you delve deeper into network programming with Python, you might want to explore related concepts such as multithreading and encryption.<\/p>\n<p>Multithreading can be used to handle multiple connections simultaneously, which is essential for building scalable servers. Encryption, on the other hand, ensures secure communication by encrypting the data before sending it over the network.<\/p>\n<h3>Further Resources for Mastering Python Sockets<\/h3>\n<p>To continue your journey in mastering Python sockets, here are some additional resources that you might find helpful:<\/p>\n<ul>\n<li><a class=\"wp-editor-md-post-content-link\" href=\"https:\/\/ioflood.com\/blog\/python-modules\/\">Python Modules: A Comprehensive Overview<\/a> &#8211; Explore the world of Python modules for code organization and reuse.<\/p>\n<\/li>\n<li>\n<p><a class=\"wp-editor-md-post-content-link\" href=\"https:\/\/ioflood.com\/blog\/python-unzip\/\">Simplifying File Decompression with Python Unzip<\/a> &#8211; Discover techniques for extracting files from zip archives in Python.<\/p>\n<\/li>\n<li>\n<p><a class=\"wp-editor-md-post-content-link\" href=\"https:\/\/ioflood.com\/blog\/using-python-heapq-module-for-heaps-and-priority-queues\/\">Python heapq Module: Priority Queues and Heaps Explained<\/a> &#8211; Reference guide for Python&#8217;s &#8220;heapq&#8221; module.<\/p>\n<\/li>\n<li>\n<p><a class=\"wp-editor-md-post-content-link\" href=\"https:\/\/docs.python.org\/3\/library\/socket.html\" target=\"_blank\" rel=\"noopener\">Python&#8217;s Official Documentation on Socket Programming<\/a> dives into socket programming for networking applications.<\/p>\n<\/li>\n<li>\n<p><a class=\"wp-editor-md-post-content-link\" href=\"https:\/\/realpython.com\/python-sockets\/\" target=\"_blank\" rel=\"noopener\">Socket Programming in Python<\/a> &#8211; An in-depth guide from Real Python on the basics and of socket programming.<\/p>\n<\/li>\n<li>\n<p><a class=\"wp-editor-md-post-content-link\" href=\"https:\/\/www.geeksforgeeks.org\/socket-programming-python\/\" target=\"_blank\" rel=\"noopener\">Tutorial on Socket Programming in Python<\/a> by GeeksforGeeks simplifies Python socket programming with examples.<\/p>\n<\/li>\n<\/ul>\n<p>Each of these resources provides a wealth of information on Python sockets, including more in-depth explanations, examples, and advanced topics. Happy learning!<\/p>\n<h2>Wrapping Up: Python Socket Mastery<\/h2>\n<p>In this comprehensive guide, we&#8217;ve explored the world of <code>Python sockets<\/code>, a critical tool for network communication in Python.<\/p>\n<p>We&#8217;ve journeyed from the basics to advanced usage, delving into creating sockets, connecting to servers, and sending and receiving data. We&#8217;ve also highlighted the importance of error handling, particularly for connection errors and timeouts.<\/p>\n<p>We&#8217;ve ventured into more complex uses, such as creating servers, handling multiple connections, and working with non-blocking sockets. We&#8217;ve also discovered alternative approaches to network communication using third-party libraries like <code>Twisted<\/code> and <code>asyncio<\/code>.<\/p>\n<p>Here&#8217;s a quick comparison of these approaches:<\/p>\n<table>\n<thead>\n<tr>\n<th>Approach<\/th>\n<th>Advantages<\/th>\n<th>Disadvantages<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Python Sockets<\/td>\n<td>High degree of control, Built-in module<\/td>\n<td>Can be tricky for beginners<\/td>\n<\/tr>\n<tr>\n<td>Twisted<\/td>\n<td>Supports many protocols, Includes servers<\/td>\n<td>Steep learning curve<\/td>\n<\/tr>\n<tr>\n<td>asyncio<\/td>\n<td>Efficient use of resources, Built-in module<\/td>\n<td>Complex to use correctly<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>We&#8217;ve also discussed the underlying fundamentals of Python sockets, including <code>TCP\/IP<\/code>, <code>UDP<\/code>, <code>ports<\/code>, and <code>IP addresses<\/code>. Additionally, we&#8217;ve looked at the real-world applications of Python sockets, such as in web servers and chat applications, and suggested further resources for deepening your understanding.<\/p>\n<p>In mastering Python sockets, you&#8217;re not only gaining a powerful tool for your Python projects, but also stepping into the broader world of network communication. It&#8217;s a journey that can open up countless possibilities for your coding future.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Are you finding it challenging to get a grip on Python sockets? Think of Python sockets like a virtual postman. They are the key to enabling communication between two nodes on a network. Whether you are a beginner just dipping your toes into the world of Python sockets or an advanced user looking to refine [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":11081,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[121,123],"tags":[],"class_list":["post-4549","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-programming-coding","category-python","cat-121-id","cat-123-id","has_thumb"],"_links":{"self":[{"href":"https:\/\/ioflood.com\/blog\/wp-json\/wp\/v2\/posts\/4549","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ioflood.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ioflood.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ioflood.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ioflood.com\/blog\/wp-json\/wp\/v2\/comments?post=4549"}],"version-history":[{"count":7,"href":"https:\/\/ioflood.com\/blog\/wp-json\/wp\/v2\/posts\/4549\/revisions"}],"predecessor-version":[{"id":16937,"href":"https:\/\/ioflood.com\/blog\/wp-json\/wp\/v2\/posts\/4549\/revisions\/16937"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ioflood.com\/blog\/wp-json\/wp\/v2\/media\/11081"}],"wp:attachment":[{"href":"https:\/\/ioflood.com\/blog\/wp-json\/wp\/v2\/media?parent=4549"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ioflood.com\/blog\/wp-json\/wp\/v2\/categories?post=4549"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ioflood.com\/blog\/wp-json\/wp\/v2\/tags?post=4549"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}