Process analysis
With the help of TCP, the basic idea is as follows:
- The sender (client) sends the file name to the server, and the server saves the file name.
- The receiver (server) returns a message ok to the client to confirm that the file name is saved successfully.
- After receiving the message, the sender (client) begins to send the file data to the server.
- The receiver (server) reads the content of the file and writes it to the previously saved file.
Because the file transmission needs a stable and reliable connection, TCP mode is used to complete the network file transmission function.
First get the filename. The stat() function in the os package is used to obtain the file attribute information. Include the file name and file size in the file properties returned by the function. Stat parameter name passed in the absolute path of file access. The Name() function in FileInfo can extract the file list independently.
func Stat(name string) (fi FileInfo, err error)
Stat returns a FileInfo that describes the file object specified by name. If the specified file object is a symbolic link, the returned FileInfo describes the information of the file that the symbolic link points to, and this function will try to jump the link. If there is an error, the error value returned is of type * PathError.
We can know from the source code that FileInfo is an interface. To implement this interface, we must implement all the following methods of this interface
In fact, the realization of network file transmission relies on the knowledge of local file replication and TCP network programming. Let's have a look first Copying files in Go language and Go network programming Learn about it.
So the general steps of using TCP to realize file transfer can be summed up as follows
Receiver:
- Create a listener and close it at the end of the program.
- Block and wait for the client to connect to Conn, and close conn at the end of the program.
- Read client send file name. Save the fileName.
- Send back "ok".
- The encapsulation function RecvFile receives the file content sent by the client. Parameters fileName and conn
- Create file by file name, Close at the end
- Loop Read the network file content of the sender. When reading 0, it means that the file has been Read.
- Write the read content to the created file intact
Receiver code:
package main import ( "fmt" "io" "net" "os" ) func recvFile(conn net.Conn, fileName string) { //Create a new file by file name file, err := os.Create(fileName) if err != nil { fmt.Printf("os.Create()Function execution error, error is:%v\n", err) return } defer file.Close() //Read data from network and write to local file for { buf := make([]byte, 4096) n, err := conn.Read(buf) //Write to local file, read and write file.Write(buf[:n]) if err != nil { if err == io.EOF { fmt.Printf("Receive file complete.\n") } else { fmt.Printf("conn.Read()Method execution error, error is:%v\n", err) } return } } } func main() { //1. Create a listening socket listener, err := net.Listen("tcp", "127.0.0.1:8000") if err != nil { fmt.Printf("net.Listen()Function execution error, error is:%v\n", err) return } defer listener.Close() //Blocking monitoring conn, err := listener.Accept() if err != nil { fmt.Printf("listener.Accept()Method execution error, error is:%v\n", err) return } defer conn.Close() //The file name cannot be longer than 1024 bytes buf := make([]byte, 4096) n, err := conn.Read(buf) if err != nil { fmt.Printf("conn.Read()Method execution error, error is:%v\n", err) return } fileName := string(buf[:n]) //Write back ok to the sender conn.Write([]byte("ok")) //Get file content recvFile(conn, fileName) }
Sending end:
- Prompts you to enter a file name using command line parameters. Receive filename filepath (including access path)
- Use os.Stat() to get the file properties and get the pure fileName (remove the access path)
- Initiate the connection server request actively, and close the connection at the end.
- Send filename to receiver conn.Write()
- Read the confirmation data sent back by the receiver conn.Read()
- Judge whether it is "ok". If so, encapsulate the SendFile() function to send the contents of the file. Parameters filePath and conn
- Read only Open file, Close file at the end
- Read the local file circularly, read EOF, and finish reading.
- Send the read content to the receiver (server) intact conn.Write
Sender Code:
package main import ( "fmt" "io" "net" "os" ) func sendFile(conn net.Conn, filePath string) { //Read only open file file, err := os.Open(filePath) if err != nil { fmt.Printf("os.Open()Function execution error, error is:%v\n", err) return } defer file.Close() buf := make([]byte, 4096) for { //Read the data from the local file and write it to the network receiver. How much to read, how much to write n, err := file.Read(buf) if err != nil { if err == io.EOF { fmt.Printf("Send file complete\n") } else { fmt.Printf("file.Read()Method execution error,Error is:%v\n", err) } return } //Write to network socket _, err = conn.Write(buf[:n]) } } func main() { //Get command line parameters list := os.Args if len(list) != 2 { fmt.Printf("Format is:go run xxx.go file name\n") return } //Absolute path to extract file path := list[1] //Get file properties fileInfo, err := os.Stat(path) if err != nil { fmt.Printf("os.Stat()Function execution error, error is:%v\n", err) return } //Initiate connection request actively conn, err := net.Dial("tcp", "127.0.0.1:8000") if err != nil { fmt.Printf("net.Dial()Function execution error, error is:%v\n", err) return } defer conn.Close() //Send file name to receiver _, err = conn.Write([]byte(fileInfo.Name())) //Read server postback data buf := make([]byte, 4096) n, err := conn.Read(buf) if err != nil { fmt.Printf("conn.Read(buf)Method execution error, error is:%v\n", err) return } if string(buf[:n]) == "ok" { //Write file content to server -- with conn sendFile(conn, path) } }