借助TCP完成文件的传输,基本思路如下:
1.客户端向服务器发送文件名,服务器保存该文件名。
2.服务端向客户端返回去一个消息ok,确认文件名保存成功。
3.客户端收到消息后,开始向服务器发送文件数据。
4.服务端读取文件内容,写入到之前保存好的文件中。
示意图大致如下:
首先获取文件名,借助os包中的stat()函数来获取文件属性信息。在函数返回的文件属性中包含文件名和文件大小。Stat函数传入参数name是文件访问的绝对路径。
func Stat (name string) (FileInfo , error)
type FileInfo interface{
Name() string //文件名字
Size() int64 //文件大小
IsDir() bool //是否是一个目录
........
}
实现一个网络文件传输的例子:
发送方:
package main import ( "fmt" "io" "net" "os" ) func main() { //1.获取命令行参数 list := os.Args if len(list) != 2{ fmt.Println("需要两个参数") return } //2.提取文件的绝对路径 exp :/home/sxf/hh filePath := list[1] //3.提取不包含路径的文件名 exp:hh fileInfo ,err := os.Stat(filePath)//fileInfo中包含文件名和文件大小 if err != nil{ fmt.Println("os.Stat err",err) return } fileName :=fileInfo.Name() //文件名hh fileSize :=fileInfo.Size() //文件大小 fmt.Println("文件名:",fileName) fmt.Println("文件大小",fileSize) //4.主动发起连接请求 conn ,err := net.Dial("tcp","127.0.0.1:8000") if err != nil{ fmt.Println("net.Dial err",err) return } defer conn.Close() //5.发送文件名给接收端 conn.Write([]byte(fileName)) //6.读取接收端回发的响应数据(ok) buf := make([]byte,4096) n, err := conn.Read(buf) if err != nil{ fmt.Println("conn.Read err",err) return } //7.判断这个数据是否是ok if "ok" == string(buf[:n]){ //8.是ok,写文件内容给接收端--借助conn sendcontent(conn,filePath) } } //发送文件内容给接受端 func sendcontent(conn net.Conn,filePath string) { //8.1只读打开文件 f,err := os.Open(filePath) if err != nil{ fmt.Println("os.Open err",err) return } defer f.Close() //8.2从本地文件读数据,写给接收端 buf := make([]byte,4096) for { n,err :=f.Read(buf) //读取本地文件放入缓冲区buf中 if err != nil{ if err == io.EOF { fmt.Println("读取文件完成") }else { fmt.Println("f.Read err",err) } return } _,err =conn.Write(buf[:n])//将缓冲区buf中数据写到网络socket中 if err != nil{ fmt.Println("conn.Write err",err) return } } }接收方:
package main import ( "fmt" "net" "os" ) func main() { //1.指定服务器通信协议、IP地址、Port端口,创建一个用于监听的socket---listener listener ,err := net.Listen("tcp","127.0.0.1:8008") if err != nil{ fmt.Println("net.Listener err:",err) return } defer listener.Close()//关闭socket //2.阻塞监听客户端连接请求,成功建立连接,返回用于通信的socket---conn conn ,err := listener.Accept() if err != nil{ fmt.Println("listener.Accept err:",err) return } defer conn.Close()//关闭socket //3.从conn套接字中获取文件名,写入缓存buf中 buf := make([]byte,4096) n ,err := conn.Read(buf) if err != nil{ fmt.Println("conn.Read err:",err) return } //4.从buf中提取文件名 fileName := string(buf[:n]) //5.回写给发送端ok conn.Write([]byte("ok")) //6.获取文件内容 recivefile(conn,fileName) } func recivefile(conn net.Conn,fileName string) { //6.1按照文件名创建新文件 f,err := os.Create(fileName) if err != nil{ fmt.Println("os.Create err:",err) return } defer f.Close() //6.2从网络socket中读数据,写入本地文件中 buf := make([]byte,4096) for { n,_ := conn.Read(buf) //从conn中读数据到buf中 if n == 0{ //判断是否读取数据完毕 fmt.Println("接收文件完毕") return } //将buf中的数据写入到本地文件 f.Write(buf[:n]) } }发送方发送本地的一个文件给接收方:
接收方收到文件,接收到的文件在GOPATH/src目录下