dongtui8593 2014-09-25 04:37
浏览 108
已采纳

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

I'm new to Go and I'm having troubles debugging this client / server file transfer code. 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?

// 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

")
    inputFromUser, _ := reader.ReadString('
')
    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 //
  • 写回答

1条回答 默认 最新

  • duanbinian2243 2014-09-25 04:46
    关注

    You need to account for the number of bytes returned from ReadAt, otherwise the last fileBuffer you send will have extra garbage bytes.

    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.

    Also the proper way of doing this is just using 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")
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥50 易语言把MYSQL数据库中的数据添加至组合框
  • ¥20 求数据集和代码#有偿答复
  • ¥15 关于下拉菜单选项关联的问题
  • ¥20 java-OJ-健康体检
  • ¥15 rs485的上拉下拉,不会对a-b<-200mv有影响吗,就是接受时,对判断逻辑0有影响吗
  • ¥15 使用phpstudy在云服务器上搭建个人网站
  • ¥15 应该如何判断含间隙的曲柄摇杆机构,轴与轴承是否发生了碰撞?
  • ¥15 vue3+express部署到nginx
  • ¥20 搭建pt1000三线制高精度测温电路
  • ¥15 使用Jdk8自带的算法,和Jdk11自带的加密结果会一样吗,不一样的话有什么解决方案,Jdk不能升级的情况