网络文件传输(客户端上传本地文件到服务器)
借助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目录下