在C语言中,进行网络编程通常使socket()、bind()、listen()、accept()等系统调用,而在Golang中,我们既可以使用net库提供的高级封装,也可以直接使用syscall库进行底层操作。本篇文章将简单的介绍Golang如何像C语言一样进行网络编程。
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包进行操作的,例如一些特殊情况下我们需要自定义的数据包包头,加密等等操作。
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"))
}
代码解析
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]))
}
代码解析