美文网首页
grpc传递文件

grpc传递文件

作者: 哆啦在这A梦在哪 | 来源:发表于2020-04-26 13:49 被阅读0次

    1.构建protoc文件

    syntax="proto3";
    
    package stbserver;
    
    message FileMessage{
        string filename=1;
        string filetype=2;
        bytes filedata=3;
        bool iscarry=4;
    }
    
    message FileResult{
        int64 filenumber=1;
        bool iscarry=2;
    }
    
    service StbServer{
        //rpc ServerTest()returns(){}不能使用参数或者返回值为空的服务
        rpc SendFile(stream FileMessage)returns(FileResult){}
    }
    

    2.书写服务文件,功能是连接后新建一个文件,然后把本次连接内的数据流写入该文件

    package stboutserver
    
    import (
        "context"
        "log"
        "os"
        "path/filepath"
        "stbweb/lib/external_service/stbserver"
        "sync"
    )
    
    const (
        //Port 服务端口
        Port = ":5000"
    )
    
    //StbServe 外部调用结构体
    type StbServe struct{}
    
    
    //SendFile 文件传输
    func (s *StbServe) SendFile(cli stbserver.StbServer_SendFileServer) error {
    
        fDir, err := os.Executable()
        if err != nil {
            panic(err)
        }
    
        fURL := filepath.Join(filepath.Dir(fDir), "assets")
        mkdir(fURL)
    //以上是检查文件路径,以及下面是生产备用文件,其他文件请自行定义
        f, err := os.Create(filepath.Join(fURL, "test.json"))
        if err != nil {
            return err
        }
        defer f.Close()
        for {
            da, err := cli.Recv()
            if err != nil {
                log.Println("err:", err)
                break
            }
            log.Println("name:", da.Filename)
            f.Write(da.Filedata)//主要是这里,把每次接收到的字节写入
        }
        return nil
    }
    
    func mkdir(url string) {
        _, err := os.Stat(url)
        if err == nil {
            return
        }
        if os.IsNotExist(err) {
            log.Println("创建目录")
            os.MkdirAll(url, os.ModePerm)
        }
    }
    
    func main(){
        lis, err := net.Listen("tcp", Port)
        if err != nil {
            panic(err)
        }
        s := grpc.NewServer()
        stbserver.RegisterStbServerServer(s, &StbServe{})
        s.Serve(lis)
    }
    

    3.客户端文件,只要把文件以字节流的形式传输,

    第一种,传一个小文件

    import (
        "context"
        "io"
        "log"
        "os"
        "stbweb/lib/external_service/stbserver"
        "strconv"
        "time"
    
        "github.com/pborman/uuid"
    
        "google.golang.org/grpc"
    
        _ "google.golang.org/grpc/balancer/grpclb"
    )
    
    const port = "localhost:5000"
    
    func main() {
        conn, err := grpc.Dial(port, grpc.WithInsecure())
        if err != nil {
            panic(err)
        }
        defer conn.Close()
        c := stbserver.NewStbServerClient(conn) //新建client
        sendfile(c)
    }
    
    
    func sendfile(c stbserver.StbServerClient) {
        res, err := c.SendFile(context.Background())
        if err != nil {
            log.Println(err)
            return
        }
        f, err := os.Open("./test.json")
        if err != nil {
            panic(err)
        }
        sta, err := f.Stat()
        if err != nil {
            panic(err)
        }
        log.Println("size:", sta.Size())//注意传一个刚好的buf进去
        defer f.Close()
        buf := make([]byte, sta.Size())
        i := 1
        for {
            _, err := f.Read(buf)
            if err != nil && err != io.EOF {
                break
            }
            if err == io.EOF {
                log.Println(err)
                break
            }
    
            res.Send(&stbserver.FileMessage{
                Filename: strconv.Itoa(i),
                Filetype: "json",
                Filedata: buf,//传入字节,这个类型自己定义,可以根据自己业务改变
                Iscarry:  true,
            })
            i++
        }
        time.Sleep(time.Second * 2)//注意传输完成前不能关闭连接,不同业务内注意
    }
    

    2.大文件传输,其他的都一样,唯一不同的是,小文件直接将所有读取到内存中,但是大文件不可能一下都读取进来,这里就需要指定每次传送的字节流大小。需要注意的是,在指定好buf空间大小的时候,最后一次如果不把这个空间填满(比如文件大小为1000,每次读400,那第三次就是200空200),这种情况下接收方会还是接收到完整大小的buf空间,会对内容有影响,所以这里会进行一定量的计算,主要是最后一次传输的大小得和剩余大小相同。

    func sendBigFile(c stbserver.StbServerClient) {
        f, err := os.Open("./test.json")
        if err != nil {
            panic(err)
        }
        defer f.Close()
        fInfo, err := f.Stat()
        if err != nil {
            panic(err)
        }
        // log.Println(fInfo.Size())
        fSize := fInfo.Size()
        i := 1
        res, err := c.SendFile(context.Background())
        if err != nil {
            panic(err)
        }
    
        for {
            bufSize := 200//定义每次传输大小
            if int64(200*i) > fSize && int64(200*(i-1)) < fSize {//判断如果是最后一次,大小重新计算
                bufSize = int(fSize) - ((i - 1) * 200)
            }
    
            buf := make([]byte, bufSize)
            _, err := f.Read(buf)
            if err != nil && err != io.EOF {
                break
            }
            if err == io.EOF {
                log.Println(err)
                break
            }
            res.Send(&stbserver.FileMessage{
                Filename: strconv.Itoa(i),
                Filetype: "json",
                Filedata: buf,
                Iscarry:  true,
            })
            i++
        }
        time.Sleep(time.Second * 2)
        return
    }
    
    

    相关文章

      网友评论

          本文标题:grpc传递文件

          本文链接:https://www.haomeiwen.com/subject/jrrdwhtx.html