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的链接
", 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
",size)
	//i, _ := strconv.Atoi(size)

	//[]byte转换为int64
	i := BytesToInt64(buffer2[:m])
	fmt.Printf("%d, %T
",i,i)
	//int64转换为int
	j := *(*int)(unsafe.Pointer(&i))
	fmt.Printf("%d, %T
",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, 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))
}

  

原文地址:https://www.cnblogs.com/yunweiqiang/p/12735452.html