Golang TFTP 服务器和客户端库

用于 Golang 的 TFTP 服务器和客户端库。「TFTP server and client library for Golang」

  • 所有者: pin/tftp
  • 平台: Linux,Mac,Windows
  • 許可證: MIT License
  • 分類:
  • 主題:
  • 喜歡:
    0
      比較:

Github星跟蹤圖

TFTP server and client library for Golang

GoDoc

Implements:

Partially implements (tsize server side only):

  • RFC 2349 - TFTP Timeout Interval and Transfer Size Options

Set of features is sufficient for PXE boot support.

import "github.com/pin/tftp/v3"

The package is cohesive to Golang io and implements
io.ReaderFrom and io.WriterTo interfaces. That allows efficient data
transmission without unnecessary memory copying and allocations.

TFTP Server


// readHandler is called when client starts file download from server
func readHandler(filename string, rf io.ReaderFrom) error {
	file, err := os.Open(filename)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v\n", err)
		return err
	}
	n, err := rf.ReadFrom(file)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v\n", err)
		return err
	}
	fmt.Printf("%d bytes sent\n", n)
	return nil
}

// writeHandler is called when client starts file upload to server
func writeHandler(filename string, wt io.WriterTo) error {
	file, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0644)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v\n", err)
		return err
	}
	n, err := wt.WriteTo(file)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v\n", err)
		return err
	}
	fmt.Printf("%d bytes received\n", n)
	return nil
}

func main() {
	// use nil in place of handler to disable read or write operations
	s := tftp.NewServer(readHandler, writeHandler)
	s.SetTimeout(5 * time.Second) // optional
	err := s.ListenAndServe(":69") // blocks until s.Shutdown() is called
	if err != nil {
		fmt.Fprintf(os.Stdout, "server: %v\n", err)
		os.Exit(1)
	}
}

See gotftpd in golang-tftp-example repository for working code.

TFTP Client

Upload file to server:

c, err := tftp.NewClient("172.16.4.21:69")
file, err := os.Open(path)
c.SetTimeout(5 * time.Second) // optional
rf, err := c.Send("foobar.txt", "octet")
n, err := rf.ReadFrom(file)
fmt.Printf("%d bytes sent\n", n)

Download file from server:

c, err := tftp.NewClient("172.16.4.21:69")
wt, err := c.Receive("foobar.txt", "octet")
file, err := os.Create(path)
// Optionally obtain transfer size before actual data.
if n, ok := wt.(tftp.IncomingTransfer).Size(); ok {
	fmt.Printf("Transfer size: %d\n", n)
}
n, err := wt.WriteTo(file)
fmt.Printf("%d bytes received\n", n)

See goftp in golang-tftp-example repository for working code.

TSize option

PXE boot ROM often expects tsize option support from a server: client
(e.g. computer that boots over the network) wants to know size of a
download before the actual data comes. Server has to obtain stream
size and send it to a client.

Often it will happen automatically because TFTP library tries to check
if io.Reader provided to ReadFrom method also satisfies
io.Seeker interface (os.File for instance) and uses Seek to
determine file size.

In case io.Reader you provide to ReadFrom in read handler does not
satisfy io.Seeker interface or you do not want TFTP library to call
Seek on your reader but still want to respond with tsize option
during outgoing request you can use an OutgoingTransfer interface:


func readHandler(filename string, rf io.ReaderFrom) error {
	...
	// Set transfer size before calling ReadFrom.
	rf.(tftp.OutgoingTransfer).SetSize(myFileSize)
	...
	// ReadFrom ...

Similarly, it is possible to obtain size of a file that is about to be
received using IncomingTransfer interface (see Size method).

Local and Remote Address

The OutgoingTransfer and IncomingTransfer interfaces also provide
the RemoteAddr method which returns the peer IP address and port as
a net.UDPAddr. The RequestPacketInfo interface provides a
LocalIP method with returns the local IP address as a net.IP that
the request is being handled on. These can be used for detailed
logging in a server handler, among other things.

Note that LocalIP may return nil or an unspecified IP address
if finding that is not supported on a particular operating system by
the Go net libraries, or if you call it as a TFTP client.


func readHandler(filename string, rf io.ReaderFrom) error {
        ...
        raddr := rf.(tftp.OutgoingTransfer).RemoteAddr()
        laddr := rf.(tftp.RequestPacketInfo).LocalIP()
        log.Println("RRQ from", raddr.String(), "To ",laddr.String())
        log.Println("")
        ...
        // ReadFrom ...

Backoff

The default backoff before retransmitting an unacknowledged packet is a
random duration between 0 and 1 second. This behavior can be overridden
in clients and servers by providing a custom backoff calculation function.

	s := tftp.NewServer(readHandler, writeHandler)
	s.SetBackoff(func (attempts int) time.Duration {
		return time.Duration(attempts) * time.Second
	})

or, for no backoff

	s.SetBackoff(func (int) time.Duration { return 0 })

Distribution packages

主要指標

概覽
名稱與所有者pin/tftp
主編程語言Go
編程語言Go (語言數: 1)
平台
許可證MIT License
所有者活动
創建於2014-11-04 03:46:35
推送於2025-04-16 21:56:07
最后一次提交2025-01-06 19:21:29
發布數7
最新版本名稱v3.1.0 (發布於 )
第一版名稱v1 (發布於 )
用户参与
星數301
關注者數5
派生數74
提交數215
已啟用問題?
問題數21
打開的問題數6
拉請求數60
打開的拉請求數3
關閉的拉請求數20
项目设置
已啟用Wiki?
已存檔?
是復刻?
已鎖定?
是鏡像?
是私有?