/* 本程序为云算力平台卖方客户端,主要提供以下功能: 1,将云算力平台上的卖方身份和GPU主机绑定 2,通过本客户端,可以使云算力平台获取到卖方具体每台机器的详细参数,包括GPU型号、显存容量等 3,卖方可通过本客户端自动匹配买方的挖矿需求,即卖方无需再买方下单后手动操作挖矿 卖家在启动客户端之前需要注意以下事项: 1,确定客户端执行主机已经配置好挖矿环境,包括显卡驱动、挖矿软件(指定挖矿软件)、执行权限等,即执行本客户端的用户可以手动通过挖矿软件进行挖矿 2,如果要对本机GPU进行移除(拔出GPU)操作,云算力平台会同步移除对应的GPU 3,如果在相关GPU有租约且没有在平台申请故障处理的情况下直接移除(拔出)GPU,会导致产生罚没,因此在有租约的情况下要移除故障GPU,请第一时间前往平台申请故障处理,在平台确认后再进行移除GPU的操作 4,如果要对本机GPU进行更换(拔出后又新插入GPU)操作,云算力平台会重新读取GPU数据,如果更换型号相同,则会按原有配置上架,如果更换的型号不同,则需在更换后前往卖家中心手动调整上架配置 5,如果在相关GPU有租约且没有在平台申请故障处理的情况下直接更换GPU,可能会导致产生罚没,因此在有租约的情况下要更换故障GPU,请第一时间前往平台申请故障处理,在平台确认后再进行更换GPU的操作 */ package client import ( message "client/internal/msg" "client/internal/src" "client/internal/src/linux" "client/internal/utils" "encoding/json" "fmt" "log" "net" "runtime" "strings" ) type Client struct { Auth string MachineCode string ServerConn net.Conn // 服务连接 GPUs map[int]message.GPU // {"gpu编号": message.GPU{}, ...} os *src.SystemServer osName string } func newClient(url string) *Client { var client = &Client{} // 读取身份文件 auth, err := utils.ReadFile("./auth") if err != nil { log.Fatalf("获取客户端身份失败:%v", err) return nil } client.Auth = auth os := src.NewSystemServer() sys := runtime.GOOS if sys == "linux" { linux_ := linux.NewLinuxClient(auth) os.ResiterSystem("linux", linux_) } else { } client.os = os client.osName = sys // 读取主机MAC地址信息 var machine_code string machine_code, err = os.GetMACAddress(sys) if err != nil { log.Fatalln(err) panic("获取当前主机信息失败,程序已退出,请检查网络后重新启动本客户端。") } utils.WirteFile("./machinecode", machine_code) client.MachineCode = machine_code gpus, err := os.GetGPUInfo(sys) if err != nil { log.Fatalln(err) panic("获取当前主机GPU数据失败,程序已退出,请检查GPU驱动等程序后重新启动本客户端。") } client.GPUs = gpus server_conn, err := net.Dial("tcp", url) if err != nil { log.Fatalf("客户端连接到服务器失败:%v", err) return nil } defer server_conn.Close() client.ServerConn = server_conn return client } func (c *Client) sendMachineCode() { var msg message.ServerMsg msg.ID = c.Auth + "." + c.MachineCode msg.Method = "auth.machineCode" msg.Params = c.GPUs msgByte, err := json.Marshal(msg) if err != nil { log.Fatalf("消息(%v)序列化失败:%v", msg, err) return } c.send(msgByte) } func (c *Client) receiveMsg() { buffer := make([]byte, 1024) for { n, err := c.ServerConn.Read(buffer) if err != nil { if err.Error() == "EOF" { // 服务端关闭连接时,退出接收循环 log.Println("服务端关闭了连接") return } log.Println("接收数据失败:", err) return } msgByte := buffer[:n] go c.handleReceiveMsg(msgByte) } } func (c *Client) send(msg []byte) { _, err := c.ServerConn.Write(msg) if err != nil { log.Fatalf("发送消息失败,消息内容:%s", string(msg)) return } } func (c *Client) handleReceiveMsg(msg []byte) { var data message.ServerMsg err := json.Unmarshal(msg, &data) if err != nil { log.Fatalf("解析接收到的消息失败:%v", err) return } parts := strings.Split(data.ID, ".") if len(parts) != 2 { log.Fatalf("解析通信协议(server->client)失败") return } auth, machine_code := parts[0], parts[1] if c.Auth != auth || c.MachineCode != machine_code { log.Fatalf("客户端接收到错误的服务端消息") return } switch data.Method { case "mining.req": mining_msg, ok := data.Params.(message.ConfigurationMiningMsg) if ok { // 这里开始挖矿 err := c.os.Mining(c.osName, mining_msg) if err != nil { sendMsg_str := message.ServerMsgResp{ ID: c.Auth + "." + c.MachineCode, Result: false, Data: err, } sendMsg_byte, err := json.Marshal(sendMsg_str) if err != nil { log.Fatalf("序列化%v失败:%v", sendMsg_str, err) break } c.send(sendMsg_byte) // 返回失败消息 } // 挖矿开始 data := message.ConfigurationMiningResp{ Coin: mining_msg.Coin, Algo: mining_msg.Algo, Pool: mining_msg.Pool, PoolUrl: mining_msg.PoolUrl, WorkerID: mining_msg.WorkerID, WalletAddress: mining_msg.WalletAddress, WatchUrl: "", // 这里需要根据矿池自动生成 } sendMsg_str := message.ServerMsgResp{ ID: c.Auth + "." + c.MachineCode, Result: true, Data: data, } sendMsg_byte, err := json.Marshal(sendMsg_str) if err != nil { log.Fatalf("序列化%v失败:%v", sendMsg_str, err) break } c.send(sendMsg_byte) // 返回成功消息 } else { sendMsg_str := message.ServerMsgResp{ ID: c.Auth + "." + c.MachineCode, Result: false, Data: fmt.Errorf("错误的params数据结构:%v", mining_msg), } sendMsg_byte, err := json.Marshal(sendMsg_str) if err != nil { log.Fatalf("序列化%v失败:%v", sendMsg_str, err) break } c.send(sendMsg_byte) // 返回失败消息 } } } func Star() { url := "xxxx" client := newClient(url) client.sendMachineCode() go client.receiveMsg() // 开始接收服务端消息 }