Go語言簡單實現FTP協議.
阿新 • • 發佈:2019-01-25
package ftp import ( "errors" "fmt" "io" "net" "os" "strconv" "strings" ) type Ftp struct { con net.Conn ip string } func NewFtp(ip string) (*Ftp, error) { buf := make([]byte, 1024) con, err := net.Dial("tcp", ip) if err != nil { return nil, err } n, err := con.Read(buf) if err != nil { return nil, err } fmt.Println(string(buf[:n])) return &Ftp{con, ip}, nil } func (self *Ftp) Login(user, pass string) error { buf := make([]byte, 1024) self.con.Write([]byte(fmt.Sprintf("USER %s\r\n", user))) self.con.Read(buf) self.con.Write([]byte(fmt.Sprintf("PASS %s\r\n", pass))) n, err := self.con.Read(buf) if err != nil { return err } if !strings.Contains(string(buf[:n]), "230 Logged on") { return errors.New(strings.TrimSpace(string(buf))) } return nil } func (self *Ftp) PutPasv(Pathname string) error { con, err := self.connection("STOR", Pathname) if err != nil { return err } File, err := os.Open(Pathname) if err != nil { con.Close() return err } io.Copy(con, File) File.Close() con.Close() buf := make([]byte, 1024) _, err = self.con.Read(buf) if err != nil { return err } return nil } func (self *Ftp) GetFile(Pathname string) error { con, err := self.connection("RETR", Pathname) if err != nil { return err } File, err := os.Create(Pathname) if err != nil { con.Close() return err } io.Copy(File, con) File.Close() con.Close() buf := make([]byte, 1024) _, err = self.con.Read(buf) if err != nil { return err } return nil } func (self *Ftp) connection(status, Pathname string) (net.Conn, error) { buf := make([]byte, 1024) self.con.Write([]byte("PASV \r\n")) n, err := self.con.Read(buf) if err != nil { return nil, err } if s := string(buf[:n]); !strings.Contains(s, "227 Entering Passive Mode") { return nil, errors.New(s) } port := getport(buf[27 : n-3]) con, err := net.Dial("tcp", fmt.Sprintf("%s:%d", strings.Split(self.ip, ":")[0], port)) if err != nil { return nil, err } self.con.Write([]byte(fmt.Sprintf("%s %s\r\n", status, Pathname))) n, err = self.con.Read(buf) if err != nil { con.Close() return nil, err } if !strings.Contains(string(buf[:n]), "150 Opening data channel") { con.Close() return nil, errors.New("create data link error.") } return con, nil } func getport(by []byte) int { s := string(by) list := strings.Split(s, ",") n1, err := strconv.Atoi(list[len(list)-2]) if err != nil { return 0 } n2, err := strconv.Atoi(list[len(list)-1]) if err != nil { return 0 } return n1*256 + n2 }