美文网首页
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