我有这样一个需求,有A,B两台服务器,A服务器会不停的往B服务器发送大量大小不固定的文件。为防止并发过高将服务器端口占完,所有采用tcp长连接。A服务器通过tcp连接B服务器,然后不停的往B服务器发送大量文件。
现在出现了这么个问题,我同时发送大量文件的时候所有的文件被写入进了1个文件当中。
代码如下:
发送端:
package main
import (
"fmt"
"io/ioutil"
"log"
"net"
)
func main() {
conn, err := net.Dial("tcp", ":9900")
if err != nil {
log.Printf("%+v\n", err)
return
}
var num = 1
for {
if num > 2 {
break
}
fname := fmt.Sprintf("./file/%d.jpg", 7)
b, err := ioutil.ReadFile(fname)
if err != nil {
log.Printf("%+v\n", err)
return
}
conn.Write(b)
num += 1
}
}
接收端:
package main
import (
"fmt"
"log"
"net"
"os"
"sync"
)
func main() {
listen, err := net.Listen("tcp", ":9900")
if err != nil {
log.Printf("%+v\n", err)
return
}
for {
conn, err := listen.Accept()
if err != nil {
log.Printf("%+v\n", err)
return
}
go handler(conn)
}
}
func handler(conn net.Conn) {
defer conn.Close()
for {
var buffer = make([]byte, 1024)
n, err := conn.Read(buffer)
if err != nil {
log.Printf("%+v\n", err)
return
}
if n > 0 {
fname := fmt.Sprintf("./tmp/%d.jpg", fname())
f, err := os.OpenFile(fname, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0777)
if err != nil {
log.Printf("%+v\n", err)
return
}
f.Write(buffer[:n])
log.Println("n:", n)
for {
var buf = make([]byte, 1024)
n, err := conn.Read(buf)
if err != nil {
log.Printf("%+v\n", err)
return
}
log.Println("n:", n)
f.Write(buf[:n])
if n != (1024) {
log.Println(fname, "写入完成")
f.Close()
break
}
}
}
}
}
var fn = 1
func fname() int {
wd := sync.Mutex{}
wd.Lock()
n := fn + 1
wd.Unlock()
return n
}
这跟语言无关,而是传输协议的特性,TCP 是传输层协议,并且是流式传输,接收端不并知道里面的数据是什么,也不知道什么时候结束,只会无差别接收,直到客户端说发完了(FIN)。所以你应该在应用层来区分数据是一个文件、多个文件或者是其它一些东西。
比如,你可以使用标准的 HTTP 协议,因为它能标识一段数据在哪里结束。
又或者,使用自己定的协议,如数据的前 8 个字节标识此段数据有多长,你就可以先读 8 个字节,发现里面说此段有 n 个字节,你就再读 n 个字节;下个循环依旧