file - Go connection.Writer 和 reader 行为不正常,在一次读取操作中读取 2 写入

标签 file go tcp io server

我正在尝试从客户端读取文件,然后将其发送到服务器。

它是这样的,你输入send <fileName>在客户端程序中,然后是<fileName>将被发送到服务器。服务器通过 TCP 连接从客户端读取 2 个东西,首先是命令 send <fileName>其次是文件的内容。

但是,有时我的程序会随机包含<fileName>中的文件内容。字符串。例如,假设我有一个名为 xyz.txt 的文本文件,其内容是“Hellow world”。服务器有时会收到 send xyz.txtHellow world .有时它不会,但它工作得很好。

我认为这是同步或不刷新读写器缓冲区的问题。但我不太确定。 提前致谢!

客户端代码:

func sendFileToServer(fileName string, connection net.Conn) {

    fileBuffer := make([]byte, BUFFER_SIZE)
    var err error

    file, err := os.Open(fileName) // For read access.

    lock := make(chan int)
    w := bufio.NewWriter(connection)

    go func(){
        w.Write([]byte("send " + fileName))
        w.Flush()
        lock <- 1
    }()

    <-lock
    // make a read buffer
    r := bufio.NewReader(file)

    //read file until there is an error
    for err == nil || err != io.EOF {
        //read a chunk
        n, err := r.Read(fileBuffer)
        if err != nil && err != io.EOF {
            panic(err)
        }
        if n == 0 {
            break
        }
        // write a chunk
        if _, err := w.Write(fileBuffer[:n]); err != nil {
            panic(err)
        }
    }
    file.Close()
    connection.Close()
    fmt.Println("Finished sending.")
}

服务器代码:(connectionHandler 是一个 goroutine,为来自客户端的每个 TCP 连接请求调用)

func connectionHandler(connection net.Conn, bufferChan chan []byte, stringChan chan string) {
    buffer := make([]byte, 1024)

    _, error := connection.Read(buffer)
    if error != nil {
        fmt.Println("There is an error reading from connection", error.Error())
        stringChan<-"failed"
        return 
    }
    fmt.Println("command recieved: " + string(buffer))
    if("-1"==strings.Trim(string(buffer), "\x00")){
        stringChan<-"failed"
        return
    }

    arrayOfCommands := strings.Split(string(buffer)," ")
    arrayOfCommands[1] = strings.Replace(arrayOfCommands[1],"\n","",-1)
    fileName := strings.Trim(arrayOfCommands[1], "\x00")    

    if arrayOfCommands[0] == "get" {
        fmt.Println("Sending a file " + arrayOfCommands[1])
        sendFileToClient(fileName, connection, bufferChan, stringChan)
    } else if arrayOfCommands[0] == "send" {
        fmt.Println("Getting a file " + arrayOfCommands[1])
        getFileFromClient(fileName, connection, bufferChan, stringChan)
    } else {
        _, error = connection.Write([]byte("bad command"))
    }
    fmt.Println("connectionHandler finished")
}


func getFileFromClient(fileName string, connection net.Conn,bufferChan chan []byte, stringChan chan string) { //put the file in memory
    stringChan<-"send"
    fileBuffer := make([]byte, BUFFER_SIZE)

    var err error
    r := bufio.NewReader(connection)

    for err == nil || err != io.EOF {
        //read a chunk
        n, err := r.Read(fileBuffer)
        if err != nil && err != io.EOF {
            panic(err)
        }
        if n == 0 {
            break
        }
        bufferChan<-fileBuffer[:n]
        stringChan<-fileName
    }

    connection.Close()
    return 

}

最佳答案

TCP 是一种流协议(protocol)。它没有消息。网络(在我们不需要担心的某些限制内)可以一次一个字节地免费发送您的数据或一次发送所有内容。即使您走运并且网络按照您希望的那样以数据包的形式发送数据,也没有什么可以阻止接收方将数据包连接到一个缓冲区中。

换句话说:没有任何东西可以使每个 Read 调用返回的字节数与您使用某些特定的 Write 调用写入的字节数一样多。你有时会很幸运,有时,正如你所注意到的,你并不幸运。如果没有错误,您从流中执行的所有读取操作都将返回您写入的所有字节,这是您拥有的唯一保证。

你需要定义一个合适的协议(protocol)。

这与 Go 无关。每种编程语言都会以这种方式运行。

关于file - Go connection.Writer 和 reader 行为不正常,在一次读取操作中读取 2 写入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42086859/

相关文章:

linux - 通过 TCP 快速发送/接收数据会导致阻塞

java - 如何在java servlet中读取文件

c++ - 'ifstream' 的初始化没有匹配的构造函数

go - 添加 3 种方法或通用方法

java - 构建套接字通信以最小化数据传输

networking - 如何控制peer上的socket[TCP Hole Punching]

javascript - 启用从服务器 Angular 下载文件

python - Flask 中的动态文件解析

go - 通用 slice 参数和限制为 slice 类型的参数有什么区别?

golang - 将 [ ] 接口(interface)转换为 [ ] 字符串或连接字符串