4.4.3 系统调用详解 #
系统调用是用户程序与操作系统内核交互的接口。Go 语言通过 syscall
包提供了对系统调用的直接访问能力。本节将深入探讨系统调用的原理、使用方法以及性能优化技巧。
系统调用基础 #
系统调用的概念 #
系统调用是操作系统提供给应用程序的编程接口,允许程序请求内核服务。主要包括:
- 进程控制:创建、终止、等待进程
- 文件操作:打开、读取、写入、关闭文件
- 设备管理:请求设备、释放设备、读写设备
- 信息维护:获取系统信息、设置时间
- 通信:创建连接、发送消息
系统调用的工作原理 #
系统调用的执行过程:
- 用户态调用:应用程序调用系统调用接口
- 模式切换:从用户态切换到内核态
- 内核处理:内核执行相应的系统服务
- 返回结果:将结果返回给用户程序
- 模式恢复:从内核态切换回用户态
Go 中的系统调用 #
syscall 包基础 #
Go 的 syscall
包提供了对系统调用的底层访问:
package main
import (
"fmt"
"syscall"
"unsafe"
"log"
)
func basicSyscallExample() {
// 使用 syscall.Syscall 进行系统调用
// 获取进程 ID
pid, _, _ := syscall.Syscall(syscall.SYS_GETPID, 0, 0, 0)
fmt.Printf("进程 ID: %d\n", pid)
// 获取用户 ID
uid, _, _ := syscall.Syscall(syscall.SYS_GETUID, 0, 0, 0)
fmt.Printf("用户 ID: %d\n", uid)
// 获取组 ID
gid, _, _ := syscall.Syscall(syscall.SYS_GETGID, 0, 0, 0)
fmt.Printf("组 ID: %d\n", gid)
}
func fileOperationSyscall() {
filename := "/tmp/syscall_test.txt"
content := "Hello, System Call!"
// 创建文件 (open 系统调用)
fd, _, errno := syscall.Syscall(syscall.SYS_OPEN,
uintptr(unsafe.Pointer(syscall.StringBytePtr(filename))),
uintptr(syscall.O_CREAT|syscall.O_WRONLY|syscall.O_TRUNC),
uintptr(0644))
if errno != 0 {
log.Fatalf("创建文件失败: %v", errno)
}
fmt.Printf("文件描述符: %d\n", fd)
// 写入文件 (write 系统调用)
data := []byte(content)
n, _, errno := syscall.Syscall(syscall.SYS_WRITE,
fd,
uintptr(unsafe.Pointer(&data[0])),
uintptr(len(data)))
if errno != 0 {
log.Fatalf("写入文件失败: %v", errno)
}
fmt.Printf("写入字节数: %d\n", n)
// 关闭文件 (close 系统调用)
_, _, errno = syscall.Syscall(syscall.SYS_CLOSE, fd, 0, 0)
if errno != 0 {
log.Fatalf("关闭文件失败: %v", errno)
}
fmt.Println("文件操作完成")
}
func main() {
fmt.Println("=== 基础系统调用示例 ===")
basicSyscallExample()
fmt.Println("\n=== 文件操作系统调用示例 ===")
fileOperationSyscall()
}
高级系统调用封装 #
为了更方便地使用系统调用,我们可以创建封装函数:
package main
import (
"fmt"
"syscall"
"unsafe"
"log"
"time"
)
// 系统信息结构
type SystemInfo struct {
Uptime int64
LoadAvg [3]uint64
TotalRAM uint64
FreeRAM uint64
SharedRAM uint64
BufferRAM uint64
TotalSwap uint64
FreeSwap uint64
Procs uint16
}
// 获取系统信息
func getSysInfo() (*SystemInfo, error) {
var info SystemInfo
_, _, errno := syscall.Syscall(syscall.SYS_SYSINFO,
uintptr(unsafe.Pointer(&info)), 0, 0)
if errno != 0 {
return nil, fmt.Errorf("获取系统信息失败: %v", errno)
}
return &info, nil
}
// 内存映射文件
func mmapFile(filename string) ([]byte, error) {
// 打开文件
fd, err := syscall.Open(filename, syscall.O_RDONLY, 0)
if err != nil {
return nil, err
}
defer syscall.Close(fd)
// 获取文件大小
var stat syscall.Stat_t
err = syscall.Fstat(fd, &stat)
if err != nil {
return nil, err
}
size := int(stat.Size)
// 内存映射
data, err := syscall.Mmap(fd, 0, size, syscall.PROT_READ, syscall.MAP_SHARED)
if err != nil {
return nil, err
}
return data, nil
}
// 解除内存映射
func munmapFile(data []byte) error {
return syscall.Munmap(data)
}
// 创建目录
func createDirectory(path string, mode uint32) error {
_, _, errno := syscall.Syscall(syscall.SYS_MKDIR,
uintptr(unsafe.Pointer(syscall.StringBytePtr(path))),
uintptr(mode), 0)
if errno != 0 {
return fmt.Errorf("创建目录失败: %v", errno)
}
return nil
}
// 删除目录
func removeDirectory(path string) error {
_, _, errno := syscall.Syscall(syscall.SYS_RMDIR,
uintptr(unsafe.Pointer(syscall.StringBytePtr(path))), 0, 0)
if errno != 0 {
return fmt.Errorf("删除目录失败: %v", errno)
}
return nil
}
func systemInfoExample() {
info, err := getSysInfo()
if err != nil {
log.Printf("获取系统信息失败: %v", err)
return
}
fmt.Printf("系统运行时间: %d 秒\n", info.Uptime)
fmt.Printf("总内存: %d MB\n", info.TotalRAM/1024/1024)
fmt.Printf("可用内存: %d MB\n", info.FreeRAM/1024/1024)
fmt.Printf("进程数: %d\n", info.Procs)
}
func mmapExample() {
// 创建测试文件
filename := "/tmp/mmap_test.txt"
content := "This is a test file for memory mapping example."
err := syscall.WriteFile(filename, []byte(content), 0644)
if err != nil {
log.Printf("创建测试文件失败: %v", err)
return
}
defer syscall.Unlink(filename)
// 内存映射文件
data, err := mmapFile(filename)
if err != nil {
log.Printf("内存映射失败: %v", err)
return
}
defer munmapFile(data)
fmt.Printf("映射的文件内容: %s\n", string(data))
}
func directoryExample() {
dirPath := "/tmp/syscall_test_dir"
// 创建目录
err := createDirectory(dirPath, 0755)
if err != nil {
log.Printf("创建目录失败: %v", err)
return
}
fmt.Printf("目录创建成功: %s\n", dirPath)
// 等待一下
time.Sleep(1 * time.Second)
// 删除目录
err = removeDirectory(dirPath)
if err != nil {
log.Printf("删除目录失败: %v", err)
return
}
fmt.Printf("目录删除成功: %s\n", dirPath)
}
func main() {
fmt.Println("=== 系统信息示例 ===")
systemInfoExample()
fmt.Println("\n=== 内存映射示例 ===")
mmapExample()
fmt.Println("\n=== 目录操作示例 ===")
directoryExample()
}
网络系统调用 #
套接字操作 #
直接使用系统调用进行网络编程:
package main
import (
"fmt"
"syscall"
"unsafe"
"log"
"net"
)
// 创建 TCP 套接字
func createTCPSocket() (int, error) {
fd, _, errno := syscall.Syscall(syscall.SYS_SOCKET,
syscall.AF_INET, syscall.SOCK_STREAM, 0)
if errno != 0 {
return -1, fmt.Errorf("创建套接字失败: %v", errno)
}
return int(fd), nil
}
// 绑定地址
func bindSocket(fd int, addr *syscall.SockaddrInet4) error {
_, _, errno := syscall.Syscall(syscall.SYS_BIND,
uintptr(fd),
uintptr(unsafe.Pointer(addr)),
unsafe.Sizeof(*addr))
if errno != 0 {
return fmt.Errorf("绑定地址失败: %v", errno)
}
return nil
}
// 监听连接
func listenSocket(fd int, backlog int) error {
_, _, errno := syscall.Syscall(syscall.SYS_LISTEN,
uintptr(fd), uintptr(backlog), 0)
if errno != 0 {
return fmt.Errorf("监听失败: %v", errno)
}
return nil
}
// 接受连接
func acceptConnection(fd int) (int, *syscall.SockaddrInet4, error) {
var addr syscall.SockaddrInet4
addrLen := uint32(unsafe.Sizeof(addr))
clientFd, _, errno := syscall.Syscall(syscall.SYS_ACCEPT,
uintptr(fd),
uintptr(unsafe.Pointer(&addr)),
uintptr(unsafe.Pointer(&addrLen)))
if errno != 0 {
return -1, nil, fmt.Errorf("接受连接失败: %v", errno)
}
return int(clientFd), &addr, nil
}
// 简单的 TCP 服务器
func tcpServerExample() {
// 创建套接字
serverFd, err := createTCPSocket()
if err != nil {
log.Fatal(err)
}
defer syscall.Close(serverFd)
// 设置地址重用
err = syscall.SetsockoptInt(serverFd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
if err != nil {
log.Fatal(err)
}
// 绑定地址
addr := &syscall.SockaddrInet4{
Port: 8080,
Addr: [4]byte{127, 0, 0, 1},
}
err = bindSocket(serverFd, addr)
if err != nil {
log.Fatal(err)
}
// 监听
err = listenSocket(serverFd, 10)
if err != nil {
log.Fatal(err)
}
fmt.Println("TCP 服务器启动,监听端口 8080")
// 接受连接
for i := 0; i < 3; i++ { // 只处理 3 个连接作为示例
clientFd, clientAddr, err := acceptConnection(serverFd)
if err != nil {
log.Printf("接受连接失败: %v", err)
continue
}
fmt.Printf("接受连接: %v\n", clientAddr)
// 处理客户端
go func(fd int) {
defer syscall.Close(fd)
// 读取数据
buffer := make([]byte, 1024)
n, err := syscall.Read(fd, buffer)
if err != nil {
log.Printf("读取数据失败: %v", err)
return
}
fmt.Printf("接收到数据: %s\n", string(buffer[:n]))
// 发送响应
response := "HTTP/1.1 200 OK\r\nContent-Length: 13\r\n\r\nHello, World!"
_, err = syscall.Write(fd, []byte(response))
if err != nil {
log.Printf("发送响应失败: %v", err)
}
}(clientFd)
}
}
func main() {
tcpServerExample()
}
UDP 套接字操作 #
package main
import (
"fmt"
"syscall"
"unsafe"
"log"
"time"
)
// 创建 UDP 套接字
func createUDPSocket() (int, error) {
fd, _, errno := syscall.Syscall(syscall.SYS_SOCKET,
syscall.AF_INET, syscall.SOCK_DGRAM, 0)
if errno != 0 {
return -1, fmt.Errorf("创建 UDP 套接字失败: %v", errno)
}
return int(fd), nil
}
// 发送 UDP 数据
func sendUDPData(fd int, data []byte, addr *syscall.SockaddrInet4) error {
_, _, errno := syscall.Syscall6(syscall.SYS_SENDTO,
uintptr(fd),
uintptr(unsafe.Pointer(&data[0])),
uintptr(len(data)),
0,
uintptr(unsafe.Pointer(addr)),
unsafe.Sizeof(*addr))
if errno != 0 {
return fmt.Errorf("发送 UDP 数据失败: %v", errno)
}
return nil
}
// 接收 UDP 数据
func receiveUDPData(fd int, buffer []byte) (int, *syscall.SockaddrInet4, error) {
var addr syscall.SockaddrInet4
addrLen := uint32(unsafe.Sizeof(addr))
n, _, errno := syscall.Syscall6(syscall.SYS_RECVFROM,
uintptr(fd),
uintptr(unsafe.Pointer(&buffer[0])),
uintptr(len(buffer)),
0,
uintptr(unsafe.Pointer(&addr)),
uintptr(unsafe.Pointer(&addrLen)))
if errno != 0 {
return 0, nil, fmt.Errorf("接收 UDP 数据失败: %v", errno)
}
return int(n), &addr, nil
}
// UDP 服务器
func udpServer() {
fd, err := createUDPSocket()
if err != nil {
log.Fatal(err)
}
defer syscall.Close(fd)
// 绑定地址
serverAddr := &syscall.SockaddrInet4{
Port: 8081,
Addr: [4]byte{127, 0, 0, 1},
}
err = bindSocket(fd, serverAddr)
if err != nil {
log.Fatal(err)
}
fmt.Println("UDP 服务器启动,监听端口 8081")
buffer := make([]byte, 1024)
for i := 0; i < 3; i++ { // 处理 3 个消息作为示例
n, clientAddr, err := receiveUDPData(fd, buffer)
if err != nil {
log.Printf("接收数据失败: %v", err)
continue
}
fmt.Printf("接收到来自 %v 的数据: %s\n", clientAddr, string(buffer[:n]))
// 发送响应
response := fmt.Sprintf("Echo: %s", string(buffer[:n]))
err = sendUDPData(fd, []byte(response), clientAddr)
if err != nil {
log.Printf("发送响应失败: %v", err)
}
}
}
// UDP 客户端
func udpClient() {
fd, err := createUDPSocket()
if err != nil {
log.Fatal(err)
}
defer syscall.Close(fd)
serverAddr := &syscall.SockaddrInet4{
Port: 8081,
Addr: [4]byte{127, 0, 0, 1},
}
messages := []string{"Hello", "World", "UDP"}
for _, msg := range messages {
// 发送消息
err = sendUDPData(fd, []byte(msg), serverAddr)
if err != nil {
log.Printf("发送消息失败: %v", err)
continue
}
fmt.Printf("发送消息: %s\n", msg)
// 接收响应
buffer := make([]byte, 1024)
n, _, err := receiveUDPData(fd, buffer)
if err != nil {
log.Printf("接收响应失败: %v", err)
continue
}
fmt.Printf("接收响应: %s\n", string(buffer[:n]))
time.Sleep(1 * time.Second)
}
}
func main() {
// 启动服务器
go udpServer()
// 等待服务器启动
time.Sleep(1 * time.Second)
// 启动客户端
udpClient()
// 等待完成
time.Sleep(1 * time.Second)
}
系统调用性能优化 #
批量系统调用 #
减少系统调用次数可以提高性能:
package main
import (
"fmt"
"syscall"
"time"
"log"
)
// 单次写入测试
func singleWriteTest(filename string, data []byte, iterations int) time.Duration {
fd, err := syscall.Open(filename, syscall.O_CREAT|syscall.O_WRONLY|syscall.O_TRUNC, 0644)
if err != nil {
log.Fatal(err)
}
defer syscall.Close(fd)
start := time.Now()
for i := 0; i < iterations; i++ {
_, err := syscall.Write(fd, data)
if err != nil {
log.Fatal(err)
}
}
return time.Since(start)
}
// 批量写入测试
func batchWriteTest(filename string, data []byte, iterations int) time.Duration {
fd, err := syscall.Open(filename, syscall.O_CREAT|syscall.O_WRONLY|syscall.O_TRUNC, 0644)
if err != nil {
log.Fatal(err)
}
defer syscall.Close(fd)
// 创建批量数据
batchData := make([]byte, len(data)*iterations)
for i := 0; i < iterations; i++ {
copy(batchData[i*len(data):], data)
}
start := time.Now()
_, err = syscall.Write(fd, batchData)
if err != nil {
log.Fatal(err)
}
return time.Since(start)
}
// 使用 writev 进行向量化写入
func vectorWriteTest(filename string, data []byte, iterations int) time.Duration {
fd, err := syscall.Open(filename, syscall.O_CREAT|syscall.O_WRONLY|syscall.O_TRUNC, 0644)
if err != nil {
log.Fatal(err)
}
defer syscall.Close(fd)
// 创建 iovec 结构
iovecs := make([]syscall.Iovec, iterations)
for i := 0; i < iterations; i++ {
iovecs[i] = syscall.Iovec{
Base: &data[0],
Len: uint64(len(data)),
}
}
start := time.Now()
_, err = syscall.Writev(fd, iovecs)
if err != nil {
log.Fatal(err)
}
return time.Since(start)
}
func performanceTest() {
data := []byte("Hello, World!\n")
iterations := 10000
// 单次写入测试
singleTime := singleWriteTest("/tmp/single_write.txt", data, iterations)
fmt.Printf("单次写入 %d 次耗时: %v\n", iterations, singleTime)
// 批量写入测试
batchTime := batchWriteTest("/tmp/batch_write.txt", data, iterations)
fmt.Printf("批量写入耗时: %v\n", batchTime)
// 向量化写入测试
vectorTime := vectorWriteTest("/tmp/vector_write.txt", data, iterations)
fmt.Printf("向量化写入耗时: %v\n", vectorTime)
fmt.Printf("批量写入性能提升: %.2fx\n", float64(singleTime)/float64(batchTime))
fmt.Printf("向量化写入性能提升: %.2fx\n", float64(singleTime)/float64(vectorTime))
// 清理文件
syscall.Unlink("/tmp/single_write.txt")
syscall.Unlink("/tmp/batch_write.txt")
syscall.Unlink("/tmp/vector_write.txt")
}
func main() {
fmt.Println("=== 系统调用性能测试 ===")
performanceTest()
}
异步 I/O 模拟 #
虽然 Go 标准库没有直接支持 Linux 的 io_uring,但我们可以模拟异步 I/O:
package main
import (
"fmt"
"syscall"
"time"
"sync"
"log"
)
// 异步 I/O 请求
type AsyncIORequest struct {
Operation string
Filename string
Data []byte
Offset int64
Callback func([]byte, error)
}
// 异步 I/O 管理器
type AsyncIOManager struct {
requests chan AsyncIORequest
workers int
wg sync.WaitGroup
}
// 创建异步 I/O 管理器
func NewAsyncIOManager(workers int) *AsyncIOManager {
return &AsyncIOManager{
requests: make(chan AsyncIORequest, 100),
workers: workers,
}
}
// 启动工作协程
func (aio *AsyncIOManager) Start() {
for i := 0; i < aio.workers; i++ {
aio.wg.Add(1)
go aio.worker(i)
}
}
// 工作协程
func (aio *AsyncIOManager) worker(id int) {
defer aio.wg.Done()
fmt.Printf("异步 I/O 工作者 %d 启动\n", id)
for req := range aio.requests {
switch req.Operation {
case "read":
aio.handleRead(req)
case "write":
aio.handleWrite(req)
default:
req.Callback(nil, fmt.Errorf("不支持的操作: %s", req.Operation))
}
}
fmt.Printf("异步 I/O 工作者 %d 退出\n", id)
}
// 处理读取请求
func (aio *AsyncIOManager) handleRead(req AsyncIORequest) {
fd, err := syscall.Open(req.Filename, syscall.O_RDONLY, 0)
if err != nil {
req.Callback(nil, err)
return
}
defer syscall.Close(fd)
// 定位到指定偏移
if req.Offset > 0 {
_, err = syscall.Seek(fd, req.Offset, 0)
if err != nil {
req.Callback(nil, err)
return
}
}
// 读取数据
buffer := make([]byte, 1024)
n, err := syscall.Read(fd, buffer)
if err != nil {
req.Callback(nil, err)
return
}
req.Callback(buffer[:n], nil)
}
// 处理写入请求
func (aio *AsyncIOManager) handleWrite(req AsyncIORequest) {
fd, err := syscall.Open(req.Filename, syscall.O_CREAT|syscall.O_WRONLY, 0644)
if err != nil {
req.Callback(nil, err)
return
}
defer syscall.Close(fd)
// 定位到指定偏移
if req.Offset > 0 {
_, err = syscall.Seek(fd, req.Offset, 0)
if err != nil {
req.Callback(nil, err)
return
}
}
// 写入数据
_, err = syscall.Write(fd, req.Data)
req.Callback(nil, err)
}
// 提交异步读取请求
func (aio *AsyncIOManager) AsyncRead(filename string, offset int64, callback func([]byte, error)) {
req := AsyncIORequest{
Operation: "read",
Filename: filename,
Offset: offset,
Callback: callback,
}
aio.requests <- req
}
// 提交异步写入请求
func (aio *AsyncIOManager) AsyncWrite(filename string, data []byte, offset int64, callback func([]byte, error)) {
req := AsyncIORequest{
Operation: "write",
Filename: filename,
Data: data,
Offset: offset,
Callback: callback,
}
aio.requests <- req
}
// 关闭管理器
func (aio *AsyncIOManager) Close() {
close(aio.requests)
aio.wg.Wait()
}
func asyncIOExample() {
// 创建异步 I/O 管理器
aio := NewAsyncIOManager(3)
aio.Start()
defer aio.Close()
filename := "/tmp/async_io_test.txt"
// 异步写入
var writeWg sync.WaitGroup
writeWg.Add(3)
for i := 0; i < 3; i++ {
data := fmt.Sprintf("异步写入数据 %d\n", i)
aio.AsyncWrite(filename, []byte(data), int64(i*20), func(result []byte, err error) {
defer writeWg.Done()
if err != nil {
log.Printf("异步写入失败: %v", err)
} else {
fmt.Printf("异步写入完成\n")
}
})
}
writeWg.Wait()
fmt.Println("所有写入操作完成")
// 异步读取
var readWg sync.WaitGroup
readWg.Add(1)
aio.AsyncRead(filename, 0, func(data []byte, err error) {
defer readWg.Done()
if err != nil {
log.Printf("异步读取失败: %v", err)
} else {
fmt.Printf("异步读取结果: %s", string(data))
}
})
readWg.Wait()
// 清理文件
syscall.Unlink(filename)
}
func main() {
fmt.Println("=== 异步 I/O 示例 ===")
asyncIOExample()
}
实践练习 #
练习 1:系统监控工具 #
使用系统调用创建一个系统监控工具:
package main
import (
"fmt"
"syscall"
"unsafe"
"time"
"log"
"strings"
"strconv"
)
// 系统统计信息
type SystemStats struct {
CPUUsage float64
MemoryUsage float64
DiskUsage float64
NetworkIO NetworkStats
}
// 网络统计信息
type NetworkStats struct {
BytesReceived uint64
BytesSent uint64
}
// 系统监控器
type SystemMonitor struct {
interval time.Duration
}
// 创建系统监控器
func NewSystemMonitor(interval time.Duration) *SystemMonitor {
return &SystemMonitor{
interval: interval,
}
}
// 获取 CPU 使用率
func (sm *SystemMonitor) getCPUUsage() (float64, error) {
// 读取 /proc/stat 文件
fd, err := syscall.Open("/proc/stat", syscall.O_RDONLY, 0)
if err != nil {
return 0, err
}
defer syscall.Close(fd)
buffer := make([]byte, 1024)
n, err := syscall.Read(fd, buffer)
if err != nil {
return 0, err
}
content := string(buffer[:n])
lines := strings.Split(content, "\n")
if len(lines) == 0 {
return 0, fmt.Errorf("无法解析 CPU 信息")
}
// 解析第一行 CPU 总体信息
fields := strings.Fields(lines[0])
if len(fields) < 8 {
return 0, fmt.Errorf("CPU 信息格式错误")
}
var total, idle uint64
for i := 1; i < len(fields); i++ {
val, _ := strconv.ParseUint(fields[i], 10, 64)
total += val
if i == 4 { // idle time
idle = val
}
}
if total == 0 {
return 0, nil
}
return float64(total-idle) / float64(total) * 100, nil
}
// 获取内存使用率
func (sm *SystemMonitor) getMemoryUsage() (float64, error) {
fd, err := syscall.Open("/proc/meminfo", syscall.O_RDONLY, 0)
if err != nil {
return 0, err
}
defer syscall.Close(fd)
buffer := make([]byte, 2048)
n, err := syscall.Read(fd, buffer)
if err != nil {
return 0, err
}
content := string(buffer[:n])
lines := strings.Split(content, "\n")
var memTotal, memFree, memAvailable uint64
for _, line := range lines {
fields := strings.Fields(line)
if len(fields) < 2 {
continue
}
switch fields[0] {
case "MemTotal:":
memTotal, _ = strconv.ParseUint(fields[1], 10, 64)
case "MemFree:":
memFree, _ = strconv.ParseUint(fields[1], 10, 64)
case "MemAvailable:":
memAvailable, _ = strconv.ParseUint(fields[1], 10, 64)
}
}
if memTotal == 0 {
return 0, fmt.Errorf("无法获取内存总量")
}
used := memTotal - memAvailable
return float64(used) / float64(memTotal) * 100, nil
}
// 获取磁盘使用率
func (sm *SystemMonitor) getDiskUsage(path string) (float64, error) {
var stat syscall.Statfs_t
err := syscall.Statfs(path, &stat)
if err != nil {
return 0, err
}
total := stat.Blocks * uint64(stat.Bsize)
free := stat.Bavail * uint64(stat.Bsize)
used := total - free
if total == 0 {
return 0, nil
}
return float64(used) / float64(total) * 100, nil
}
// 获取网络统计信息
func (sm *SystemMonitor) getNetworkStats() (NetworkStats, error) {
fd, err := syscall.Open("/proc/net/dev", syscall.O_RDONLY, 0)
if err != nil {
return NetworkStats{}, err
}
defer syscall.Close(fd)
buffer := make([]byte, 4096)
n, err := syscall.Read(fd, buffer)
if err != nil {
return NetworkStats{}, err
}
content := string(buffer[:n])
lines := strings.Split(content, "\n")
var totalRx, totalTx uint64
for _, line := range lines[2:] { // 跳过头部两行
if strings.TrimSpace(line) == "" {
continue
}
fields := strings.Fields(line)
if len(fields) < 10 {
continue
}
// 跳过 lo 接口
if strings.HasPrefix(fields[0], "lo:") {
continue
}
rx, _ := strconv.ParseUint(fields[1], 10, 64)
tx, _ := strconv.ParseUint(fields[9], 10, 64)
totalRx += rx
totalTx += tx
}
return NetworkStats{
BytesReceived: totalRx,
BytesSent: totalTx,
}, nil
}
// 获取系统统计信息
func (sm *SystemMonitor) GetStats() (*SystemStats, error) {
stats := &SystemStats{}
// 获取 CPU 使用率
cpu, err := sm.getCPUUsage()
if err != nil {
log.Printf("获取 CPU 使用率失败: %v", err)
} else {
stats.CPUUsage = cpu
}
// 获取内存使用率
mem, err := sm.getMemoryUsage()
if err != nil {
log.Printf("获取内存使用率失败: %v", err)
} else {
stats.MemoryUsage = mem
}
// 获取磁盘使用率
disk, err := sm.getDiskUsage("/")
if err != nil {
log.Printf("获取磁盘使用率失败: %v", err)
} else {
stats.DiskUsage = disk
}
// 获取网络统计信息
network, err := sm.getNetworkStats()
if err != nil {
log.Printf("获取网络统计信息失败: %v", err)
} else {
stats.NetworkIO = network
}
return stats, nil
}
// 启动监控
func (sm *SystemMonitor) Start() {
fmt.Println("系统监控器启动")
for {
stats, err := sm.GetStats()
if err != nil {
log.Printf("获取系统统计信息失败: %v", err)
continue
}
fmt.Printf("=== 系统状态 ===\n")
fmt.Printf("CPU 使用率: %.2f%%\n", stats.CPUUsage)
fmt.Printf("内存使用率: %.2f%%\n", stats.MemoryUsage)
fmt.Printf("磁盘使用率: %.2f%%\n", stats.DiskUsage)
fmt.Printf("网络接收: %d 字节\n", stats.NetworkIO.BytesReceived)
fmt.Printf("网络发送: %d 字节\n", stats.NetworkIO.BytesSent)
fmt.Println()
time.Sleep(sm.interval)
}
}
func main() {
monitor := NewSystemMonitor(3 * time.Second)
monitor.Start()
}
总结 #
本节深入介绍了 Go 语言中系统调用的使用方法:
- 系统调用基础:了解了系统调用的概念和工作原理
- syscall 包使用:学会了使用 Go 的 syscall 包进行底层系统调用
- 网络系统调用:掌握了使用系统调用进行网络编程
- 性能优化:学习了批量操作和异步 I/O 的优化技巧
- 实践应用:构建了完整的系统监控工具
这些知识为深入理解操作系统和进行系统级编程提供了坚实的基础。在下一节中,我们将学习共享内存和信号量的使用方法。