Network programming is an indispensable technical field in the modern Internet. In Golang, we can easily build efficient network communication applications.
In Golang, we can use the net package
in the standard library to implement network programming. The net package
has many common network protocols and functions, such as TCP, UDP, HTTP, etc.
1. TCP server and client
Server:
package main import ( "net" "fmt" ) func main() {<!-- --> listen, err := net.Listen("tcp", ":8080") if err != nil {<!-- --> fmt.Println(err) return } defer listen.Close() for {<!-- --> conn, err := listen.Accept() if err != nil {<!-- --> continue } go handleConnection(conn) // Use new goroutine for each connection to improve concurrency } } func handleConnection(conn net.Conn) {<!-- --> defer conn.Close() buf := make([]byte, 1024) n, err := conn.Read(buf) if err != nil {<!-- --> return } msg := string(buf[:n]) fmt.Println("Received message:", msg) //Send data to client conn.Write([]byte("Server response")) }
We can use the telnet tool to connect to the server
$ telnet localhost 8080 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. Hello, server! Server response
The client sends a message to the server, and the server receives the message and sends a response.
Client:
func main() {<!-- --> //Connect to port 8080 conn, err := net.Dial("tcp", "localhost:8080") if err != nil {<!-- --> fmt.Println(err) return } defer conn.Close() //Send data to server conn.Write([]byte("Hello, server!")) buffer := make([]byte, 1024) \t //Read the server's response information conn.Read(buffer) fmt.Println(string(buffer)) }
2. UDP server and client
Unlike TCP, UDP is connectionless. Below is the implementation of UDP server and client.
Server:
package main import ( "net" "fmt" ) func main() {<!-- --> conn, err := net.ListenPacket("udp", ":8080") if err != nil {<!-- --> fmt.Println(err) return } defer conn.Close() buffer := make([]byte, 1024) // read data n, addr, err := conn.ReadFrom(buffer) if err != nil {<!-- --> fmt.Println(err) return } fmt.Println("Received: ", string(buffer[:n])) //Send data to the specified address conn.WriteTo([]byte("Message received!"), addr) }
Client:
func main() {<!-- --> addr, err := net.ResolveUDPAddr("udp", "localhost:8080") if err != nil {<!-- --> fmt.Println(err) return } \t conn, err := net.DialUDP("udp", nil, addr) if err != nil {<!-- --> return } defer conn.Close() // Write a message to the server. conn.Write([]byte("Hello, server!")) buffer := make([]byte, 1024) // Read the response from the server. conn.Read(buffer) fmt.Println(string(buffer)) }
The server reads messages from any client and sends responses. The client sends the message and waits for a response.
3. HTTP Programming
package main import ( "fmt" "net/http" ) func main() {<!-- --> http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {<!-- --> fmt.Fprintf(w, "Hello, client!") }) err := http.ListenAndServe(":1234", nil) if err != nil {<!-- --> fmt.Println("Error:", err) return } }
Use the curl tool to send an HTTP request to the server:
$ curl http://localhost:1234 Hello, client!
Gorilla Mux library simplifies HTTP request routing:
package main import ( "fmt" "github.com/gorilla/mux" "net/http" ) func main() {<!-- --> r := mux.NewRouter() r.HandleFunc("/", homeHandler) http.ListenAndServe(":8080", r) } func homeHandler(w http.ResponseWriter, r *http.Request) {<!-- --> fmt.Fprint(w, "Welcome to Home!") }
4. HTTPS server
package main import ( "net/http" "log" ) func main() {<!-- --> http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {<!-- --> w.Write([]byte("Hello, this is an HTTPS server!")) }) // Use the cert.pem and key.pem files to secure the server. http.ListenAndServeTLS(":8080", "cert.pem", "key.pem", nil) }
Implementing an HTTPS server ensures secure communication. The server uses TLS (Transport Layer Security) to encrypt communications.
5. WebSocket communication
Using the Gorilla websocket library
WebSockets provide real-time, full-duplex communication over a single connection.
package main import ( "github.com/gorilla/websocket" "net/http" ) var upgrader = websocket.Upgrader{<!-- --> ReadBufferSize: 1024, WriteBufferSize: 1024, } func handler(w http.ResponseWriter, r *http.Request) {<!-- --> conn, err := upgrader.Upgrade(w, r, nil) if err != nil {<!-- --> http.Error(w, "Could not open websocket connection", http.StatusBadRequest) return } defer conn.Close() for {<!-- --> messageType, p, err := conn.ReadMessage() if err != nil {<!-- --> return } conn.WriteMessage(messageType, p) } } func main() {<!-- --> http.HandleFunc("/", handler) http.ListenAndServe(":8080", nil) }
6. Connection timeout
Connection timeouts can be managed using the context
package.
package main import ( "context" "fmt" "net" "time" ) func main() {<!-- --> // Create a context with a timeout of 2 seconds ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() // Dialer using the context dialer := net.Dialer{<!-- -->} conn, err := dialer.DialContext(ctx, "tcp", "localhost:8080") if err != nil {<!-- --> panic(err) } buffer := make([]byte, 1024) _, err = conn.Read(buffer) if err == nil {<!-- --> fmt.Println("Received:", string(buffer)) } else {<!-- --> fmt.Println("Connection error:", err) } }
7. Rate Limiting
Use golang.org/x/time/rate
for rate limiting
package main import ( "golang.org/x/time/rate" "net/http" "time" ) var limiter = rate.NewLimiter(2, 5) func handler(w http.ResponseWriter, r *http.Request) {<!-- --> if !limiter.Allow() {<!-- --> http.Error(w, "Too Many Requests", http.StatusTooManyRequests) return } w.Write([]byte("Welcome!")) } func main() {<!-- --> http.HandleFunc("/", handler) http.ListenAndServe(":8080", nil) }
This example uses a rate limiter to limit the request rate to two requests per second with a burst capacity of five.