All skills
gogf avatar

/goframe-v2

@911705d
by GoFramegogf/skills81 stars
3

GoFrame v2 development skill. Use only when the target Go project uses or is explicitly adopting GoFrame v2: the nearest go.mod requires github.com/gogf/gf/v2, existing Go files import github.com/gogf/gf/v2 or any github.com/gogf/gf/v2/... component package, or the user asks to scaffold, migrate, or build with GoFrame. Trigger for GoFrame-backed Go work such as APIs/controllers/services, middleware, routing/config, ORM/DAO/DO/entity/database operations, gf CLI/codegen, HTTP/gRPC services, and microservice conventions. Do not trigger for generic Go projects without GoFrame evidence, frontend-only work, shell scripts, or unrelated infrastructure tasks.

Use this Skill: https://skilld.dev/gh/gogf/skills/goframe-v2

This session only. Nothing lands on disk.

references组件列表网络组件TCP组件TCP组件-连接对象连接对象-消息包处理.md

gtcp 提供了许多方便的原生操作连接数据的方法,但是在绝大多数的应用场景中,开发者需要自己设计数据结构,并进行封包/解包处理,由于 TCP 消息协议是没有消息边界保护的,因此复杂的网络通信环境中很容易出现 粘包 的情况。因此 gtcp 也提供了简单的数据协议,方便开发者进行消息包交互,开发者不再需要担心消息包的处理细节,包括封包/解包处理,这一切复杂的逻辑 gtcp 已经帮你处理好了。

简单协议

gtcp 模块提供了简单轻量级数据交互协议,效率非常高,协议格式如下:

数据长度(16bit)|数据字段(变长)
  1. 数据长度:默认为 16位( 2字节),用于标识该消息体的数据长度,单位为字节,不包含自身的2字节;
  2. 数据字段:变长,根据数据长度可以知道,数据最大长度不能超过 0xFFFF = 65535 bytes = 64 KB;

简单协议由 gtcp 封装实现,如果开发者客户端和服务端如果都使用 gtcp 模块来通信则无需关心协议实现,专注 数据 字段封装/解析实现即可。如果涉及和其他开发语言对接,则需要按照该协议实现对接即可,由于简单协议非常简单轻量级,因此对接成本很低。 :::tip 数据字段也可以为空,即没有任何长度。 :::

操作方法

https://pkg.go.dev/github.com/gogf/gf/v2/net/gtcp

type Conn
    func (c *Conn) SendPkg(data []byte, option ...PkgOption) error
    func (c *Conn) SendPkgWithTimeout(data []byte, timeout time.Duration, option ...PkgOption) error
    func (c *Conn) SendRecvPkg(data []byte, option ...PkgOption) ([]byte, error)
    func (c *Conn) SendRecvPkgWithTimeout(data []byte, timeout time.Duration, option ...PkgOption) ([]byte, error)
    func (c *Conn) RecvPkg(option ...PkgOption) (result []byte, err error)
    func (c *Conn) RecvPkgWithTimeout(timeout time.Duration, option ...PkgOption) ([]byte, error)

可以看到,消息包方法命名是在原有的基本连接操作方法中加上了 Pkg 关键词便于区分。

其中,请求参数中的 PkgOption 数据结构如下,用于定义消息包接收策略:

// 数据读取选项
type PkgOption struct {
    HeaderSize  int   // 自定义头大小(默认为2字节,最大不能超过4字节)
    MaxDataSize int   // (byte)数据读取的最大包大小,默认最大不能超过2字节(65535 byte)
    Retry       Retry // 失败重试策略
}

使用示例

示例1,基本使用

package main

import (
    "fmt"
    "github.com/gogf/gf/v2/net/gtcp"
    "github.com/gogf/gf/v2/os/glog"
    "github.com/gogf/gf/v2/util/gconv"
    "time"
)

func main() {
    // Server
    go gtcp.NewServer("127.0.0.1:8999", func(conn *gtcp.Conn) {
        defer conn.Close()
        for {
            data, err := conn.RecvPkg()
            if err != nil {
                fmt.Println(err)
                break
            }
            fmt.Println("receive:", data)
        }
    }).Run()

    time.Sleep(time.Second)

    // Client
    conn, err := gtcp.NewConn("127.0.0.1:8999")
    if err != nil {
        panic(err)
    }
    defer conn.Close()
    for i := 0; i < 10000; i++ {
        if err := conn.SendPkg([]byte(gconv.String(i))); err != nil {
            glog.Error(err)
        }
        time.Sleep(1*time.Second)
    }
}

这个示例比较简单,执行后,输出结果为:

receive: [48]
receive: [49]
receive: [50]
receive: [51]
...

示例2,自定义数据结构

大多数场景下,我们需要对发送的消息能自定义数据结构,开发者可以利用 数据 字段传递任意的消息内容实现。

以下是一个简单的自定义数据结构的示例,用于客户端上报当前主机节点的内存及CPU使用情况。在该示例中, 数据 字段使用了 JSON 数据格式进行自定义,便于数据的编码/解码。 :::tip 实际场景中,开发者往往需要自定义包解析协议,或者采用较通用的 protobuf 二进制包封装/解析协议。 :::

  1. types/types.go

数据结构定义。

package types

import "github.com/gogf/gf/v2/frame/g"

type NodeInfo struct {
       Cpu       float32 // CPU百分比(%)
       Host      string  // 主机名称
       Ip        g.Map   // IP地址信息(可能多个)
       MemUsed   int     // 内存使用(byte)
       MemTotal  int     // 内存总量(byte)
       Time      int     // 上报时间(时间戳)
}
  1. gtcp_monitor_server.go

服务端。

package main

import (
       "encoding/json"
       "github.com/gogf/gf/v2/net/gtcp"
       "github.com/gogf/gf/v2/os/glog"
       "github.com/gogf/gf/.example/net/gtcp/pkg_operations/monitor/types"
)

func main() {
       // 服务端,接收客户端数据并格式化为指定数据结构,打印
       gtcp.NewServer("127.0.0.1:8999", func(conn *gtcp.Conn) {
           defer conn.Close()
           for {
               data, err := conn.RecvPkg()
               if err != nil {
                   if err.Error() == "EOF" {
                       glog.Println("client closed")
                   }
                   break
               }
               info := &types.NodeInfo{}
               if err := json.Unmarshal(data, info); err != nil {
                   glog.Errorf("invalid package structure: %s", err.Error())
               } else {
                   glog.Println(info)
                   conn.SendPkg([]byte("ok"))
               }
           }
       }).Run()
}
  1. gtcp_monitor_client.go

客户端。

package main

import (
       "encoding/json"
       "github.com/gogf/gf/v2/frame/g"
       "github.com/gogf/gf/v2/net/gtcp"
       "github.com/gogf/gf/v2/os/glog"
       "github.com/gogf/gf/v2/os/gtime"
       "github.com/gogf/gf/.example/net/gtcp/pkg_operations/monitor/types"
)

func main() {
       // 数据上报客户端
       conn, err := gtcp.NewConn("127.0.0.1:8999")
       if err != nil {
           panic(err)
       }
       defer conn.Close()
       // 使用JSON格式化数据字段
       info, err := json.Marshal(types.NodeInfo{
           Cpu       : float32(66.66),
           Host      : "localhost",
           Ip        : g.Map {
               "etho" : "192.168.1.100",
               "eth1" : "114.114.10.11",
           },
           MemUsed   : 15560320,
           MemTotal  : 16333788,
           Time      : int(gtime.Timestamp()),
       })
       if err != nil {
           panic(err)
       }
       // 使用 SendRecvPkg 发送消息包并接受返回
       if result, err := conn.SendRecvPkg(info); err != nil {
           if err.Error() == "EOF" {
               glog.Println("server closed")
           }
       } else {
           glog.Println(string(result))
       }
}
  1. 执行后

    • 客户端输出结果为:

        2019-05-03 13:33:25.710 ok
    • 服务端输出结果为:

        2019-05-03 13:33:25.710 &{66.66 localhost map[eth1:114.114.10.11 etho:192.168.1.100] 15560320 16333788 1556861605}
        2019-05-03 13:33:25.710 client closed

Source: SKILL.md on GitHub

1 alert16d5 checks · Risk MEDIUM
  • Gen Agent Trust Hub16d

    The skill provides a comprehensive development guide and code examples for the GoFrame v2 framework. While highly informative for Go developers, it contains several examples with hardcoded placeholder secrets, tokens, and specific local file paths to sensitive configuration files (like Kubernetes credentials). These elements are provided for demonstration purposes but represent insecure practices if used in production without modification.

  • Socket16d

    5 alerts: gptSecurity, gptAnomaly

  • Snyk16d

    Risk: LOW · No issues

  • Runlayer6mo

    227/949 files flagged

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at 911705d. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 4 months ago.

Steadyupdated 4 months ago
  • Go
  • Database
  • goframe
  • orm
  • http
  • grpc
  • microservices
  • crud
  • scaffolding
  • middleware

README badge

README badge for gogf/skills

Provides instruction and conventions for developing with GoFrame v2, a modular Go framework for building HTTP and gRPC services, microservices, and database operations using its ORM, CLI tooling, and project scaffolding. Use this skill when the target project has GoFrame v2 as a dependency or when the user requests scaffolding, migrations, or service development with GoFrame conventions.

Generated from the current SKILL.md.

When should I use this skill?
Use this skill only when your Go project uses GoFrame v2, indicated by github.com/gogf/gf/v2 in go.mod or imports. Do not use for generic Go projects, frontend work, or infrastructure tasks unrelated to GoFrame.
Should I manually set created_at and updated_at fields?
No. GoFrame automatically writes created_at on insert and updated_at on insert/update/save. Manually setting these fields is redundant and violates project conventions.
What should I use for database operations instead of g.Map?
Always use DO objects from internal/model/do/. DO struct fields are interface{}, unset fields remain nil and are automatically ignored by the ORM.
How does soft delete work in GoFrame?
Call Delete() on the DAO; GoFrame automatically converts it to UPDATE SET deleted_at = NOW(). Queries automatically filter out soft-deleted rows without requiring manual WhereNull conditions.
Where should I implement business logic?
Implement business logic directly in the service/ directory. Do not use the logic/ directory unless explicitly requested.

Generated from the current SKILL.md. These answers refresh after source changes.