Golang TCP文件传输陷入困境

时间:2017-02-15 20:27:01

标签: go

我在TCP的{​​{1}}上遇到了一些文件传输问题。文件传输有时会起作用,有时会卡在中间。当它卡住时,它看起来好像在期望通信通道中的数据但是没有数据也没有错误。因此它无限期地被卡住了。为了让事情变得混乱,它显示了同一文件的这种行为,即对于同一文件,它有时会起作用,有时它不起作用。

这是我的程序的工作方式。它会监听传入的请求。请求采用go格式。根据请求类型,它将执行不同的操作。我发布了与文件传输相关的代码段。

server.go

JSON

test.go

package main

import (
    "bufio"
    "encoding/json"
    "fmt"
    _"io"
    "net"
    "os"
)

const (
    COMMAND_RECEIVE_FILE    = "TRANSFER_FILE"
    COMMAND_EXIT            = "EXIT"

    CONNECTION_TYPE = "tcp"
    CONNECTION_PORT = "3645"
    CONNECTION_HOST = ""
    BUFFER_SIZE     = 1024
)

type Command struct {
    Identifier string `json:"identifier"`
    Name       string `json:"name"`
    Size       int64  `json:"size"`
}

type Result struct {
    Message     string        `json:"message"`
}

func receiveFile(connection net.Conn, fileName string, fileSize int64) Result {
    fmt.Println("Receiving file")
    result := Result{Message: ""}

    file, err := os.Create(fileName)
    if err != nil {
        fmt.Println(err)
        result.Message = "Error opening file: " + fileName
        return result
    }

    defer file.Close()

    fileBuffer := make([]byte, BUFFER_SIZE)
    bytesRead := int64(0)
    count := 0
    for {
        if fileSize-bytesRead < int64(BUFFER_SIZE) {
            fileBuffer = make([]byte, fileSize-bytesRead)
        }

        fmt.Println("Reading ", BUFFER_SIZE, " bytes of data")
        n, err := connection.Read(fileBuffer)
        count++
        fmt.Println("Completed reading", n, " bytes of data, count=", count)
        file.Write(fileBuffer[0:n])
        bytesRead += int64(n)

        if err != nil {
            result.Message = "File transfer incomplete"
            break
        }

        if bytesRead >= fileSize {
            result.Message = "File transfer complete"
            break
        }
    }

    file.Chmod(0777)

    return result
}

func main() {
    ln, err := net.Listen(CONNECTION_TYPE, CONNECTION_HOST + ":"+CONNECTION_PORT)
    if err != nil {
        fmt.Println("error opening a tcp connection")
    }

    for {
        fmt.Println("waiting for new connection")
        conn, err := ln.Accept()
        if err != nil {

        } else {
            var commandStr string
            reader := bufio.NewReader(conn)

            var exitStatus = 1
            for exitStatus == 1 {
                fmt.Println("Waiting for new command: ")
                line,_,err := reader.ReadLine()
                if err != nil {
                    conn.Close()
                    exitStatus = 0
                    break
                } else {
                    fmt.Println("Size read :", len(line))
                }
                commandStr = string(line)
                fmt.Println("CommandStr: ", commandStr)


                var msg Command
                err = json.Unmarshal([]byte(commandStr), &msg)
                if err != nil {
                    fmt.Println("Error")
                    conn.Close()
                    break
                }

                result := Result{}
                fmt.Println("Received new command: ", msg.Identifier)
                switch msg.Identifier {

                case COMMAND_RECEIVE_FILE:
                    result = receiveFile(conn, msg.Name, msg.Size)

                case COMMAND_EXIT:
                    exitStatus = 0
                    conn.Close()
                default:
                    result = Result{Message: "Unrecognized command"}
                }

                out, _ := json.Marshal(result)
                fmt.Fprint(conn, string(out)+"\n")
            }
        }
    }
}

我在Linux和Windows上测试过,它在两个系统上都表现出相同的行为。我唯一能想到的是发送器比接收器更快,即使我在同一台机器上运行它。如果是这种情况,除了握手机制之外,解决它的最佳做法是什么。

1 个答案:

答案 0 :(得分:2)

您无法将net.Conn包裹在bufio.Reader中,然后继续使用net.Conn。您的功能被阻止的原因是您将数据保留在reader中,因此您将无法达到所需的邮件大小。

您需要将reader传递给receiveFile函数,以免丢失缓冲数据。

您也忽略了isPrefix的{​​{1}}返回值。如果您不打算处理该方法的所有情况,我会按照文档使用ReadLine