duanbinian2243 2017-02-07 10:01
浏览 95
已采纳

进行连接。写入器和读取器行为异常,在一次读取操作中读取了2次写入

I am trying to read a file from client and then send it to server.

It goes like this, you input send <fileName> in the client program, then <fileName> will be sent to server. The server read 2 things from the client via TCP connection, first the command send <fileName> and second the content of the file.

However, sometimes my program will randomly include the file content in the <fileName> string. For example, say I have a text file called xyz.txt, the content of which is "Hellow world". The server sometimes receive send xyz.txtHellow world. Sometimes it doesn't and it works just fine.

I think that it is the problem of synchronization or not flushing reader/writer buffer. But I am not quite sure. Thanks in advance!

Client code:

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.")
}

Server code: (connectionHandler is a goroutine that is invoked for every TCP connection request from client)

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],"
","",-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 

}
  • 写回答

1条回答 默认 最新

  • dsf4354353452 2017-02-07 10:10
    关注

    TCP is a stream protocol. It doesn't have messages. The network is (within some limits we don't need to concern us about) free to send your data one byte at a time or everything at once. And even if you get lucky and the network sends your data in packets like you want them there's nothing that prevents the receive side from concatenating the packets into one buffer.

    In other words: there is nothing that will make each Read call return as many bytes as you wrote with some specific Write calls. You sometimes get lucky, sometimes, as you noticed, you don't get lucky. If there are no errors, all the reads you do from the stream will return all the bytes you wrote, that's the only guarantee you have.

    You need to define a proper protocol.

    This is not related to Go. Every programming language will behave this way.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 求学软件的前人们指明方向🥺
  • ¥50 如何增强飞上天的树莓派的热点信号强度,以使得笔记本可以在地面实现远程桌面连接
  • ¥15 MCNP里如何定义多个源?
  • ¥20 双层网络上信息-疾病传播
  • ¥50 paddlepaddle pinn
  • ¥20 idea运行测试代码报错问题
  • ¥15 网络监控:网络故障告警通知
  • ¥15 django项目运行报编码错误
  • ¥15 STM32驱动继电器
  • ¥15 Windows server update services