Golang实现SMB2协议通信与认证的完整指南

Golang实现SMB2协议通信与认证的完整指南 大家好,

我一直在尝试从几个方面理解Go语言,但在SMB2配置方面遇到了很多麻烦:

包 smb2 包 smb2 实现了 [MS-SMB2] 中的 SMB2/3 客户端。

在这个模块中,有一个名为 *RemoteFileSystem 的类型。先不谈这个模块,在我运行以下代码后:

filesystem, err := client.Mount(host)
if err != nil {
panic(err)
}
defer filesystem.Umount()
fmt.Println(filesystem)

这会打印出以下内容: &{0xc000048650 0xc0000160d8}

我如何在程序中查看、导入并在后续使用这个值?例如: 在这个SMB2模块中,有很多函数可以使用 *RemoteFileSystem 结构体来调用。 例如: *RemoteFileSystem.Remove() *RemoteFileSystem.FileRead()

如果我想在我刚刚发布的语法中,将 ‘filesystem’ 的返回值用在另一个函数里,这该如何实现? 另外,如果有人能用更简单的方式向我解释一下如何操作 * 和 & 这些值,我将不胜感激。

谢谢!


更多关于Golang实现SMB2协议通信与认证的完整指南的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

谢谢,我已经解决了这个问题!

更多关于Golang实现SMB2协议通信与认证的完整指南的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你好,@T_pch

首先,你能把你的代码用 ``` 包裹起来以便正确格式化吗?例如:

code here

其次:如果你能打印那个 filesystem 对象,那么你也可以调用它的方法。你能说明一下你想做什么以及到目前为止你尝试过什么吗?

在Go中处理SMB2的*RemoteFileSystem时,你看到的是结构体指针的内存地址。以下是具体的使用方法:

1. 直接使用filesystem变量

你获取的filesystem已经是*RemoteFileSystem类型,可以直接调用其方法:

package main

import (
    "fmt"
    "github.com/hirochachacha/go-smb2"
    "net"
)

func main() {
    conn, err := net.Dial("tcp", "server:445")
    if err != nil {
        panic(err)
    }
    defer conn.Close()

    d := &smb2.Dialer{
        Initiator: &smb2.NTLMInitiator{
            User:     "username",
            Password: "password",
        },
    }

    client, err := d.Dial(conn)
    if err != nil {
        panic(err)
    }
    defer client.Logoff()

    // 获取RemoteFileSystem指针
    filesystem, err := client.Mount("sharename")
    if err != nil {
        panic(err)
    }
    defer filesystem.Umount()

    // 直接使用filesystem调用方法
    // 列出目录
    entries, err := filesystem.ReadDir(".")
    if err != nil {
        panic(err)
    }
    
    for _, entry := range entries {
        fmt.Println(entry.Name())
    }

    // 删除文件
    err = filesystem.Remove("test.txt")
    if err != nil {
        fmt.Println("删除失败:", err)
    }

    // 读取文件
    f, err := filesystem.Open("document.pdf")
    if err != nil {
        panic(err)
    }
    defer f.Close()

    buf := make([]byte, 1024)
    n, err := f.Read(buf)
    if err != nil {
        panic(err)
    }
    fmt.Printf("读取了 %d 字节\n", n)
}

2. 将filesystem传递给其他函数

package main

import (
    "fmt"
    "github.com/hirochachacha/go-smb2"
    "io"
    "net"
)

// 接受*RemoteFileSystem作为参数的函数
func listFiles(fs *smb2.RemoteFileSystem, path string) error {
    entries, err := fs.ReadDir(path)
    if err != nil {
        return err
    }
    
    for _, entry := range entries {
        fmt.Printf("%s (目录: %v)\n", entry.Name(), entry.IsDir())
    }
    return nil
}

// 另一个使用filesystem的函数
func copyFile(fs *smb2.RemoteFileSystem, src, dst string) error {
    srcFile, err := fs.Open(src)
    if err != nil {
        return err
    }
    defer srcFile.Close()

    dstFile, err := fs.Create(dst)
    if err != nil {
        return err
    }
    defer dstFile.Close()

    _, err = io.Copy(dstFile, srcFile)
    return err
}

func main() {
    // ... 连接和认证代码同上
    
    filesystem, err := client.Mount("sharename")
    if err != nil {
        panic(err)
    }
    defer filesystem.Umount()

    // 将filesystem传递给其他函数
    fmt.Println("目录列表:")
    if err := listFiles(filesystem, "."); err != nil {
        panic(err)
    }

    fmt.Println("\n复制文件:")
    if err := copyFile(filesystem, "source.txt", "destination.txt"); err != nil {
        panic(err)
    }
}

3. 关于 * 和 & 的解释

// * 表示指针类型
var fs *RemoteFileSystem  // fs是一个指向RemoteFileSystem的指针

// & 获取变量的地址(创建指针)
var value int = 42
var ptr *int = &value     // ptr现在指向value的内存地址

// 对于结构体
type RemoteFileSystem struct {
    client *Client
    share  string
}

// 创建实例并获取指针的两种方式:
// 方式1:使用new()
fs1 := new(RemoteFileSystem)  // fs1是*RemoteFileSystem类型

// 方式2:使用结构体字面量和&
fs2 := &RemoteFileSystem{      // fs2也是*RemoteFileSystem类型
    client: someClient,
    share:  "sharename",
}

// 当你调用client.Mount()时,它返回的就是&RemoteFileSystem{...}

4. 实际使用示例:完整的文件操作

func performFileOperations(fs *smb2.RemoteFileSystem) {
    // 创建目录
    err := fs.Mkdir("newfolder", 0755)
    if err != nil {
        fmt.Println("创建目录失败:", err)
    }

    // 创建并写入文件
    file, err := fs.Create("newfolder/test.txt")
    if err != nil {
        panic(err)
    }
    
    _, err = file.Write([]byte("Hello SMB2!"))
    if err != nil {
        panic(err)
    }
    file.Close()

    // 重命名文件
    err = fs.Rename("newfolder/test.txt", "newfolder/renamed.txt")
    if err != nil {
        panic(err)
    }

    // 获取文件信息
    info, err := fs.Stat("newfolder/renamed.txt")
    if err != nil {
        panic(err)
    }
    fmt.Printf("文件大小: %d 字节\n", info.Size())
}

// 在主函数中调用
func main() {
    // ... 建立连接和认证
    
    filesystem, err := client.Mount("sharename")
    if err != nil {
        panic(err)
    }
    defer filesystem.Umount()

    // 直接使用filesystem
    performFileOperations(filesystem)
}

你看到的&{0xc000048650 0xc0000160d8}是结构体指针的默认字符串表示,显示的是两个字段的内存地址。在实际使用中,你不需要直接操作这些地址值,只需要使用filesystem变量来调用SMB2提供的方法即可。

回到顶部