Why Go is the Ideal Language for Network Programming?
\n\nIf you've ever written a network server in Python (especially using socket or asyncio), you know how quickly code can turn into a maze of callbacks and event loops. Go (Golang) solves this problem at the architectural level: goroutines and channels make asynchronous network work as simple as writing sequential code.
In this article, we'll explore network programming in Go in practice. You'll learn how to build a full-fledged TCP chat in 15 minutes, send a UDP packet, and launch an HTTP server with routing. All examples are working and can be copied and run.
\n\nBasics: The net Package and Its Superpower
\n\nIn Go, all the network magic lives in the standard net package. It provides a unified interface for working with TCP, UDP, Unix sockets, and even SSL/TLS. The main feature is that the Listen, Dial, and Accept functions work synchronously but don't block the entire program because each goroutine is lightweight.
Let's get straight to the point.
\n\nTCP Server: A Chat in 10 Lines
\n\nLet's create a simple echo server that accepts connections and sends back what it received. This is a classic of network programming in Go.
\n\npackage main\n\nimport (\n "bufio"\n "fmt"\n "net"\n)\n\nfunc handleConnection(conn net.Conn) {\n defer conn.Close()\n scanner := bufio.NewScanner(conn)\n for scanner.Scan() {\n message := scanner.Text()\n fmt.Printf("Received: %s\\n", message)\n conn.Write([]byte("Echo: " + message + "\\n"))\n }\n}\n\nfunc main() {\n listener, _ := net.Listen("tcp", ":8080")\n fmt.Println("TCP server started on :8080")\n for {\n conn, _ := listener.Accept()\n go handleConnection(conn) // each goroutine is a separate client\n }\n}\n\nWhat's happening here?
\n- \n
net.Listen("tcp", ":8080")— creates a TCP listener on port 8080. \n - The infinite
forloop accepts new connections viaAccept(). \n - Each connection is handled in a separate goroutine
go handleConnection(). \n - Inside the function, we read lines using
bufio.Scannerand send a response. \n
Run this code, open a terminal, and connect via nc localhost 8080 (or Putty). Any message will be returned with the prefix "Echo:". Surprisingly, this is already a full-fledged network server capable of serving thousands of clients without a single callback.
UDP: Fast Delivery Without Guarantees
\n\nIf TCP is like a phone call (established a connection — we talk), then UDP is like postcards: sent and forgotten. Go makes working with UDP just as simple.
\n\nUDP Client and Server
\n\n// Server\npackage main\n\nimport (\n "fmt"\n "net"\n)\n\nfunc main() {\n addr, _ := net.ResolveUDPAddr("udp", ":8081")\n conn, _ := net.ListenUDP("udp", addr)\n defer conn.Close()\n\n buffer := make([]byte, 1024)\n for {\n n, clientAddr, _ := conn.ReadFromUDP(buffer)\n message := string(buffer[:n])\n fmt.Printf("Received from %s: %s\\n", clientAddr, message)\n conn.WriteToUDP([]byte("Acknowledged: "+message+"\\n"), clientAddr)\n }\n}\n\n// Client\n// In a separate file or goroutine:\nconn, _ := net.Dial("udp", "localhost:8081")\ndefer conn.Close()\nconn.Write([]byte("Hello, UDP!"))\nbuffer := make([]byte, 1024)\nn, _ := conn.Read(buffer)\nfmt.Println(string(buffer[:n]))\n\nKey difference from TCP:
\n- \n
- No
Accept()— we simply listen on a port and read datagrams. \n - Each packet comes with its own sender address. \n
- Go manages buffering itself:
ReadFromUDPBlogs
Book Recommendations
Read also
Metaprogramming in JavaScript: The Magic of Proxy, Reflect, and Symbol
Microservices in Rust: Architecture, Practice, and Code Examples
Go as Glue: Integration with Python, C and Other Languages
Deploying Rust on Kubernetes: A Practical Basic Guide
Taming Dependencies: How to Install a Specific Version of a Composer Package