踩坑日志:使用websocket,并发的传输文件(服务器之间)

这功能不要问,问就是项目需求
直接上代码

server


import (
	"demo/model"
	"encoding/json"
	"fmt"
	"github.com/golang/protobuf/proto"
	"github.com/gorilla/websocket"
	"net"
	"net/http"
	"os"
	"strconv"
	"sync"
	"time"
)

var wsUpgrader = websocket.Upgrader{
	// 允许所有CORS跨域请求
	CheckOrigin: func(r *http.Request) bool {
		return true
	},
}

// 开启成功的端口号
var DictPoirts []int

type DictHttp struct{}

// 接收到的数据!!
var Result map[string]*sync.Map

// 开几个go程
var TotalThread int = 5

func main() {
	Result = make(map[string]*sync.Map,0)
	DictPoirts = make([]int, 0)

	count := 0
	for i := 7780;; i++ {

		handle := DictHttp{}
		websocketServer := &http.Server{
			Handler:      handle,
			ReadTimeout:  time.Duration(1000000) * time.Millisecond,
			WriteTimeout: time.Duration(1000000) * time.Millisecond,
		}
		listen, err := net.Listen("tcp", "127.0.0.1:"+strconv.Itoa(i))
		if err != nil {
			continue
		}
		count++
		if count > TotalThread {
			break
		}

		DictPoirts = append(DictPoirts, i)
		go websocketServer.Serve(listen)
	}
	fmt.Println(DictPoirts)
	for true {

	}
}

//  agent !!! - 写文件 - 接收

func (d DictHttp) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
	// 应答客户端告知升级连接为websocket
	wsSocket, err := wsUpgrader.Upgrade(resp, req, nil)
	if err != nil {
		return
	}
	fmt.Println("dict传输建立连接...")

	for true {
		_, countent, err := wsSocket.ReadMessage()
		if err != nil {
			fmt.Println("err=>", err)
			wsSocket.Close()
			break
		}
		if len(countent) == 0 {
			continue
		}
		ret := &model.DictTransfer{}
		err = proto.Unmarshal(countent, ret)
		marshal, _ := json.Marshal(ret)
		fmt.Println(string(marshal))
		if err != nil {
			fmt.Println("proto 解析错误")
			return
		}
		// 解析完成,放入 sync.map 中
		_, ok := Result[ret.Id]
		if !ok {
			Result[ret.Id] = &sync.Map{}
		}

		if ret.IsEnd == 1 {
			go intoFile(ret.Id)
		} else {
			Result[ret.Id].Store(ret.PageNum, ret.Content)
		}
	}

}

// 写入文件
func intoFile(id string) {
	file, _ := os.OpenFile("./3.txt", os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
	defer file.Close()
	fmt.Println("server 开始写文件")
	time.Sleep(time.Second * 2)
	// 文件发送完成
	for i := 1; ; i++ {
		num := int32(i)
		load, ok := Result[id].LoadAndDelete(num)
		if !ok {
			break
		}
		// 写入文件
		_, _ = file.Write(load.([]byte))
	}
}

client


import (
	"bufio"
	"demo/model"
	"encoding/json"
	"fmt"
	"github.com/golang/protobuf/proto"
	"github.com/gorilla/websocket"
	"io"
	"os"
	"strconv"
	"time"
)

// server - 读取文件 - 发送

var webSockets []*websocket.Conn

func main() {
	dialer := websocket.Dialer{
		HandshakeTimeout: 3 * time.Second,
	}
	for i := 7780; i < 7785; i++ {
		ws, _, err := dialer.Dial("ws://127.0.0.1:"+strconv.Itoa(i), nil)
		if err != nil {
			fmt.Println(i, "--client => ", err)
			return
		}
		webSockets = append(webSockets, ws)
	}

	fmt.Println("==>>开始读取文件")

	// 读文件
	open, _ := os.Open("./1.txt")
	buf := make([]byte, 20)
	reader := bufio.NewReader(open)
	for i := 1; ; i++ {
		tmp := i
		isend := 2
		n, err := reader.Read(buf)
		if err != nil && err != io.EOF || n == 0 {
			isend = 1
			end := &model.DictTransfer{
				PageNum: 0,
				Id:      open.Name(),
				IsEnd:   int32(isend),
			}
			endCon, _ := proto.Marshal(end)
			_ = webSockets[tmp%5].WriteMessage(websocket.TextMessage, endCon)
			break
		}
		ret := model.DictTransfer{
			PageNum: int32(tmp),
			Id:      open.Name(),
			Content: buf[:n],
			IsEnd:   int32(isend),
		}
		marshal, _ := proto.Marshal(&ret)
		bytes, _ := json.Marshal(ret)
		fmt.Println(string(bytes))
		// 将读取到的数据发送
		err = webSockets[tmp%5].WriteMessage(websocket.TextMessage, marshal)
		if err != nil {
			break
		}
	}

	fmt.Println("==>>文件发送完成")
}

还有就是 proto的文件
记得protoc 一下

syntax = "proto3";
package model;

message DictTransfer {

  int32 pageNum = 1; // 第几片
  string id = 2; // 字典id
  bytes content = 3; // 字典内容
  int32 isEnd =4; // 是否是最后一片 1=是最后一片
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值