禪院真希 發表於 2025-12-27 09:10:50

golang实现ftp功能简单又实用(示例代码)

<p>配置文件部分:</p>
<div class="jb51code"><pre class="brush:go;">FtpServer:
ListenAddr: ":2121"
ListenDir: "/data/ftpwww" # ftp目录
PassivePortRange: # end必须大于start,否则会panic, 非被动模式不用配置
    Start: 3121
    End: 3124
ListenUsers: # ftp账号
    - Username: ftpadmin
      Password: "123456..."
    - Username: ftpadmin
      Password: "yueduo-654321..."</pre></div>
<p>加载配置文件</p>
<div class="jb51code"><pre class="brush:go;">package config
import (
        "fmt"
        "gopkg.in/yaml.v3"
        "os"
)
var (
        Conf Config
)
type Config struct {
...
        FtpServerFtpServer`yaml:"FtpServer"`
...
}
func InitConfigFromYaml(file string) error {
        if file == "" {
                file = "config.yaml"
        }
        f, err := os.Open(file)
        if err != nil {
                return fmt.Errorf("配置文件打开错误.%w", err)
        }
        dec := yaml.NewDecoder(f)
        err = dec.Decode(&amp;Conf)
        if err != nil {
                return err
        }
        return nil
}</pre></div>
<p>main.go引用</p>
<div class="jb51code"><pre class="brush:go;">//初始化配置文件
        err := config.InitConfigFromYaml(f)
        if err != nil {
                logn.Errorf("配置文件初始化错误,file:%s 错误信息:%v", f, err)
                return
        }
// 加载ftp
        go ftp.FtpDirver()</pre></div>
<p>ftp部分perm</p>
<div class="jb51code"><pre class="brush:go;">package ftp
import (
        "fmt"
        "os"
)
// 加载文件权限只读
type ReadOnlyPerm struct{}
func (p *ReadOnlyPerm) GetOwner(path string) (string, error) {
        return "ftp", nil
}
func (p *ReadOnlyPerm) GetGroup(path string) (string, error) {
        return "ftp", nil
}
func (p *ReadOnlyPerm) GetMode(path string) (os.FileMode, error) {
        // 0444: 只读(r--r--r--)
        return 0444, nil
}
func (p *ReadOnlyPerm) ChOwner(path, owner string) error {
        return fmt.Errorf("permission denied")
}
func (p *ReadOnlyPerm) ChGroup(path, group string) error {
        return fmt.Errorf("permission denied")
}
func (p *ReadOnlyPerm) ChMode(path string, mode os.FileMode) error {
        return fmt.Errorf("permission denied")
}</pre></div>
<p>dirver.go</p>
<div class="jb51code"><pre class="brush:go;">package ftp
import (
        "fmt"
        filedriver "github.com/goftp/file-driver"
        "github.com/goftp/server"
        "io"
        "log"
        "net"
        "os"
        "safe-agent/config"
)
type MultiUserAuth struct {
        users mapconfig.FTPUser
}
type PerUserDriverFactory struct {
        users mapconfig.FTPUser
}
type PerUserFileDriver struct {
        *filedriver.FileDriver
        users mapconfig.FTPUser
}
func (d *PerUserFileDriver) Init(conn *server.Conn) {
        // 🔥 每个用户设置自己的根目录
        d.FileDriver.RootPath = config.Conf.FtpServer.ListenDir
}
func (d *PerUserFileDriver) Delete(path string) error {
        return fmt.Errorf("550 permission denied")
}
func (d *PerUserFileDriver) DeleteFile(path string) error {
        return fmt.Errorf("550 permission denied")
}
func (d *PerUserFileDriver) Rename(from, to string) error {
        return fmt.Errorf("550 permission denied")
}
func (d *PerUserFileDriver) PutFile(destPath string, data io.Reader, appendData bool) (int64, error) {
        return 0, fmt.Errorf("550 permission denied")
}
func (d *PerUserFileDriver) Chmod(path string, mode os.FileMode) error {
        return fmt.Errorf("550 permission denied")
}
func (d *PerUserFileDriver) Remove(path string) error {
        return fmt.Errorf("550 permission denied")
}
func (d *PerUserFileDriver) RemoveDir(path string) error {
        return fmt.Errorf("550 permission denied")
}
func (d *PerUserFileDriver) MakeDir(path string) error {
        return fmt.Errorf("550 permission denied")
}
func (f *PerUserDriverFactory) NewDriver() (server.Driver, error) {
        return &amp;PerUserFileDriver{
                FileDriver: &amp;filedriver.FileDriver{
                        Perm: &amp;ReadOnlyPerm{},
                },
                users: f.users,
        }, nil
}
func (a *MultiUserAuth) CheckPasswd(user, pass string) (bool, error) {
        u, ok := a.users
        if !ok {
                return false, nil
        }
        return u.Password == pass, nil
}
func FtpDirver() {
        userMap := make(mapconfig.FTPUser)
        for _, u := range config.Conf.FtpServer.ListenUsers {
                userMap = u
        }
        host, portStr, _ := net.SplitHostPort(config.Conf.FtpServer.ListenAddr)
        port := 0
        if portStr != "" {
                fmt.Sscanf(portStr, "%d", &amp;port)
        }
        passiveRange := config.Conf.FtpServer.PassivePortRange
        passivePorts := fmt.Sprintf("%d-%d", passiveRange.Start, passiveRange.End)
        opts := &amp;server.ServerOpts{
                Factory: &amp;PerUserDriverFactory{
                        users: userMap,
                },
                PassivePorts: passivePorts,
                Auth:         &amp;MultiUserAuth{users: userMap},
                Port:         port,
                Hostname:   host,
        }
        //log.Printf("FTP server listening on %s", config.Conf.FtpServer.ListenAddr)
        fmt.Printf(
                "FTP listen=%s passive_ports=%s",
                config.Conf.FtpServer.ListenAddr,
                passivePorts,
        )
        s := server.NewServer(opts)
        log.Fatal(s.ListenAndServe())
}</pre></div>
頁: [1]
查看完整版本: golang实现ftp功能简单又实用(示例代码)