xfeng

xfeng

Sporting | Reading | Technology | Recording
github
bilibili

Basics of Golang Network Programming

image

1. Overview#

Network programming is actually a vast field, and this article simply demonstrates how to use Golang's networking package for communication.

  • TCP socket programming (the mainstream of network programming, based on TCP/IP at the lower level)
  • B/S structure HTTP programming (when accessing websites using a browser, the HTTP protocol is used, which is also implemented using TCP sockets at the lower level)

TCP socket programming:

  • Server processing flow:
    • Listen on a port
    • Accept TCP requests from clients and establish a connection with the client
    • Create a goroutine to handle the requests for that connection
  • Client processing flow:
    • Establish a connection with the server
    • Send request data and receive the results returned by the server
    • Close the connection

2. Internet Layered Model#

The logical implementation of the Internet is divided into several layers, each responsible for its own content, just like a building, where each layer requires support from the layer below. Most of what we usually encounter is the topmost layer, which is encapsulated layer by layer and presented to us in the most user-friendly way.

image

image

3. Several Core Network Packages#

3.1 net#

The net.Dial() method is used for client network connections.

The net.Listen() method is used for the server to accept network connections.

3.2 net/http#

The net/http package provides functions for developing powerful web servers and clients.

The http.Get() and https.Get() methods can be used as clients to send HTTP and HTTPS requests.

The http.ListenAndServe() method can be used to create a web server, specifying the IP address and TCP port number for the server to listen on, and then handle incoming requests in that method.

3.3 http.RoundTripper#

RoundTripper can be seen as middleware for http.Client.

Usage scenarios:

  • Caching HTTP responses (if cache exists, retrieve directly from cache)
  • Setting appropriate HTTP headers
  • Rate limiting

Reference link

4. Go Implementation of DNS Query#

The role of DNS (Domain Name System) is to convert IP addresses to domain names or to convert domain names to IP addresses.

package main
import (
	"fmt"
	"net"
	"os"
)
func main() {
	arguments := os.Args
	if len(arguments) == 1 {
		fmt.Println("Please provide an argument!")
		return
	}
	input := arguments[1]
	IPaddress := net.ParseIP(input)  // The function net.ParseIP parses the input string into an IP address
	if IPaddress == nil {
		IPs, err := lookHostname(input)
		if err == nil {
			for _, singleIP := range IPs {
				fmt.Println(singleIP)
			}
		}
	} else {
		hosts, err := lookIP(input)
		if err == nil {
			for _, hostname := range hosts {
				fmt.Println(hostname)
			}
		}
	}
}
func lookIP(address string) ([]string, error) {
	hosts, err := net.LookupAddr(address) // Returns a list of hosts matching the provided IP address (/etc/hosts)
	if err != nil {
		return nil, err
	}
	return hosts, nil
}
func lookHostname(hostname string) ([]string, error) {
	IPs, err := net.LookupHost(hostname) // Returns a list of IP addresses matching the provided hostname
	if err != nil {
		return nil, err
	}
	return IPs, nil
}

5. Go Implementation of Web Functionality#

You can use Go's standard library functions to implement a web server.

If you need a truly powerful web server, it is still recommended to use web servers like Apache or Nginx.

5.1 Web Server#

package main
import (
	"fmt"
	"net/http"
	"os"
	"time"
)
func main() {
	PORT := ":8001"
	arguments := os.Args
	if len(arguments) == 1 {
		fmt.Println("Using default port number: ", PORT)
	}else{
		PORT = ":" + arguments[1]
	}
	http.HandleFunc("/time", timeHandler) // Associate a URL route with a handler function
	http.HandleFunc("/", myHandler)
	err := http.ListenAndServe(PORT, nil)
	if err != nil {
		fmt.Println(err)
		return
	}
}
func myHandler(w http.ResponseWriter, r *http.Request) { 
	fmt.Fprintf(w, "Serving: %s\n", r.URL.Path)
	fmt.Printf("Served: %s\n", r.Host)
}
func timeHandler(w http.ResponseWriter, r *http.Request) { 
	t := time.Now().Format(time.RFC1123)
	Body := "The current time is:" // Dynamic output
	fmt.Fprintf(w, "<h1 align=\"center\">%s</h1>", Body)
	fmt.Fprintf(w, "<h2 align=\"center\">%s</h2>\n", t)
	fmt.Fprintf(w, "Serving: %s\n", r.URL.Path)
	fmt.Fprintf(w, "Served time for: %s\n", r.Host)
}

5.2 Web Client#

package main
import (
	"fmt"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"time"
)
func main() {
	if len(os.Args) != 2 {
		fmt.Printf("Usage: %s URL\n", filepath.Base(os.Args[0]))
		return
	}
	URL, err := url.Parse(os.Args[1]) // Parse the provided URL
	if err != nil {
		fmt.Println("Error in parsing:", err)
		return
	}
	c := &http.Client{
		Timeout: 15 * time.Second,
	}
	request, err := http.NewRequest("GET", URL.String(), nil)
	if err != nil {
		fmt.Println("Get:", err)
		return
	}
	httpData, err := c.Do(request)
	if err != nil {
		fmt.Println("Error in Do():", err)
		return
	}
	fmt.Println("Status code:", httpData.Status)
	header, _ := httputil.DumpResponse(httpData, false)
	fmt.Println(string(header))
	contentType := httpData.Header.Get("Content-Type")
	characterSet := strings.SplitAfter(contentType, "charset=")
	if len(characterSet) > 1 {
		fmt.Println("Character Set:", characterSet[1])
	}
	if httpData.ContentLength == -1 {
		fmt.Println("ContentLength is unknown!")
	} else {
		fmt.Println("ContentLength:", httpData.ContentLength)
	}
	length := 0
	var buffer [1024]byte
	r := httpData.Body
	for {
		n, err := r.Read(buffer[0:])
		if err != nil {
			fmt.Println(err)
			break
		}
		length = length + n
	}
	fmt.Println("Calculated response data length:", length)
}

6. Go Implementation of TCP Functionality#

6.1 TCP Server#

package main
import(
	"bufio"
	"fmt"
	"net"
	"os"
	"strings"
	"time"
)
func main() {
	arguments := os.Args
	if len(arguments) == 1 {
		fmt.Println("Please provide port number")
		return
	}
	PORT := ":" + arguments[1]
	l, err := net.Listen("tcp" , PORT)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer l.Close()
	c, err := l.Accept()
	if err != nil {
		fmt.Println(err)
		return
	}
	for {
		netData, err := bufio.NewReader(c).ReadString('\n')
		if err != nil {
			fmt.Println(err)
			return
		}
		if strings.TrimSpace(string(netData)) == "STOP" {
			fmt.Println("Exiting TCP server!")
			return
		}
		fmt.Print("-> ", string(netData))
		t := time.Now()
		myTime := t.Format(time.RFC3339) + "\n"
		c.Write([]byte(myTime))
	}
}

6.2 TCP Client#

package main
import (
	"bufio"
	"fmt"
	"net"
	"os"
	"strings"
)
func main(){
	arguments := os.Args
	if len(arguments) == 1 {
		fmt.Println("Please provide host:port.")
		return
	}
	CONNECT := arguments[1]
	c, err := net.Dial("tcp", CONNECT)
	if err != nil {
		fmt.Println(err)
		return
	}
	for {
		reader := bufio.NewReader(os.Stdin)
		fmt.Print(">> ")
		text, _ := reader.ReadString('\n')
		fmt.Fprintf(c, text + "\n")
		message, _ := bufio.NewReader(c).ReadString('\n')
		fmt.Print("->: " + message)
		if strings.TrimSpace(string(text)) == "STOP" {
			fmt.Println("TCP client exiting...")
			return
		}
	}
}

7. Go Implementation of UDP Functionality#

7.1 UDP Server#

package main

import (
	"fmt"
	"net"
)

func main() {
	// Create listener
	socket, err := net.ListenUDP("udp4", &net.UDPAddr{
		IP:   net.IPv4(0, 0, 0, 0),
		Port: 8080,
	})
	if err != nil {
		fmt.Println("Listening failed!", err)
		return
	}
	defer socket.Close()

	for {
		// Loop to read data
		data := make([]byte, 4096)
		read, remoteAddr, err := socket.ReadFromUDP(data)
		if err != nil {
			fmt.Println("Failed to read data!", err)
			continue
		}
		fmt.Println(read, remoteAddr)
		fmt.Printf("%s\n\n", data)

		// Send data
		senddata := []byte("hello client!")
		_, err = socket.WriteToUDP(senddata, remoteAddr)
		if err != nil {
			return
			fmt.Println("Failed to send data!", err)
		}
	}
}

7.2 UDP Client#

package main

import (
	"fmt"
	"net"
)

func main() {
	// Create connection
	socket, err := net.DialUDP("udp4", nil, &net.UDPAddr{
		IP:   net.IPv4(192, 168, 110, 110),
		Port: 8080,
	})
	if err != nil {
		fmt.Println("Connection failed!", err)
		return
	}
	defer socket.Close()

	// Send data
	senddata := []byte("hello server!")
	_, err = socket.Write(senddata)
	if err != nil {
		fmt.Println("Failed to send data!", err)
		return
	}

	// Receive data
	data := make([]byte, 4096)
	read, remoteAddr, err := socket.ReadFromUDP(data)
	if err != nil {
		fmt.Println("Failed to read data!", err)
		return
	}
	fmt.Println(read, remoteAddr)
	fmt.Printf("%s\n", data)
}

8. Summary#

This article mainly introduces the Golang version of web servers, clients, TCP servers, clients, and UDP servers, clients, as well as the concept of network layering, the Golang version of DNS queries, and several network packages.

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.