[英]TCP client / server file transfer in Go
I'm new to Go and I'm having troubles debugging this client / server file transfer code. 我是Go的新手,我在调试此客户端/服务器文件传输代码时遇到了麻烦。 When I request a 719kb png file from the server, I get the 719kb.. but not perfectly, the png when I open it isn't completely displayed (some is cut off. Where am I going wrong here? 当我从服务器请求一个719kb的png文件时,我得到719kb ..但不完美,当我打开它时png没有完全显示(有些被切断了。我在哪里错了?
// CLIENT ///
package main
import (
"bufio"
"bytes"
"fmt"
"io"
"log"
"net"
"os"
"strings"
)
const BUFFER_SIZE = 1024
func main() {
//get port and ip address to dial
if len(os.Args) != 3 {
fmt.Println("useage example: tcpClient 127.0.0.1 7005")
return
}
var ip string = os.Args[1]
var port string = os.Args[2]
connection, err := net.Dial("tcp", ip+":"+port)
if err != nil {
fmt.Println("There was an error making a connection")
}
//read from
reader := bufio.NewReader(os.Stdin)
fmt.Print("Please enter 'get <filename>' or 'send <filename>' to transfer files to the server\n\n")
inputFromUser, _ := reader.ReadString('\n')
arrayOfCommands := strings.Split(inputFromUser, " ")
if arrayOfCommands[0] == "get" {
getFileFromServer(arrayOfCommands[1], connection)
} else if arrayOfCommands[0] == "send" {
sendFileToServer(arrayOfCommands[1], connection)
} else {
fmt.Println("Bad Command")
}
}
func sendFileToServer(fileName string, connection net.Conn) {
var currentByte int64 = 0
fmt.Println("send to client")
fileBuffer := make([]byte, BUFFER_SIZE)
var err error
//file to read
file, err := os.Open(strings.TrimSpace(fileName)) // For read access.
if err != nil {
connection.Write([]byte("-1"))
log.Fatal(err)
}
connection.Write([]byte("send " + fileName))
//read file until there is an error
for err == nil || err != io.EOF {
_, err = file.ReadAt(fileBuffer, currentByte)
currentByte += BUFFER_SIZE
fmt.Println(fileBuffer)
connection.Write(fileBuffer)
}
file.Close()
connection.Close()
}
func getFileFromServer(fileName string, connection net.Conn) {
var currentByte int64 = 0
fileBuffer := make([]byte, BUFFER_SIZE)
var err error
file, err := os.Create(strings.TrimSpace(fileName))
if err != nil {
log.Fatal(err)
}
connection.Write([]byte("get " + fileName))
for {
connection.Read(fileBuffer)
cleanedFileBuffer := bytes.Trim(fileBuffer, "\x00")
_, err = file.WriteAt(cleanedFileBuffer, currentByte)
currentByte += BUFFER_SIZE
if err == io.EOF {
break
}
}
file.Close()
return
}
// END CLIENT //
// SERVER //
package main
import (
"bytes"
"fmt"
"io"
"log"
"net"
"os"
"strings"
)
const BUFFER_SIZE = 1024
const PORT = "7005"
func main() {
fmt.Println("start listening")
server, error := net.Listen("tcp", "localhost:"+PORT)
if error != nil {
fmt.Println("There was an error starting the server" + error.Error())
return
}
//infinate loop
for {
connection, error := server.Accept()
if error != nil {
fmt.Println("There was am error with the connection" + error.Error())
return
}
fmt.Println("connected")
//handle the connection, on it's own thread, per connection
go connectionHandler(connection)
}
}
func connectionHandler(connection net.Conn) {
buffer := make([]byte, BUFFER_SIZE)
_, error := connection.Read(buffer)
if error != nil {
fmt.Println("There is an error reading from connection", error.Error())
return
}
fmt.Println("command recieved: " + string(buffer))
//loop until disconntect
cleanedBuffer := bytes.Trim(buffer, "\x00")
cleanedInputCommandString := strings.TrimSpace(string(cleanedBuffer))
arrayOfCommands := strings.Split(cleanedInputCommandString, " ")
fmt.Println(arrayOfCommands[0])
if arrayOfCommands[0] == "get" {
sendFileToClient(arrayOfCommands[1], connection)
} else if arrayOfCommands[0] == "send" {
fmt.Println("getting a file")
getFileFromClient(arrayOfCommands[1], connection)
} else {
_, error = connection.Write([]byte("bad command"))
}
}
func sendFileToClient(fileName string, connection net.Conn) {
var currentByte int64 = 0
fmt.Println("send to client")
fileBuffer := make([]byte, BUFFER_SIZE)
//file to read
file, err := os.Open(strings.TrimSpace(fileName)) // For read access.
if err != nil {
log.Fatal(err)
}
var err2 error
//read file until there is an error
for {
_, err2 = file.ReadAt(fileBuffer, currentByte)
currentByte += BUFFER_SIZE
fmt.Println(fileBuffer)
connection.Write(fileBuffer)
if err2 == io.EOF {
break
}
}
file.Close()
return
}
func getFileFromClient(fileName string, connection net.Conn) {
var currentByte int64 = 0
fileBuffer := make([]byte, BUFFER_SIZE)
var err error
file, err := os.Create(strings.TrimSpace(fileName))
if err != nil {
log.Fatal(err)
}
connection.Write([]byte("get " + fileName))
for err == nil || err != io.EOF {
connection.Read(fileBuffer)
cleanedFileBuffer := bytes.Trim(fileBuffer, "\x00")
_, err = file.WriteAt(cleanedFileBuffer, currentByte)
if len(string(fileBuffer)) != len(string(cleanedFileBuffer)) {
break
}
currentByte += BUFFER_SIZE
}
connection.Close()
file.Close()
return
}
// END SERVER //
You need to account for the number of bytes returned from ReadAt
, otherwise the last fileBuffer you send will have extra garbage bytes. 您需要考虑从ReadAt
返回的字节数,否则您发送的最后一个fileBuffer将有额外的垃圾字节。
Example: 例:
n, err := file.ReadAt(fileBuffer, currentByte)
connection.Write(fileBuffer[:n])
Also bytes.Trim(fileBuffer, "\\x00")
will destroy almost any binary file since usually they use null bytes to fill space. bytes.Trim(fileBuffer, "\\x00")
也会破坏几乎所有二进制文件,因为它们通常使用空字节来填充空间。
Also the proper way of doing this is just using io.Copy
: 这样做的正确方法就是使用io.Copy
:
file, err := os.Open(strings.TrimSpace(fileName)) // For read access.
if err != nil {
log.Fatal(err)
}
defer file.Close() // make sure to close the file even if we panic.
n, err = io.Copy(connection, file)
if err != nil {
log.Fatal(err)
}
fmt.Println(n, "bytes sent")
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.