Golang在windows与linux的部分区别
Posted StaticAuto
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Golang在windows与linux的部分区别相关的知识,希望对你有一定的参考价值。
前言
Golang语言包下载分为windows,linux和MAC,在平常的使用中并没有什么问题,但是在交叉编译场景的发生,却有不得不注意的问题
一、Golang为什么分不同的操作系统版本?
在linux中,一切皆文件,内核不同,Linux操作系统使用Linux内核,Windows操作系统使用NT内核;Linux内核代码开源,NT内核代码闭源,在针对读取操作系统本身信息的Go语言包,便有了不同之处
二、包
1.syscall
syscall 是语言与系统交互的唯一手段,其重要性不言而喻,所以此包也是go语言在linux与windows最大的不同之处,下面举几个实际应用场景
- Linux读取磁盘容量
type Disk struct {
All uint64 `json:"all"`
Used uint64 `json:"used"`
Free uint64 `json:"free"`
}
func xx(){
fs := syscall.Statfs_t{}
err := syscall.Statfs(path, &fs)
if err != nil {
return 0,err
}
disk.All = fs.Blocks * uint64(fs.Bsize) //总容量
disk.Free = fs.Bfree * uint64(fs.Bsize) //空闲容量
disk.Used = disk.All - disk.Free //已使用容量
}
其中syscall.Statfs_t{}
该结构体是Linux独有,在windows上是不存在的
- windows读取磁盘容量
func xxx() {
kernel32, err := syscall.LoadLibrary("Kernel32.dll")
if err != nil {
log.Panic(err)
}
defer syscall.FreeLibrary(kernel32)
GetDiskFreeSpaceEx, err := syscall.GetProcAddress(syscall.Handle(kernel32), "GetDiskFreeSpaceExW")
if err != nil {
log.Panic(err)
}
lpFreeBytesAvailable := int64(0)
lpTotalNumberOfBytes := int64(0)
lpTotalNumberOfFreeBytes := int64(0)
r, a, b := syscall.Syscall6(uintptr(GetDiskFreeSpaceEx), 4,
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr("C:"))),
uintptr(unsafe.Pointer(&lpFreeBytesAvailable)),
uintptr(unsafe.Pointer(&lpTotalNumberOfBytes)),
uintptr(unsafe.Pointer(&lpTotalNumberOfFreeBytes)), 0, 0)
log.Printf("Available %dmb", lpFreeBytesAvailable/1024/1024.0)
log.Printf("Total %dmb", lpTotalNumberOfBytes/1024/1024.0)
log.Printf("Free %dmb", lpTotalNumberOfFreeBytes/1024/1024.0)
}
当然,go对windows读取信息的操作还是最弱的,远不及linux
再举个例子,使用Go语言获取系统IP
- windows获取系统IP
func getAdapterList() (*syscall.IpAdapterInfo, error) {
b := make([]byte, 1000)
l := uint32(len(b))
a := (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0]))
err := syscall.GetAdaptersInfo(a, &l)
if err == syscall.ERROR_BUFFER_OVERFLOW {
b = make([]byte, l)
a = (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0]))
err = syscall.GetAdaptersInfo(a, &l)
}
if err != nil {
return nil, os.NewSyscallError("GetAdaptersInfo", err)
}
return a, nil
}
其中syscall
包的部分结构体
,函数
又是linux中没有的
- Linux获取系统IP
netInterfaces, err := net.Interfaces()
if err != nil {
fmt.Println("net.Interfaces failed, err:", err.Error())
return false
}
for i := 0; i < len(netInterfaces); i++ {
if (netInterfaces[i].Flags & net.FlagUp) != 0 {
addrs, _ := netInterfaces[i].Addrs()
for _, address := range addrs {
if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
if ipnet.IP.To4() != nil {
fmt.Println(ipnet.IP.String())
return true
}
}
}
}
}
当然,这里用到了net
包,此方法winodws与linux都可以使用
2.runtime
runtime调度器是非常有用的东西,主要使用的是内存的相关操作,关于runtime包几个方法:
-
Gosched:让当前线程让出cpu以让其他线程运行,它不会挂起当前线程,因此当前线程未来会继续执行
-
NumCPU:返回当前系统的CPU核数量
-
GOMAXPROCS:设置最大的可同时使用的CPU核数
-
Goexit:退出当前goroutine(但是defer语句会照常执行)
-
NumGoroutine:返回真该执行和排队的任务总数
-
GOOS:目标操作系统
-
GOROOT:返回本机的GO路径
-
Linux下获取内存占用
type MemStatus struct {
All uint32 `json:"all"`
Used uint32 `json:"used"`
Free uint32 `json:"free"`
Self uint64 `json:"self"`
}
func MemStat() MemStatus {
//自身占用
memStat := new(runtime.MemStats)
runtime.ReadMemStats(memStat)
mem := MemStatus{}
mem.Self = memStat.Alloc
//系统占用,仅linux/mac下有效
sysInfo := new(syscall.Sysinfo_t)
err := syscall.Sysinfo(sysInfo)
if err == nil {
mem.All = sysInfo.Totalram * uint32(syscall.Getpagesize())
mem.Free = sysInfo.Freeram * uint32(syscall.Getpagesize())
mem.Used = mem.All - mem.Free
}
return mem
}
- window获取内存占用
var m runtime.MemStats
runtime.ReadMemStats(&m)
fmt.Printf("%+v\\n", m)
fmt.Printf("os %d\\n", m.Sys)
主要是 runtime.MemStats
结构体,这里面字段较多,如果只是想了解占用 OS 的内存,可以查看其中的 Sys字段。当然,如同上例一样,在获取内存上,windows对于Go是不太友好的
解决方案
- 第三方包
github.com/shirou/gopsutil
- CPU
import "github.com/shirou/gopsutil/cpu"
// cpu info
func getCpuInfo() {
cpuInfos, err := cpu.Info()
if err != nil {
fmt.Printf("get cpu info failed, err:%v", err)
}
for _, ci := range cpuInfos {
fmt.Println(ci)
}
// CPU使用率
for {
percent, _ := cpu.Percent(time.Second, false)
fmt.Printf("cpu percent:%v\\n", percent)
}
}
- Memory
import "github.com/shirou/gopsutil/mem"
// mem info
func getMemInfo() {
memInfo, _ := mem.VirtualMemory()
fmt.Printf("mem info:%v\\n", memInfo)
}
但是该包所包含的功能又不尽然,如果已经可以满足即可考虑使用
- Linux使用
exec.Command("bash", "-c", command)
可直接读取到想要的信息,例如,exec.Command("bash", "-c","ifconfig")
读取网络信息,但需要##注意##的是返回的参数如果是多行,在使用strings
包解析时许多空格或其他内容读出来会是二进制等内容,这里建议将读出的字符串写入文件,然后使用打开文件再解析的方式
总结
总的来说,除了特定场景,windows与linux的交叉编译还是没有问题的,但是当必须与冲突点打交道时,只能选择合适的方式规避,期待Go官方或者有团队的第三方解决该类问题,以上仅为暂时在开发中发现的问题~
以上是关于Golang在windows与linux的部分区别的主要内容,如果未能解决你的问题,请参考以下文章
做10年Windows程序员与做10年Linux程序员的区别