进行连接。写入器和读取器行为异常,在一次读取操作中读取了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 

}

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.