Golang TCP網(wǎng)絡(luò)編程的具體實(shí)現(xiàn)
網(wǎng)絡(luò)編程介紹
網(wǎng)絡(luò)編程介紹
- 網(wǎng)絡(luò)編程是指通過(guò)計(jì)算機(jī)網(wǎng)絡(luò)實(shí)現(xiàn)程序間通信的一種編程技術(shù),涉及到在不同計(jì)算機(jī)之間建立連接、傳輸數(shù)據(jù)和協(xié)議解析等操作。
- 套接字(Socket)編程是網(wǎng)絡(luò)編程的一種實(shí)現(xiàn)方式,其提供了一種機(jī)制,使得應(yīng)用程序能夠通過(guò)網(wǎng)絡(luò)進(jìn)行數(shù)據(jù)傳輸和通信。
- Go中的net包是標(biāo)準(zhǔn)庫(kù)中提供的網(wǎng)絡(luò)編程包,是基于套接字編程的一種實(shí)現(xiàn)方式,提供了對(duì)TCP、UDP、IP、ICMP、Unix域套接字等常見(jiàn)網(wǎng)絡(luò)協(xié)議的支持,通過(guò)net包可以完成創(chuàng)建套接字、建立連接、發(fā)送和接收數(shù)據(jù)等操作,實(shí)現(xiàn)網(wǎng)絡(luò)通信。
TCP網(wǎng)絡(luò)編程
服務(wù)器監(jiān)聽(tīng)
服務(wù)器監(jiān)聽(tīng)
在Go的net包中,Listen函數(shù)用于創(chuàng)建并返回一個(gè)網(wǎng)絡(luò)監(jiān)聽(tīng)器(Listener),以監(jiān)聽(tīng)指定網(wǎng)絡(luò)地址和端口上的連接請(qǐng)求。該函數(shù)的函數(shù)原型如下:
func Listen(network, address string) (Listener, error)
參數(shù)說(shuō)明:
- network:用于指定網(wǎng)絡(luò)類型,其值必須是"tcp", “tcp4”, “tcp6”, “unix"或"unixpacket”。
- address:用于指定需要被監(jiān)聽(tīng)的IP地址和端口號(hào),格式為"host:port"。
返回值說(shuō)明:
- 第一個(gè)返回值:表示創(chuàng)建的網(wǎng)絡(luò)監(jiān)聽(tīng)器。
- 第二個(gè)返回值:如果創(chuàng)建網(wǎng)絡(luò)監(jiān)聽(tīng)器過(guò)程中出錯(cuò),將返回非nil的錯(cuò)誤值。
通過(guò)Listen函數(shù)創(chuàng)建得到的網(wǎng)絡(luò)監(jiān)聽(tīng)器是Listener類型的,該類型是一個(gè)接口類型,其定義如下:
type Listener interface {
// Accept waits for and returns the next connection to the listener.
Accept() (Conn, error)
// Close closes the listener.
// Any blocked Accept operations will be unblocked and return errors.
Close() error
// Addr returns the listener's network address.
Addr() Addr
}
Listener接口中各方法說(shuō)明:
- Accept方法:從底層獲取下一個(gè)已經(jīng)建立好的連接給監(jiān)聽(tīng)器。
- Close方法:關(guān)閉監(jiān)聽(tīng)器。
- Addr方法:返回監(jiān)聽(tīng)器對(duì)應(yīng)的網(wǎng)絡(luò)地址(由IP地址和端口號(hào)組成)。
當(dāng)使用Listen函數(shù)創(chuàng)建TCP類型的監(jiān)聽(tīng)器時(shí),其返回的監(jiān)聽(tīng)器底層具體的類型是TCPListener,其定義如下:
type TCPListener struct {
fd *netFD
lc ListenConfig
}
TCPListener結(jié)構(gòu)體各字段說(shuō)明:
- fd:對(duì)底層網(wǎng)絡(luò)文件描述符的封裝,提供了對(duì)網(wǎng)絡(luò)連接的讀寫(xiě)和控制操作。
- lc:用于配置監(jiān)聽(tīng)器創(chuàng)建的行為,比如設(shè)置監(jiān)聽(tīng)地址、控制網(wǎng)絡(luò)參數(shù)等。
TCPListener結(jié)構(gòu)體中的fd字段是netFD類型的,其定義如下:
type netFD struct {
pfd poll.FD
// immutable until Close
family int
sotype int
isConnected bool // handshake completed or use of association with peer
net string
laddr Addr
raddr Addr
}
netFD結(jié)構(gòu)體各字段說(shuō)明:
- pfd:用于與底層的操作系統(tǒng)文件描述符進(jìn)行交互。
- family:表示套接字的協(xié)議家族,比如IPv4或IPv6。
- sotype:表示套接字的類型,比如TCP或UDP
- isConnected:表示連接是否已完成握手或與對(duì)方建立關(guān)聯(lián)。
- net:表示網(wǎng)絡(luò)協(xié)議,比如"tcp"或"udp"。
- laddr:表示本地網(wǎng)絡(luò)連接的地址。
- raddr:表示遠(yuǎn)程網(wǎng)絡(luò)連接的地址。
服務(wù)器監(jiān)聽(tīng)示例
服務(wù)器監(jiān)聽(tīng)示例如下:
package main
import (
"fmt"
"net"
)
func main() {
// 服務(wù)器監(jiān)聽(tīng)
listen, err := net.Listen("tcp", "0.0.0.0:8081")
if err != nil {
fmt.Printf("listen error, err = %v\n", err)
return
}
defer listen.Close()
fmt.Println("listen success...")
}
說(shuō)明一下:
- 服務(wù)器在創(chuàng)建監(jiān)聽(tīng)套接字時(shí),將其綁定到
0.0.0.0(通常表示為INADDR_ANY)地址,這樣服務(wù)器就可以同時(shí)監(jiān)聽(tīng)和接受來(lái)自不同網(wǎng)絡(luò)接口的連接請(qǐng)求,而不需要為每個(gè)接口分別創(chuàng)建監(jiān)聽(tīng)套接字。 - 為了避免網(wǎng)絡(luò)文件描述符資源泄露,在創(chuàng)建監(jiān)聽(tīng)器后及時(shí)利用defer機(jī)制關(guān)閉監(jiān)聽(tīng)器。監(jiān)聽(tīng)器被關(guān)閉后會(huì)停止監(jiān)聽(tīng)新的連接請(qǐng)求,并且任何被阻塞的Accept操作都會(huì)被解除阻塞并返回錯(cuò)誤。
客戶端連接服務(wù)器
客戶端連接服務(wù)器
在Go的net包中,Dial函數(shù)用于客戶端應(yīng)用程序與遠(yuǎn)程服務(wù)器建立連接。該函數(shù)的函數(shù)原型如下:
func Dial(network, address string) (Conn, error)
參數(shù)說(shuō)明:
- network:用于指定網(wǎng)絡(luò)協(xié)議,比如"tcp", "udp"等。
- address:用于指定連接的目標(biāo)地址。
返回值說(shuō)明:
- 第一個(gè)返回值:表示建立的網(wǎng)絡(luò)連接。
- 第二個(gè)返回值:如果建立網(wǎng)絡(luò)連接過(guò)程中出錯(cuò),將返回非nil的錯(cuò)誤值。
通過(guò)Dial函數(shù)建立得到的連接Conn類型的,該類型是一個(gè)接口類型,其定義如下:
type Conn interface {
// Read reads data from the connection.
Read(b []byte) (n int, err error)
// Write writes data to the connection.
Write(b []byte) (n int, err error)
// Close closes the connection.
// Any blocked Read or Write operations will be unblocked and return errors.
Close() error
// LocalAddr returns the local network address, if known.
LocalAddr() Addr
// RemoteAddr returns the remote network address, if known.
RemoteAddr() Addr
// SetDeadline sets the read and write deadlines associated
// with the connection. It is equivalent to calling both
// SetReadDeadline and SetWriteDeadline.
SetDeadline(t time.Time) error
// SetReadDeadline sets the deadline for future Read calls
// and any currently-blocked Read call.
SetReadDeadline(t time.Time) error
// SetWriteDeadline sets the deadline for future Write calls
// and any currently-blocked Write call.
SetWriteDeadline(t time.Time) error
}
Conn接口中各方法說(shuō)明:
- Read方法:從連接中讀取數(shù)據(jù)。
- Write方法:向連接中寫(xiě)入數(shù)據(jù)。
- Close方法:關(guān)閉連接。
- LocalAddr方法:返回連接對(duì)應(yīng)的本地網(wǎng)絡(luò)地址(由IP地址和端口號(hào)組成)。
- RemoteAddr方法:返回連接對(duì)應(yīng)的遠(yuǎn)程網(wǎng)絡(luò)地址(由IP地址和端口號(hào)組成)。
- SetDeadline方法:設(shè)置連接讀取和寫(xiě)入的截止時(shí)間。
- SetReadDeadline方法:設(shè)置連接讀取的截止時(shí)間。
- SetWriteDeadline方法:設(shè)置連接寫(xiě)入的截止時(shí)間。
當(dāng)使用Dial函數(shù)與TCP服務(wù)器建立連接時(shí),其返回的網(wǎng)絡(luò)連接底層具體的類型是TCPConn,其定義如下:
type TCPConn struct {
conn
}
TCPConn結(jié)構(gòu)體中僅嵌套了一個(gè)conn類型的匿名結(jié)構(gòu)體,其定義如下:
type conn struct {
fd *netFD
}
可以看到,conn結(jié)構(gòu)體中的fd字段與TCPListener結(jié)構(gòu)體中的fd字段的類型相同,它們都是對(duì)底層網(wǎng)絡(luò)文件描述符的封裝,提供了對(duì)網(wǎng)絡(luò)連接的讀寫(xiě)和控制操作。
客戶端連接服務(wù)器示例
客戶端連接服務(wù)器示例如下:
package main
import (
"fmt"
"net"
)
func main() {
// 客戶端連接服務(wù)器
conn, err := net.Dial("tcp", "127.0.0.1:8081")
if err != nil {
fmt.Printf("connect server error, err = %v\n", err)
return
}
defer conn.Close()
fmt.Println("connect server success...")
}
說(shuō)明一下:
- 當(dāng)客戶端連接TCP服務(wù)器時(shí),服務(wù)器必須處于監(jiān)聽(tīng)狀態(tài)。
- 為了避免網(wǎng)絡(luò)文件描述符資源泄露,客戶端在與服務(wù)器建立連接后及時(shí)利用defer機(jī)制關(guān)閉連接。
服務(wù)端獲取連接
服務(wù)端獲取連接
在創(chuàng)建TCP網(wǎng)絡(luò)監(jiān)聽(tīng)器后,調(diào)用Listener接口的Accept方法,本質(zhì)調(diào)用的是TCPListener的Accept方法,該方法用于從底層獲取下一個(gè)已經(jīng)建立好的連接給監(jiān)聽(tīng)器,如果底層沒(méi)有建立好的連接則會(huì)進(jìn)行阻塞等待。該方法的原型如下:
func (l *TCPListener) Accept() (Conn, error)
返回值說(shuō)明:
- 第一個(gè)返回值:表示獲取到的與客戶端建立好的連接。
- 第二個(gè)返回值:如果在獲取連接過(guò)程中出錯(cuò),將返回非nil的錯(cuò)誤值。
服務(wù)端獲取連接示例
服務(wù)端獲取連接示例如下:
package main
import (
"fmt"
"net"
)
func process(conn net.Conn) {
defer conn.Close()
fmt.Printf("handle a link %v...\n", conn.RemoteAddr())
}
func main() {
// 服務(wù)器監(jiān)聽(tīng)
listen, err := net.Listen("tcp", "0.0.0.0:8081")
if err != nil {
fmt.Printf("listen error, err = %v\n", err)
return
}
defer listen.Close()
fmt.Println("listen success...")
for {
fmt.Println("waiting client connect...")
// 服務(wù)端獲取連接
conn, err := listen.Accept()
if err != nil {
fmt.Printf("accept error, err = %v\n", err)
continue
}
fmt.Printf("get a link from %v...\n", conn.RemoteAddr())
// 開(kāi)啟新協(xié)程為客戶端提供服務(wù)
go process(conn)
}
}
說(shuō)明一下:
- 網(wǎng)絡(luò)監(jiān)聽(tīng)器的任務(wù)就是不斷調(diào)用Accept方法,從底層獲取已經(jīng)建立好的連接并為其提供服務(wù),通常在獲取到一個(gè)連接后會(huì)開(kāi)啟一個(gè)新協(xié)程為其提供服務(wù),而主協(xié)程則繼續(xù)調(diào)用Accept方法獲取新的連接。
- 為了讓新協(xié)程能夠獲取需要被處理的連接,需要將對(duì)應(yīng)的連接通過(guò)參數(shù)傳遞的方式,傳遞給協(xié)程對(duì)應(yīng)的處理函數(shù)。此外,為了避免網(wǎng)絡(luò)文件描述符資源泄露,需要在處理函數(shù)中利用defer機(jī)制關(guān)閉連接,保證連接處理完畢后能夠及時(shí)關(guān)閉連接。
向連接中寫(xiě)入數(shù)據(jù)
向連接中寫(xiě)入數(shù)據(jù)
在創(chuàng)建TCP連接后,調(diào)用Conn接口的Write方法,本質(zhì)調(diào)用的是TCPConn的Write方法,該方法用于向連接中寫(xiě)入數(shù)據(jù)。該方法的原型如下:
func (c *TCPConn) Write(b []byte) (int, error)
參數(shù)說(shuō)明:
- b:表示要寫(xiě)入連接的數(shù)據(jù)。
返回值說(shuō)明:
- 第一個(gè)返回值:表示實(shí)際寫(xiě)入的字節(jié)數(shù)。
- 第二個(gè)返回值:如果在寫(xiě)入數(shù)據(jù)過(guò)程中出錯(cuò),將返回非nil的錯(cuò)誤值。
從連接中讀取數(shù)據(jù)
從連接中讀取數(shù)據(jù)
在創(chuàng)建TCP連接后,調(diào)用Conn接口的Read方法,本質(zhì)調(diào)用的是TCPConn的Read方法,該方法用于從連接中讀取數(shù)據(jù)。該方法的原型如下:
func (c *TCPConn) Read(b []byte) (int, error)
參數(shù)說(shuō)明:
- b:輸出型參數(shù),用于存儲(chǔ)讀取到的數(shù)據(jù)。
返回值說(shuō)明:
- 第一個(gè)返回值:表示實(shí)際讀取的字節(jié)數(shù)。
- 第二個(gè)返回值:如果在讀取數(shù)據(jù)過(guò)程中出錯(cuò),將返回非nil的錯(cuò)誤值。
關(guān)閉連接/監(jiān)聽(tīng)器
關(guān)閉連接/監(jiān)聽(tīng)器
為了避免網(wǎng)絡(luò)文件描述符泄露,TCP網(wǎng)絡(luò)監(jiān)聽(tīng)器和TCP連接在使用完畢后都需要及時(shí)將其關(guān)閉,對(duì)應(yīng)調(diào)用的分別是TCPListener和TCPConn的Close方法,這兩個(gè)方法的原型如下:
func (l *TCPListener) Close() error func (c *TCPConn) Close() error
返回值說(shuō)明:
- 如果在關(guān)閉監(jiān)聽(tīng)器或關(guān)閉連接過(guò)程中出錯(cuò),將返回非nil的錯(cuò)誤值。
簡(jiǎn)易的TCP回聲服務(wù)器
效果展示
效果展示
為了演示使用net包實(shí)現(xiàn)網(wǎng)絡(luò)通信,下面實(shí)現(xiàn)了一個(gè)簡(jiǎn)易的TCP回聲服務(wù)器,其功能如下:
- 服務(wù)端能夠同時(shí)處理多個(gè)客戶端的連接請(qǐng)求,在為每個(gè)客戶端提供服務(wù)時(shí),能夠?qū)⒏鱾€(gè)客戶端發(fā)來(lái)的數(shù)據(jù)顯示在服務(wù)端,同時(shí)將客戶端發(fā)來(lái)的數(shù)據(jù)再發(fā)回給客戶端。
- 客戶端在連接到服務(wù)器后,能夠不斷從控制臺(tái)讀取用戶輸入的數(shù)據(jù)發(fā)送給服務(wù)端,并將服務(wù)端發(fā)來(lái)的數(shù)據(jù)顯示在客戶端,用戶在控制臺(tái)輸入exit能夠退出客戶端。
最終效果如下:

服務(wù)端處理邏輯
服務(wù)端處理邏輯
服務(wù)端處理邏輯如下:
- 主協(xié)程調(diào)用Listen函數(shù)完成服務(wù)器的監(jiān)聽(tīng)后,通過(guò)監(jiān)聽(tīng)器不斷調(diào)用Accept方法從底層獲取已經(jīng)建立好的連接,并為每一個(gè)獲取到的連接創(chuàng)建一個(gè)新協(xié)程為其提供服務(wù),而主協(xié)程則繼續(xù)獲取新的連接。
- 每個(gè)新協(xié)程在為其對(duì)應(yīng)的連接提供服務(wù)時(shí),通過(guò)調(diào)用連接的Read方法不斷讀取客戶端發(fā)來(lái)的數(shù)據(jù),將數(shù)據(jù)其顯示在服務(wù)端,同時(shí)通過(guò)調(diào)用連接的Write方法將客戶端發(fā)來(lái)的數(shù)據(jù)再發(fā)回給客戶端。
- 每個(gè)新協(xié)程在為其對(duì)應(yīng)的連接提供服務(wù)的過(guò)程中,如果從連接中讀取數(shù)據(jù)或向連接中寫(xiě)入數(shù)據(jù)時(shí)出錯(cuò),或是客戶端退出,則通過(guò)調(diào)用連接的Close方法將對(duì)應(yīng)的連接關(guān)閉。
服務(wù)端代碼如下:
package main
import (
"fmt"
"io"
"net"
)
func process(conn net.Conn) {
defer conn.Close()
data := make([]byte, 1024)
for {
// 1、讀取客戶端發(fā)來(lái)的數(shù)據(jù)
n, err := conn.Read(data)
if err != nil {
if err == io.EOF {
fmt.Printf("client %v quit\n", conn.RemoteAddr())
} else {
fmt.Printf("read client message error, err = %v\n", err)
}
return
}
fmt.Printf("client message[%v]: %v\n", conn.RemoteAddr(), string(data[:n]))
// 2、發(fā)送數(shù)據(jù)給客戶端
len, err := conn.Write(data[:n])
if err != nil || len != n {
fmt.Printf("send back message error, err = %v\n", err)
return
}
}
}
func main() {
// 服務(wù)器監(jiān)聽(tīng)
listen, err := net.Listen("tcp", "0.0.0.0:8081")
if err != nil {
fmt.Printf("listen error, err = %v\n", err)
return
}
defer listen.Close()
fmt.Println("listen success...")
for {
fmt.Println("waiting client connect...")
// 服務(wù)端獲取連接
conn, err := listen.Accept()
if err != nil {
fmt.Printf("accept error, err = %v\n", err)
continue
}
fmt.Printf("get a link from %v...\n", conn.RemoteAddr())
// 開(kāi)啟新協(xié)程為客戶端提供服務(wù)
go process(conn)
}
}
說(shuō)明一下:
- 當(dāng)服務(wù)端從某個(gè)連接中讀取數(shù)據(jù)時(shí),如果該連接對(duì)應(yīng)的客戶端已經(jīng)將連接關(guān)閉,那么服務(wù)端的讀操作將會(huì)返回io.EOF錯(cuò)誤。
客戶端處理邏輯
客戶端處理邏輯
客戶端處理邏輯如下:
- 客戶端在調(diào)用Dial函數(shù)與服務(wù)端建立連接后,不斷讀取用戶的輸入,通過(guò)調(diào)用連接Write方法將用戶輸入的數(shù)據(jù)發(fā)送給服務(wù)端,然后通過(guò)調(diào)用連接的Read方法讀取服務(wù)端發(fā)來(lái)的數(shù)據(jù)并顯示在客戶端,如果用戶輸入exit則調(diào)用連接的Close方法將連接關(guān)閉。
客戶端代碼如下:
package main
import (
"bufio"
"fmt"
"net"
"os"
)
func main() {
// 客戶端連接服務(wù)器
conn, err := net.Dial("tcp", "127.0.0.1:8081")
if err != nil {
fmt.Printf("connect server error, err = %v\n", err)
return
}
defer conn.Close()
fmt.Println("connect server success...")
reader := bufio.NewReader(os.Stdin)
data := make([]byte, 1024)
for {
// 1、讀取用戶輸入
str, err := reader.ReadString('\n')
if err != nil {
fmt.Printf("read input error, err = %v\n", err)
continue
}
str = str[:len(str)-2] // 去掉\r\n
if str == "exit" {
fmt.Printf("exit success...")
break
}
// 2、發(fā)送數(shù)據(jù)給服務(wù)端
n, err := conn.Write([]byte(str))
if err != nil || n != len(str) {
fmt.Printf("send message error, err = %v\n", err)
continue
}
fmt.Printf("send %d byte message to server...\n", n)
// 3、讀取服務(wù)端發(fā)來(lái)的數(shù)據(jù)
n, err = conn.Read(data)
if err != nil {
fmt.Printf("read message error, err = %v\n", err)
continue
}
fmt.Printf("server message: %v\n", string(data[:n]))
}
}
說(shuō)明一下:
- Stdin、Stdout和Stderr是os包中的全局變量,分別表示標(biāo)準(zhǔn)輸入流、標(biāo)準(zhǔn)輸出流和標(biāo)準(zhǔn)錯(cuò)誤流。
- 客戶端在讀取用戶輸入時(shí),通過(guò)bufio包中的Reader,以帶緩沖的方式每次從標(biāo)準(zhǔn)輸入流中讀取一行數(shù)據(jù)。
- Windows系統(tǒng)中通常使用
\r\n作為換行符,因此客戶端在每次讀取一行用戶輸入的數(shù)據(jù)后需要將末尾的兩個(gè)字符去掉。
到此這篇關(guān)于Golang TCP網(wǎng)絡(luò)編程的具體實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Golang TCP網(wǎng)絡(luò)編程內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Golang跨平臺(tái)GUI框架Fyne的使用教程詳解
Go 官方?jīng)]有提供標(biāo)準(zhǔn)的 GUI 框架,在 Go 實(shí)現(xiàn)的幾個(gè) GUI 庫(kù)中,Fyne 算是最出色的,它有著簡(jiǎn)潔的API、支持跨平臺(tái)能力,且高度可擴(kuò)展,下面我們就來(lái)看看它的具體使用吧2024-03-03
Go語(yǔ)言fmt.Sprintf格式化輸出的語(yǔ)法與實(shí)例
Go 可以使用 fmt.Sprintf 來(lái)格式化字符串,下面這篇文章主要給大家介紹了關(guān)于Go語(yǔ)言fmt.Sprintf格式化輸出的語(yǔ)法與實(shí)例,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-07-07
Go語(yǔ)言CSP并發(fā)模型實(shí)現(xiàn)MPG
這篇文章主要為大家介紹了Go語(yǔ)言CSP并發(fā)模型實(shí)現(xiàn)MPG圖文詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05
關(guān)于升級(jí)go1.18的goland問(wèn)題詳解
作為一個(gè)go語(yǔ)言程序員,覺(jué)得自己有義務(wù)為go新手開(kāi)一條更簡(jiǎn)單便捷的上手之路,下面這篇文章主要給大家介紹了關(guān)于升級(jí)go1.18的goland問(wèn)題的相關(guān)資料,需要的朋友可以參考下2022-11-11
Golang構(gòu)建WebSocket服務(wù)器和客戶端的示例詳解
這篇文章主要為大家詳細(xì)介紹了如何使用Go語(yǔ)言構(gòu)建WebSocket服務(wù)器和客戶端,以實(shí)現(xiàn)雙向通信,文中的示例代碼講解詳細(xì),需要的小伙伴可以參考一下2023-11-11
從淺入深帶你掌握Golang數(shù)據(jù)結(jié)構(gòu)map
在?Go?語(yǔ)言中,map?是一種非常常見(jiàn)的數(shù)據(jù)類型,它可以用于快速地檢索數(shù)據(jù)。本篇文章將介紹?Go?語(yǔ)言中的?map,包括?map?的定義、初始化、操作和優(yōu)化,需要的可以參考一下2023-04-04
Go中調(diào)用JS代碼(otto)的實(shí)現(xiàn)示例
Otto是一個(gè)用Go語(yǔ)言實(shí)現(xiàn)的JavaScript解釋器,可用于執(zhí)行和操作JavaScript代碼,適合在Go項(xiàng)目中執(zhí)行簡(jiǎn)單的JS腳本,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-10-10
使用go實(shí)現(xiàn)刪除sql里面的注釋和字符串功能(demo)
這篇文章主要介紹了使用go實(shí)現(xiàn)刪除sql里面的注釋和字符串功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-11-11

