我正在尝试从客户端读取文件,然后将其发送到服务器。
它是这样的,你输入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/