Golang 網絡編程:像 C 語言一樣操作 Socket
在 C 語言中,進行網絡編程通常使 socket()、bind()、listen()、accept() 等系統調用,而在 Golang 中,我們既可以使用 net 庫提供的高級封裝,也可以直接使用 syscall 庫進行底層操作。本篇文章將簡單的介紹 Golang 如何像 C 語言一樣進行網絡編程。
使用 net 庫進行 TCP 編程(推薦方式)
Golang 的 net 包對 socket 進行了封裝,使得網絡編程更簡單、更易用。
TCP 服務器例子 net 版
package main
import (
"fmt"
"net"
)
func main() {
listener, err := net.Listen("tcp", ":8080") // 監聽 8080 端口
if err != nil {
panic(err)
}
defer listener.Close()
fmt.Println("Server listening on port 8080...")
for {
conn, err := listener.Accept() // 接受客戶端連接
if err != nil {
fmt.Println("Accept error:", err)
continue
}
go handleConnection(conn) // 處理連接
}
}
func handleConnection(conn net.Conn) {
defer conn.Close()
buffer := make([]byte, 1024)
n, err := conn.Read(buffer) // 讀取數據
if err != nil {
fmt.Println("Read error:", err)
return
}
fmt.Println("Received:", string(buffer[:n]))
conn.Write([]byte("Hello from server\n")) // 發送響應
}
TCP 客戶端 net 版
package main
import (
"fmt"
"net"
)
func main() {
conn, err := net.Dial("tcp", "127.0.0.1:8080") // 連接服務器
if err != nil {
panic(err)
}
defer conn.Close()
conn.Write([]byte("Hello, Server!\n")) // 發送數據
buffer := make([]byte, 1024)
n, _ := conn.Read(buffer) // 讀取服務器響應
fmt.Println("Server response:", string(buffer[:n]))
}
上述給出的就是使用 golang 標準庫中 net 包編寫的,簡單的 tcp server 代碼例子,這比傳統的 socket 代碼量少了很多,卻能達到預期的效果。但是在實際的工作中,往往有些需求我們不能直接使用 net 包進行操作的,例如一些特殊情況下我們需要自定義的數據包包頭,加密等等操作。
使用 syscall 實現 TCP 服務器
TCP 服務器例子 syscall 版
package main
import (
"fmt"
"syscall"
)
func main() {
// 創建 socket
fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, 0)
if err != nil {
panic(err)
}
defer syscall.Close(fd)
// 設置 SO_REUSEADDR,避免端口占用問題
err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
if err != nil {
panic(err)
}
// 綁定地址和端口
addr := syscall.SockaddrInet4{Port: 9527, Addr: [4]byte{0, 0, 0, 0}}
if err := syscall.Bind(fd, &addr); err != nil {
panic(err)
}
// 監聽連接
if err := syscall.Listen(fd, syscall.SOMAXCONN); err != nil {
panic(err)
}
fmt.Println("Server listening on port 9527...")
for {
// 接受客戶端連接
clientFD, _, err := syscall.Accept(fd)
if err != nil {
fmt.Println("Accept error:", err)
continue
}
go handleClient(clientFD)
}
}
// 處理客戶端連接
func handleClient(fd int) {
defer syscall.Close(fd)
buffer := make([]byte, 1024)
n, err := syscall.Read(fd, buffer) // 讀取數據
if err != nil {
fmt.Println("Read error:", err)
return
}
fmt.Println("Received:", string(buffer[:n]))
// 發送數據
syscall.Write(fd, []byte("Hello from server\n"))
}
代碼解析
• syscall.Socket(AF_INET, SOCK_STREAM, 0): 創建 TCP 套接字(IPv4)。
• syscall.Bind(fd, &addr): 綁定端口 9527。
• syscall.Listen(fd, syscall.SOMAXCONN): 監聽連接。
• syscall.Accept(fd): 接受連接並返回新的 clientFD。
• syscall.Read(fd, buffer): 讀取客戶端數據。
• syscall.Write(fd, response): 發送數據。
TCP 客戶端 syscall 版
package main
import (
"fmt"
"syscall"
)
func main() {
// 創建 socket
fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, 0)
if err != nil {
panic(err)
}
defer syscall.Close(fd)
// 連接服務器
serverAddr := syscall.SockaddrInet4{Port: 9527, Addr: [4]byte{127, 0, 0, 1}}
if err := syscall.Connect(fd, &serverAddr); err != nil {
panic(err)
}
// 發送數據
message := "Hello, Server!"
syscall.Write(fd, []byte(message))
// 讀取響應
buffer := make([]byte, 1024)
n, err := syscall.Read(fd, buffer)
if err != nil {
fmt.Println("Read error:", err)
return
}
fmt.Println("Server response:", string(buffer[:n]))
}
代碼解析
• syscall.Socket(AF_INET, SOCK_STREAM, 0): 創建 TCP 套接字。
• syscall.Connect(fd, &serverAddr): 連接到 127.0.0.1:9527 服務器。
• syscall.Write(fd, message): 發送數據。
• syscall.Read(fd, buffer): 讀取服務器響應。
syscall 方式 vs net 庫
如果只是進行一般的 TCP 網絡編程,推薦使用 net 庫。如果你想更深入理解底層 socket 機制,或者進行 epoll、raw socket 等底層優化,則可以使用 syscall。
總結
本文介紹了 Golang 進行網絡編程的兩種方式:
✅ net 庫提供了簡單易用的 API,適合大多數應用場景。
✅ syscall 允許 Golang 直接調用 Linux/Unix 系統 API 進行底層網絡編程。
✅ syscall.Socket()、syscall.Bind()、syscall.Listen() 等函數的用法與 C 語言幾乎一致。
✅ syscall 適用於高性能和自定義網絡編程,但比 net 庫更復雜。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/ig8R-inbTB3M0Cm_m-ypCQ?poc_token=HNJVzmejNmlx9wXkPdX1WrPkq73iPBh4B8JoFa2J