Go语言网络通信---tcp上传大文件(粘包问题还需优雅解决)
server端:
package main import ( "bufio" "encoding/binary" "fmt" "net" "os" "unsafe" ) func SHandleError(err error, when string) { if err != nil{ fmt.Println("服务端异常退出,err=", err, when) os.Exit(1) } } func BytesToInt64(buf []byte) int64 { return int64(binary.BigEndian.Uint64(buf)) } func main() { //建立tcp监听 listener, e := net.Listen("tcp", ":8080") SHandleError(e, "net.Listen") defer func() { listener.Close() fmt.Println("服务端正常退出") }() //接受客户端请求,建立会话专线Conn conn, e := listener.Accept() SHandleError(e, "listener.Accept") defer func() { conn.Close() fmt.Printf("已断开与%v的链接\n", conn.RemoteAddr()) }() dstFile, e := os.OpenFile(`meinv1.mp4`, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666) writer := bufio.NewWriter(dstFile) defer dstFile.Close() buffer := make([]byte, 100) total := 0 //接受客户端发来的要传文件大小 buffer2 := make([]byte, 10) m, e := conn.Read(buffer2) //size := string(buffer2[:m]) //fmt.Printf("%s\n",size) //i, _ := strconv.Atoi(size) //[]byte转换为int64 i := BytesToInt64(buffer2[:m]) fmt.Printf("%d, %T\n",i,i) //int64转换为int j := *(*int)(unsafe.Pointer(&i)) fmt.Printf("%d, %T\n",j,j) for { //接受客户端上传的文件 n, e := conn.Read(buffer) SHandleError(e, "conn.Read") total += n //写入服务端本地文件 writer.Write(buffer[:n]) writer.Flush() fmt.Printf("成功写入%d个字节,共%d字节\n", n, total) //如果实际总接受字节数与客户端给的要传输字节数相等,说明传输完毕 if total == j{ fmt.Println("文件接受成功,共",total,"字节") //回复客户端已收到文件 conn.Write([]byte("文件接受成功")) break } } }
client端:
package main import ( "bufio" "encoding/binary" "fmt" "io" "net" "os" "time" ) /* ·实现tcp文件上传功能 */ func CHandleError2(err error, when string) { if err != nil { fmt.Println("客户端异常退出:err=", err, when) os.Exit(1) } } func Int64ToBytes(i int64) []byte { var buf = make([]byte, 8) binary.BigEndian.PutUint64(buf, uint64(i)) return buf } func main() { conn, e := net.Dial("tcp", "127.0.0.1:8080") CHandleError2(e, "net.Dial") defer func() { conn.Close() fmt.Println("客户端正常退出") }() //获取目标文件的大小,传给服务端 fileInfo, _ := os.Stat(`perfect.mp4`) size := fileInfo.Size() bytes := Int64ToBytes(size) conn.Write(bytes) //暂时通过客户端sleep 200毫秒解决粘包问题,还可以通过tcp重连解决,以后再用(包头+数据)封装数据包的方式解决 time.Sleep(time.Millisecond * 200) buffer := make([]byte, 100) srcFile, _ := os.Open(`perfect.mp4`) reader := bufio.NewReader(srcFile) total := 0 for { n, err := reader.Read(buffer) fmt.Println(n, err) if err == io.EOF{ fmt.Println("文件发送完毕") fmt.Println(total) break }else { _, e = conn.Write(buffer[:n]) total += n CHandleError2(e, "conn.Write") } } n, e := conn.Read(buffer) CHandleError2(e, "conn.Read") replyMsg := buffer[:n] fmt.Println("服务端:", string(replyMsg)) }