Covering networking concepts, HTTP communication, and process management.
full lessons here👇:
https://programmerscareer.com/golang-basic-skill/
Generated by AI, there may be errors, for reference only
Topic: 0.1 Understanding of Basic Networking
Starting from basics often makes the learning process more productive. Even if you’re already familiar with the subject matter, a quick refresher can help reinforce your understanding.
Computer networks are comprised of many computers that are connected to each other for the purpose of sharing resources and data.
The most common types of computer networks are:
- Local Area Network (LAN): A network that is confined to a relatively small area. It’s usually confined to a single building, such as a home, office, or a group of buildings.
- Wide Area Network (WAN): A network that spans a large physical distance. The internet is a WAN.
A basic understanding of networking protocols is also crucial. A protocol is a set of rules that dictate how data should be transferred over the network.
Internet Protocol(IP), Transmission Control Protocol(TCP), and User Datagram Protocol(UDP) are some of the fundamental protocols you must understand.
In Go, the ‘net’ package presents a general interface for network I/O, including TCP/IP, UDP, domain name resolution, and Unix domain sockets.
These networking concepts will be the foundation as we venture deeper into how Go handle HTTP communication, and manage processes.
Topic: 0.2 Introduction to the Golang Net Package
Go’s standard library comes with excellent support for HTTP. The net/http
package provides functionalities for building HTTP clients and servers. However, before diving into HTTP, the foundational package that deals with network calls is ‘net’.
The ‘net’ package in Go provides a portable interface for network I/O, including TCP/IP, UDP, domain name resolution, and Unix domain sockets.
Let’s take a quick look at functions provided by the ‘net’ package that we will use:
- Dial: The Dial function connects to the address on the named network.
1 | conn, err := net.Dial("tcp", "golang.org:80") |
- Listen: Listen announces on the local network address. You would use this to create a server that listens for incoming connections.
1 | ln, err := net.Listen("tcp", ":8080") |
- Accept: And this is how you wait for and return the next connection to the listener.
1 | conn, err := ln.Accept() |
Don’t worry if it seems overwhelming the first time. In the next sections, we’ll dive into more specifics and play around with these functions a lot more.
Topic: 0.3 Introduction to HTTP
HTTP stands for Hypertext Transfer Protocol, which is the foundation for any data exchange on the Web. HTTP is a protocol used globally for transmission of hypertext over the internet.
The key feature of HTTP includes:
- Statelessness: HTTP is stateless, which means that each client request is an independent one. Server and client do not preserve data between different requests.
- Media Independent: As long as a client can interpret the data, any type of media file can be sent by HTTP.
HTTP works as a request-response protocol between a client and a server, including browsers, mobile applications, and other servers are the typical HTTP clients. Whenever an HTTP request is made by a client, the server responds with an HTTP response.
In Go, creating an HTTP server is made easy with its standard ‘net/http’ package by granting us the ListenAndServe
function.
We can also make HTTP requests via the ‘http.Client’, ‘http.NewRequest’ and ‘http.Do’ commands.
Go features a really powerful http package that provides all the necessary utilities needed to run HTTP servers or make client-side HTTP requests. We’ll examine how to work with Go’s ‘http’ package in the upcoming segments as we go hands-on with code and examples.
Topic: 1.1 HTTP Client
Go’s ‘net/http’ package provides methods for performing HTTP requests. In this first part of our HTTP module, we will cover the basics of sending GET requests, which are one of the most common types of HTTP requests.
Here is a basic example of sending a GET request:
1 | package main |
In this example, we’re making a GET request to “http://example.com“. The http.Get
function makes a request to the provided URL and returns the response and any errors.
The resp.Body
contains the server’s response to the request. The ioutil.ReadAll
function reads all the data from the response body. We then print the body of the response to the console.
The defer resp.Body.Close()
line is crucial. It ensures that the network connection established for the request will be closed after the function finishes, not immediately. This is a good practice because reusing connections in the pool improves performance.
I hope you found this start to our HTTP Client lesson helpful. Remember, practice is beneficial so feel free to try coding a GET request to familiarize yourself with the process.
When we send an HTTP request, we receive an HTTP response. An HTTP response is made of the following parts:
- Status line: It includes the HTTP version, a status code, and a status message.
- Headers: They provide more information about the response or the request. In Go, they are available as a
map[string][]string
in theHeader
field of thehttp.Response
struct. - Body: This is the actual data (content) returned by the server.
When we make a request with http.Get()
, we get a pointer to an http.Response
. Here’s an example of how to access these fields:
1 | resp, _ := http.Get("http://example.com/") |
It’s important to remember, as before, to close the response body when you’re done with it:
1 | defer resp.Body.Close() |
With all this new knowledge, you can inspect your HTTP responses more accurately when creating a client in Go.
Topic: 1.2 HTTP Server
In Go, we can build a robust web server using the net/http
package. We can create RESTful services, serve static files, use dynamic routes and the list goes on. For the sake of this lesson, let’s focus on creating a simple web server.
1 | package main |
In this simple example, ‘http.HandleFunc’ tells the http package to handle all requests to the web root (“/”) with ‘handler’.
The ‘handler’ function receives two parameters: an ‘http.ResponseWriter’ and an ‘http.Request’. The ‘http.ResponseWriter’ is where you write your text/html response to and ‘http.Request’ is the data structure that represents the client HTTP request.
‘fmt.Fprintf’ then assembles the HTTP server’s response; in this case, it’s just a string that we send down to the client.
Finally, ‘http.ListenAndServe’: This function listens at the specified port until the program is terminated. In our case it’s port 8080.
In reality, servers are not often used for sending a “Hello, World” message. Instead, they are used to send dynamic contents that change based on specific situations or parameters.
To illustrate this, we’re going to look at a simple example of how to handle HTTP POST requests.
1 | // Global variable to simulate a database. |
The code creates a form asking for a name. When you submit the form, it makes a POST request to ‘/submit’. This request handler retrieves the name from POST data and stores it.
Topic: 1.3 Context Package in Go
The context package in Go is typically used in routines that may need to be canceled or timed out. A common theme during concurrent programming in Go is the ability to manage long-lived and short-lived worker routines. The need arises in scenarios like processing streams of data that can last indefinitely or managing automated tasks that can be triggered to stop on certain conditions such as a calculated result being reached, an error occurring, prerequisites not being met, etc.
The context package provides a standardized interface to define parent-child relationships between routines, and propagates deadlines, cancellation signals, and other information required to handle the tasks effectively.
Let’s take a look at an example of how contexts can be used:
1 | package main |
In this example, we initialized a new background context ctx
and then created a new context that is automatically canceled after 3 seconds using context.WithTimeout(ctx, 3*time.Second)
. The cancel function returned by context.WithTimeout
is called using defer
to ensure resources are cleaned up properly.
The function go func(ctx context.Context)
represents a worker routine that performs a task every second indefinitely until a cancel signal is received. In this case, it’s canceled when the context timeout of 3 seconds is reached.
Topic: 1.4 Processes in Go
In the computing world, a process is an instance of a computer program that is executing. It contains the program code and its current activity. In Go, a process can be started by using the ‘os/exec’ package.
Here’s a simple code snippet that shows how to start a process in Go:
1 | package main |
Here’s what happening in this code:
exec.Command("ls")
prepares a command to execute. It’s like typingls
in a terminal but it’s not running the command yet.cmd.Output()
actually runs the command and waits for it to finish. It returns the standard output and a value of Go’s built-in interface type ‘error’.
This program will therefore print the contents of your current directory, somewhat like the ls
command in Unix-based systems.
Go offers a powerful set of tools for process management. In simple terms, process management in any language involves keeping track of and controlling the processes we’ve started. It’s all about knowing what’s happening with your program.
Let’s consider this example where we start a process (Sleep 5 seconds), then stop it before it completes.
1 | package main |
In this script:
cmd.Start()
starts the process, but it does not wait for it to complete.time.AfterFunc
creates a timer that executes a function after a certain duration (2 seconds in this case).cmd.Process.Kill()
forcibly stops the process. Note that there’s also a gracefulcmd.Process.Signal
function that allows the process to cleanup before it exits.cmd.Wait()
waits for the process to finish.
Topic 1.5: Signals in Go
In an operating system, a signal is a software interrupt delivered to a process. A process can use these signals to trigger certain behaviors. For example, when a program is running in a terminal, hitting ctrl+c sends an interrupt signal, usually causing the program to terminate.
In Go, we can decide what to do when our programs receive signals using the os/signal
package. This can allow us to gracefully stop a program, performing any cleanup that might be required before stopping.
Here’s an example:
1 | package main |
In this program:
- We first create a channel to receive signals.
- We use
signal.Notify
to relay incoming signals to the channel. We’re specifically looking forSIGINT
(sent by pressing ctrl+c) andSIGTERM
(a termination request sent to the program). - When a signal is received, it’s printed out and then “true” is sent over the done channel to indicate that we’re ready to exit.
This way, interruption can be gracefully handled by saving progression, freeing resources, finishing important operations, or asking for user confirmation before exiting.
Topic 1.6: Clean Exit in Go
In any properly structured program, there’s always the requirement to free up resources that the program has consumed before it ends. These resources may include opened files, database connections, network connections, or allocated memory. Go provides us with the defer
statement which helps us in automatically managing this.
The key idea behind the defer
statement is that it allows us to delay the execution of a function until the enclosing function returns, no matter how it returns.
Consider this common situation wherein we open a file, perform some operation on it, and then close it:
1 | func main() { |
Now, let’s suppose an error occurs during the file operations and we return from the function prematurely. In this situation, the Close function will never be called, leading to a file descriptor leak. This is where defer
can come into play:
1 | func main() { |
In the revised version, f.Close()
will be executed every time the function encloses, no matter where it encloses. This ensures that we’re not leaving any resources hanging.
Topic: 1.7 Review and Practice
Let’s have a brief recap:
- HTTP Client: We journeyed through making HTTP requests using the ‘net/http’ standard library in Go, and learned how to get and post data.
- HTTP Server: We delved into how to design an HTTP server and handle incoming requests.
- Context in Go: We discovered how to handle and manage long-running processes using the context package.
- Processes in Go: We took a peek at how to create and manage processes in Go.
- Signals in Go: We explored handling system signals for a graceful shutdown of the application.
- Clean Exit in Go: We learned about resource cleanup before application termination, and you made acquaintance with
defer
keyword.
Now, to put this knowledge into practice, let’s work on a couple of exercises:
- Create an HTTP server in Go which listens on port 8080 and responds to the
/ping
route with aPong!
. - Create an HTTP client in Go which sends an HTTP GET request to an API endpoint.
- Write a Go function, which runs an infinite loop, but exists gracefully on receiving a shutdown signal (
SIGINT
orSIGTERM
). - Develop a simple Go script which opens a file, writes something to it, and then closes it, ensuring that the file gets closed even if an error occurs during the write operation.
If you encounter any issues while solving these exercises or if you want to clarify something we’ve studied, please don’t hesitate to ask.
Topic: 1.8 Assessments
It’s essential to know precisely where you stand in order to improve. To this end, we’ve prepared a unique set of questions for you to answer. Some may be challenging, but we’re confident you can handle them.
Questions:
- You are required to write a REST API in Go. This API consists of a
GET
endpoint that retrieves a user’s data from the database. Describe how you would design this endpoint. - How would you handle timeouts on long-running http requests in Go?
- Suppose your Go application has a long-running Goroutine that needs to be stopped under certain conditions. How would you design your code to stop this Goroutine gracefully?
- What happens if your Go application receives an
SIGKILL
signal? Can you handle such a signal in your code? - You have an open file in your Go application. Now due to some unexpected error, your application panics. How would you ensure that the file is closed before the application exits?
Take your time to think carefully about each question and provide thoughtful answers. Remember, it’s not about speed; it’s about concept understanding and being thorough!
中文文章: https://programmerscareer.com/zh-cn/go-basic-15/
Author: Wesley Wei – Twitter Wesley Wei – Medium
Note: If you choose to repost or use this article, please cite the original source.
Comments