2017-02-07 13 views
-1

Я пытаюсь прочитать файл с клиента, а затем отправить его на сервер.Перейти к соединению. Писатель и читатель не работают должным образом, чтение 2 записи в одной операции чтения

Похоже, вы вводите send <fileName> в клиентскую программу, тогда <fileName> будет отправлен на сервер. Сервер читает 2 вещи от клиента по TCP-соединению, сначала команду 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 

} 

ответ

1

TCP является протоколом потока. У него нет сообщений. Сеть (в каких-то пределах нам не нужно беспокоиться) бесплатно отправлять ваши данные по одному байту за раз или все сразу. И даже если вам повезет, и сеть отправляет ваши данные в виде пакетов, подобных вам, нет ничего, что мешало бы стороне-получателю объединять пакеты в один буфер.

Другими словами: нет ничего, что заставит каждого Read вызывать возврат как можно большего количества байтов, как вы писали, с помощью некоторых вызовов Write. Иногда вам повезло, иногда, как вы заметили, вам не повезло. Если ошибок нет, все чтения, которые вы делаете из потока, возвратят все байты, которые вы написали, это единственная гарантия, которую вы имеете.

Необходимо определить правильный протокол.

Это не связано с Go. Каждый язык программирования будет вести себя таким образом.