2017-02-07 12 views
-1

クライアントからファイルを読み取り、サーバーに送信しようとしています。接続します.Writerとリーダーが正常に動作しません。1回の読み取り操作で2回の読み取りを行います。

クライアントプログラムにsend <fileName>と入力すると、<fileName>がサーバーに送信されます。サーバは、TCP接続を介してクライアントから2つのものを読み込み、最初にコマンドsend <fileName>と2番目にファイルの内容を読み込みます。

ただし、私のプログラムでは、ファイルの内容が無作為に<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.") 
} 

Serverコード:(connectionHandlerは、クライアントからのすべての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はストリームプロトコルです。メッセージはありません。ネットワークは、(一度にいくつかの制限内で、私たちに懸念する必要はありません)、一度に1バイトまたは一気にデータを送信することができます。そして、たとえあなたが運が良ければネットワークがあなたの望むようにあなたのデータをパケットで送信しても、受信側がパケットを一つのバッファに連結するのを妨げるものはありません。

言い換えれば、Readの呼び出しが、いくつかの特定のWrite呼び出しで書いた数の呼び出しを返すようにするものはありません。あなたはたまに幸運になることがあります。時には気づいたように、あなたは幸運を得ません。エラーがなければ、ストリームからのすべての読み込みは、書き込んだすべてのバイトを返します。これが唯一の保証です。

適切なプロトコルを定義する必要があります。

これはGoとは関係ありません。すべてのプログラミング言語がこのように動作します。

関連する問題