基于Smb协议实现网络文件传输(Golang)

news2025/1/12 3:51:32

在前面章节已经展示了一些关于SMB的基本介绍,以及对应SMB相关操作的Java实现,这一章主要是前一章的补充,使用Golang来对 SMB共享文件夹进行操作。如果没有阅读过上一章节的同学,请跳转到 基于Smb协议实现网络文件传输,本文不再重复介绍。

版本介绍

本文使用到的主要框架版本如下

  • Golang 1.20.5
  • github.com/gin-gonic/gin v1.9.1
  • github.com/hirochachacha/go-smb2 v1.1.0

Smb操作实现

smb2 包在 [MS-SMB2] 中实现了 SMB2/3 客户端
API文档:https://pkg.go.dev/github.com/hirochachacha/go-smb2

SMBClient.go 模块

导入依赖包

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

如果不能正常导入依赖包,可能会用到以下指令下载依赖包或者清理不必要依赖包 :

go get -u
go mod tidy

创建SMBClient 类

首先我们定义和初始化SMBClient类用到的变量

type SMBClient struct {
	conn    net.Conn
	dialer  *smb2.Dialer
	session *smb2.Session
	share   *smb2.Share
}

func NewSMBClient(server, username, password, sharename string) (*SMBClient, error) {
	conn, err := net.Dial("tcp", server+":445")
	if err != nil {
		return nil, err
	}

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

	s, err := d.Dial(conn)
	if err != nil {
		return nil, err
	}

	share, err := s.Mount(sharename)
	if err != nil {
		return nil, err
	}

	return &SMBClient{
		conn:    conn,
		dialer:  d,
		session: s,
		share:   share,
	}, nil
}

封装 SMBClient类的常用方法

把一些常用的增删改查操作封装在SMBClient

func (c *SMBClient) Close() {
	c.share.Umount()
	c.session.Logoff()
	c.conn.Close()
}

func (c *SMBClient) Upload(localPath, remotePath string) error {
	srcFile, err := os.Open(localPath)
	if err != nil {
		return err
	}
	defer srcFile.Close()

	dstFile, err := c.share.Create(remotePath)
	if err != nil {
		return err
	}
	defer dstFile.Close()

	_, err = io.Copy(dstFile, srcFile)
	if err != nil {
		return err
	}

	return nil
}

func (c *SMBClient) getMatchingFiles(basePath, pattern string) ([]string, error) {
	var results []string
	regex := regexp.MustCompile(pattern)

	fis, err := c.share.ReadDir(basePath)
	if err != nil {
		return nil, err
	}

	for _, fi := range fis {
		if !fi.IsDir() && regex.MatchString(fi.Name()) {
			results = append(results, basePath+"/"+fi.Name())
		}
	}

	return results, nil
}

func (c *SMBClient) Download(basePath, remotePattern, localPath string) error {
	matchingFiles, err := c.getMatchingFiles(basePath, remotePattern)
	if err != nil {
		return err
	}

	for _, remoteFIle := range matchingFiles {
		srcFile, err := c.share.Open(remoteFIle)
		if err != nil {
			return err
		}
		defer srcFile.Close()
		stat, err := srcFile.Stat()
		if err != nil {
			return err
		}
		dstFile, err := os.Create(localPath + stat.Name())
		if err != nil {
			return err
		}
		defer dstFile.Close()

		_, err = io.Copy(dstFile, srcFile)
		if err != nil {
			return err
		}
	}

	return nil
}

func (c *SMBClient) Delete(basePath, remotePattern string) error {
	matchingFiles, err := c.getMatchingFiles(basePath, remotePattern)
	if err != nil {
		return err
	}

	for _, remotePath := range matchingFiles {
		err := c.share.Remove(remotePath)
		if err != nil {
			return err
		}
	}

	return nil
}

func (c *SMBClient) Rename(basePath, oldPattern, suffix string) error {
	matchingFiles, err := c.getMatchingFiles(basePath, oldPattern)
	if err != nil {
		return err
	}

	for _, oldPath := range matchingFiles {
		err := c.share.Rename(oldPath, oldPath+suffix)
		if err != nil {
			return err
		}
	}

	return nil
}

func (c *SMBClient) Search(basePath, pattern string) ([]string, error) {
	return c.getMatchingFiles(basePath, pattern)
}

SMBMain.go 模块

该模块是程序入口,这里使用到了Gin作为Web框架,方便大家通过 API调用SMB相关操作进行测试。

import (
	"fmt"
	"github.com/gin-gonic/gin"
)

func main() {
	client, err := NewSMBClient("192.168.50.69", "user", "123456", "LANdrive")
	if err != nil {
		panic(err)
	}
	defer client.Close()

	router := gin.Default()

	router.POST("/upload", func(c *gin.Context) {
		localPath := c.PostForm("localPath")
		remotePath := c.PostForm("remotePath")
		fmt.Printf("localPath: %s, remotePath: %s\n", localPath, remotePath)
		err := client.Upload(localPath, remotePath)
		if err != nil {
			c.JSON(500, gin.H{"error": err.Error()})
			return
		}
		c.JSON(200, gin.H{"message": "Upload successful"})
	})

	router.GET("/download", func(c *gin.Context) {
		basePath := c.Query("basePath")
		remotePattern := c.Query("remotePattern")
		localPath := c.Query("localPath")

		err := client.Download(basePath, remotePattern, localPath)
		if err != nil {
			c.JSON(500, gin.H{"error": err.Error()})
			return
		}
		c.JSON(200, gin.H{"message": "Download successful"})
	})

	router.PUT("/rename", func(c *gin.Context) {
		basePath := c.Query("basePath")
		oldPattern := c.Query("oldPattern")
		suffix := c.Query("suffix")

		err := client.Rename(basePath, oldPattern, suffix)
		if err != nil {
			c.JSON(500, gin.H{"error": err.Error()})
			return
		}
		c.JSON(200, gin.H{"message": "Rename successful"})
	})

	router.GET("/search", func(c *gin.Context) {
		basePath := c.Query("basePath")
		pattern := c.Query("pattern")

		results, err := client.Search(basePath, pattern)
		if err != nil {
			c.JSON(500, gin.H{"error": err.Error()})
			return
		}
		c.JSON(200, gin.H{"files": results})
	})

	router.DELETE("/delete", func(c *gin.Context) {
		basePath := c.Query("basePath")
		remotePattern := c.Query("remotePattern")

		err := client.Delete(basePath, remotePattern)
		if err != nil {
			c.JSON(500, gin.H{"error": err.Error()})
			return
		}
		c.JSON(200, gin.H{"message": "Delete successful"})
	})

	router.Run(":8080")
}

通过Postman进行调用

大家可以在本文后面的Github链接下载完整代码,运行SMBMain.go模块即可启动Web服务。

文件上传

这里我把本地的downloaded_file.txt文件上传到远程共享文件夹test目录,远程文件夹文件名为downloaded_file.ext

文件成功上传到共享文件夹

文件下载

这里把远程文件夹test下的所有文件下载到本地/Users/evan/Downloads/目录,remotePattern是匹配远程目录下文件的正则表达式

文件下载成功

文件查询

这里查询所有在远程test目录下符合.*正则表达式的文件

文件改名

这里把远程目录test下所有符合.*$的文件加上.d2后缀

远程文件改名成功

文件删除

这里把远程目录test下符合.*$正则表达式的文件删除

远程目录下的文件被删除成功

完整代码

链接: https://github.com/EvanLeung08/eshare-smb-client-in-golang

上面示例的Postman Collection已经到处到以下文件,直接把Golang SMB.postman_collection.json导入到你的Postman即可

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/679845.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Axure教程—折叠面手风琴效果

上文中介绍了用Axure制作折叠面板的基础制作,这次介绍折叠面板手机风琴效果 效果 预览地址:https://e18rf6.axshare.com 功能 点击标题展开内容,点击另一标题,其展开的内容折叠 制作 拖入四个动态面板,分别命名为1、…

PHP流程控制与文件包含:基础与关键要点

目录 PHP流程控制 顺序结构: 分支结构: Switch分支: PHP循环结构 for循环 while循环 do-while循环 while和do-while的区别: 循环控制 流程控制代替语法 PHP文件包含 PHP文件包含的作用 PHP文件包含的四种形式 PHP文…

【spring cloud学习】3、Eureka Server注册中心

Eureka本身是Netflix开源的一款注册中心产品,并且Spring Cloud提供了相应的集成封装。选择Eureka作为注册中心实例来讲解是出于以下原因: (1)Eureka在业界的应用十分广泛,整个框架经受住了Netflix严酷生产环境的考验。…

Qt中的信号和信号槽(一)

目录 1. 信号和槽概述 信号和槽的关系 2. 标准信号槽使用 标准信号/槽 示例: 3. 自定义信号槽使用 自定义信号 自定义槽 示例: 1. 信号和槽概述 信号和槽是一种事件驱动的通信机制,广泛应用于Qt框架的事件处理、GUI编程、网络通信等…

如何在教育与科研领域使用ChatGPT

ChatGPT提示是您给予ChatGPT的一系列指示,以便它能够按需生成结果。由于ChatGPT是一种会话型人工智能,因此它需要明确的指示才能生成准确的结果。 ChatGPT提示的结构通常是以指令格式呈现的。它看起来像是您在与AI交流,给予它执行特定任务的…

基于树莓派4B的OpenCV安装与简单应用(真速通版)

前言:本文为手把手教学树莓派4B的OpenCV安装与简单应用(真速通版本),树莓派4B最为目前最新款的树莓派家族一员深受创客和开发者喜爱。树莓派4B作为一款搭载 Cortex-A72 系列芯片的板载电脑,其不仅可以作为简单的 MCU 进…

第三方库介绍——Protobuf库(更高效的协议)

文章目录 protobuf综述传输协议与指令创建协议编译协议介绍addressbook.pb.h文件序列化与反序列化的接口 利用soctet实现客户端与服务端传输协议Linux(Ubuntu)安装protoc步骤编写案例代码Cartoon.prototcpsocket.hMyTcpsocket.hclient.cppserver.cppCMak…

01.4进程原理和系统调用--->经典的CFS调度器

进程的一些正常状态 什么是进程 操作系统作为硬件的使用层,提供使用硬件资源的能力,进程作为操作系统使用层, 提供使用操作系统抽象出的资源层的能力。 进程:是指计算机中已运行的程序。进程本身不是基本的运行单位,…

【微服务】springboot 通用限流方案设计与实现

目录 一、背景 二、限流概述 2.1 dubbo 服务治理模式 2.1.1 dubbo框架级限流 2.1.2 线程池设置 2.1.3 集成第三方组件 2.2 springcloud 服务治理模式 2.2.1 hystrix 2.2.2 sentinel 2.3 网关层限流 三、常用限流策略 3.1 限流常用的算法 3.1.1 令牌桶算法 3.1.2 …

2023最新Java面试八股文汇总(五十万字总结版)

写在前面 今年的疫情,让招聘面试变得雪上加霜。已经有不少大厂,如腾讯、字节跳动的招聘名额明显减少,面试门槛却一再拔高,如果不用心准备,很可能就被面试官怼得哑口无言,甚至失去了难得的机会。 现如今&a…

<Linux开发>驱动开发 -之- Linux RTC 驱动

<Linux开发>驱动开发 -之- Linux RTC 驱动 交叉编译环境搭建: <Linux开发> linux开发工具-之-交叉编译环境搭建 uboot移植可参考以下: <Linux开发> -之-系统移植 uboot移植过程详细…

Dubbo【 Dubbo概念(什么是分布式系统、什么是RPC、核心组件、Zookeeper注册中心 )】(一)-全面详解(学习总结---从入门到深化)

目录 Dubbo概念_什么是分布式系统 什么是分布式 Dubbo概念_什么是RPC Dubbo概念_简介 Dubbo概念_核心组件 Dubbo配置开发环境_Zookeeper注册中心 Dubbo配置开发环境_管理控制台 Dubbo入门案例_需求介绍 Dubbo入门案例_配置开发环境 Dubbo入门案例_服务生产者配置…

VLC-QT源码编译(Windows10+VS2020+MSVC20019+QT5.15)

参考VLC-Qt的编译与使用 windows10VS2019qt5.15 下载源码 VLC-QT https://github.com/vlc-qt/vlc-qt可以通过git或者直接下载ZIP文件,但是里面的libvlc-header和packaging没有下载下来,需要再自行下载。 VLC https://download.videolan.org/vlc/las…

行为型模式--备忘录模式

目录 概述 结构 案例实现 “白箱”备忘录模式 总结: “黑箱”备忘录模式 优缺点 优点: 缺点: 使用场景 概述 又叫快照模式,在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这…

zeromq的学习笔记

ctx_t 在创建ctx_t时,会设置以下参数 _io_thread_count io线程数默认是1 _max_sockets最大socket数是1023 _starting标识设置为true,此时socket还没有创建 _terminating设置为false,在调用zmq_ctx_term时该标识会设置为true _tag设置为ZMQ_CTX_TAG_VALUE_GOOD&…

mySql和VSC++

确认主机服务里的mysql服务已打开 使用组合键“winR”运行“services.msc”,进入本地服务窗口; 2.进入本地服务窗口后,在右侧服务列表中,查找到“ mysql ”服务选项; 3.查找到mysql服务选项后,双击打开mysq…

C++ 面向对象(3)——重载运算符和重载函数

C 允许在同一作用域中的某个函数和运算符指定多个定义,分别称为函数重载和运算符重载。 重载声明是指一个与之前已经在该作用域内声明过的函数或方法具有相同名称的声明,但是它们的参数列表和定义(实现)不相同。 当您调用一个重…

FDM3D打印系列——3、常用打印材料介绍

大家好,我是阿赵。 FDM3D打印机一般都可以支持多种打印材料的,下面来介绍一下几种常用的打印材料 一、PLA 使用FDM打印,最常见的材料就是PLA了 PLA(Polylactic acid),中文名为生物降解塑料聚乳酸&#…

网络安全面试题,渗透测试面试总结

1.什么是WebShell? WebShell就是以asp、php、jsp或者cgi等网页文件形式存在的─种命令执行环境,也可以将其称做为─种网页后门。黑客在入侵了─个网站后,通常会将这些asp或php后门文件与网站服务器WEB目录下正常的网页文件混在─起,然后就可…

【Vue3】生命周期(钩子)函数

在 Vue 3 中,生命周期函数已经被重新设计为钩子函数,并且与 Vue 2 中的生命周期函数有所不同,可以在 setup 函数中使用 onXXX 形式的钩子函数来执行对应的操作。以下是选项式 API 和组合式 API 中常用的几个钩子函数对比: beforeC…