简体   繁体   English

Go中的TCP客户端/服务器文件传输

[英]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.

相关问题 Netty:TCP客户端服务器文件传输:异常TooLongFrameException: - Netty: TCP Client Server File transfer: Exception TooLongFrameException: 扭曲的客户端和服务器tcp传输不发送整个文件 - twisted not sending entire file with twisted client and server tcp transfer 使用sslStream的C#Tcp客户端传输文件 - c# Tcp client transfer file with sslStream 使用TCP File Transfer客户端发送时遇到问题 - Trouble with sending using TCP File Transfer Client TCPServer / TCP客户端文件传输问题:0字节 - TCPServer / TCP Client File transfer issue: 0 bytes 如何在java和TCP客户端中实现TCP服务器在cpp中传输字符串 - How to implement TCP server in java and TCP Client in cpp to transfer string 如何在java中实现TCP服务器和TCP客户端传输文件 - how to implement TCP server and TCP client in java to transfer files 使用TCP在Java(Android客户端)和C(PC服务器-Linux)之间进行文件传输 - Using TCP for File Transfer Between Java (Android client) and C (PC server - Linux) 当服务器和客户端在1台PC上运行时,TCP传输文件有效,但在2上运行时,TCP传输文件会损坏 - TCP transfer file works when server&client are running on 1 PC but corrupts when running on 2 C#TCP编程从客户端到服务器传输二进制文件的简单方法 - c# tcp programming a simple way to transfer binary file from client to server
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM