zoukankan      html  css  js  c++  java
  • 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))
    }
    

      

  • 相关阅读:
    (五)Hibernate 操作对象
    (四)关联关系一对多映射
    (三)映射对象标识符(OID)
    随机取数据
    Delphi的时间处理
    调用MYSQL存储过程实例
    php接收数据
    NodeJS入门
    idHTTP访问百度
    delphi 从TWebBrowser WebBrowser得到全部html源码
  • 原文地址:https://www.cnblogs.com/yunweiqiang/p/12735452.html
Copyright © 2011-2022 走看看