编程笔记

lifelong learning & practice makes perfect

Linux 查看端口占用情况可以使用 lsof 和 netstat 命令。

lsof

lsof(list open files)是一个列出当前系统打开文件的工具。

lsof 查看端口

  • lsof -i:端口号

    查看服务器 8000 端口的占用情况:

    1
    2
    3
    # lsof -i:8000
    COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
    nodejs 26993 root 10u IPv4 37999514 0t0 TCP *:8000 (LISTEN)
  • 其他参数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    lsof -i:8080:查看8080端口占用

    lsof abc.txt:显示开启文件abc.txt的进程

    lsof -c abc:显示abc进程现在打开的文件

    lsof -c -p 1234:列出进程号为1234的进程所打开的文件

    lsof -g gid:显示归属gid的进程情况

    lsof +d /usr/local/:显示目录下被进程开启的文件

    lsof +D /usr/local/:同上,但是会搜索目录下的目录,时间较长

    lsof -d 4:显示使用fd为4的进程

    lsof -i -U:显示所有打开的端口和UNIX domain文件

netstat

netstat -tunlp 用于显示 tcp,udp 的端口和进程等相关情况。

netstat 查看端口占用语法格式

1
2
3
4
5
6
7
netstat -tunlp | grep 端口号

-t (tcp) 仅显示tcp相关选项
-u (udp)仅显示udp相关选项
-n 拒绝显示别名,能显示数字的全部转化为数字
-l 仅列出在Listen(监听)的服务状态
-p 显示建立相关链接的程序名

更多命令

1
2
3
netstat -ntlp              //查看当前所有tcp端口
netstat -ntulp | grep 80 //查看所有80端口使用情况
netstat -ntulp | grep 3306 //查看所有3306端口使用情况

go-repo code snippet

  1. 判断机器位数

    1
    const intSize = 32 << (^uint(0) >> 63)

    在64平台系统:
      1. uint(0)在平台底层是0x0000000000000000
      2. ^uint(0)在平台底层是0xFFFFFFFFFFFFFFFF
      3. ^uint(0) >> 63 在底层平台是0x0000000000000001,也就是1
      4. 32 << 1 结果是32*2 = 64

data conversion

  1. 充分利用已有的实现
1
2
3
4
5
6
7
8
9
10
11
12
type Sorter interface{
Sort()[]int
}

// 自己实现需要为Sequence实现container包内的接口,转换可以利用已有的代码

type Sequence []int
func (s Sequence)Sort()[]int{
copy:=make(Sequence,0,len(s))
append(copy,s...)
sort.IntSlice(s).Sort()
}
  1. 断言防止panic,使用安全方式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var list interface{}
    list=&Sequence{1,2,4,3}
    // 不安全方式,assertion不成功,会panic
    convert:=list.(*Sequence)

    // 安全方式
    convert,ok:=list.(*Sequence)
    if !ok{
    return errors.New("convert error")
    }
  2. 反射,通过CanSet()判断反射得到的值能否修改

    1
    2
    3
    var f float64=3
    val:=reflect.ValueOf(x)
    val.CanSet()

    反射在标准库中大量使用,fmt.Fprintf及其他格式化函数大多使用反射实现;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    //fmt.Fprintf
    func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
    p := newPrinter()
    p.doPrintf(format, a)
    n, err = w.Write(p.buf)
    p.free()
    return
    }

    // 判断interface的类型,在go 1.15 ".(type)"只能在switch使用
    var i interface{}=&os.File{}
    switch val.(type){
    case int:
    case *os.File:
    case string:
    }

参考文档

  1. golang官方文档 https://golang.google.cn/doc/effective_go#pointers_vs_values
  2. uber代码规范 (https://github.com/uber-go/guide)
  3. code snippet https://www.cnblogs.com/keystone/p/13930136.html

example

  1. top

param

统计数据

  1. load average
  2. uptime

task and cpu states 任务和cpu状态

memory usage 内存使用

process & thread state 进程/线程状态

CURD

Create

json自定义字段使用

  1. 如下为system使用自定义字段

    1
    2
    3
    type System struct{
    Version string
    }
  2. 为自定义类型实现接口Value/Scan

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    func (s System)Value()(driver.Value, error) {
    bytes, err := json.Marshal(s)
    return string(bytes), err
    }

    func (s *System) Scan(value interface{}) error {
    var bytes []byte
    switch v := value.(type) {
    case []byte:
    bytes = v
    case string:
    bytes = []byte(v)
    default:
    return fmt.Errorf("解析失败,原始数据:%v", value)
    }

    result := System{}
    if len(bytes) <= 0 {
    *s = result
    return nil
    }
    err := json.Unmarshal(bytes, &result)
    *s = result
    return err
    }
  3. json查询,例如这里要查询version=1.0的System

    1
    2
    select * from table_t
    where system->'$.version' = "1.0"

Update

Retrieve

预加载,preload

外键tag

预加载依赖在领域层结构体变量的gorm tag,需要在结构体上变量上增加外键tag,tag有多种写法,根
领域对象间的不同关系如:belongs to/has one/has many等有不同写法.

  1. belongs to 参考: https://gorm.io/zh_CN/docs/belongs_to.html
  2. has one
  3. has many
  4. many to many
    在项目ForeignKey,References这两个标签最常用,主要用于Preload相关数据
自定义预加载,可在预加载时添加条件实现排序等功能
  1. 排序

    1
    2
    3
    4
    5
    6
    7
    // 文档:https://gorm.io/zh_CN/docs/preload.html
    //您可以通过 func(db *gorm.DB) *gorm.DB 实现自定义预加载 SQL,例如:

    db.Preload("Users", func(db *gorm.DB) *gorm.DB {
    return db.Order("user.age DESC")
    }).Find(&users)
    // SELECT * FROM user WHERE id IN (1,2,3,4) order by user.age DESC;

2.

order by

  1. 常用
    指定从数据库检索记录时的排序方式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    db.Order("age desc, name").Find(&users)
    // SELECT * FROM users ORDER BY age desc, name;

    // 多个 order
    db.Order("age desc").Order("name").Find(&users)
    // SELECT * FROM users ORDER BY age desc, name;

    db.Clauses(clause.OrderBy{
    Expression: clause.Expr{SQL: "FIELD(id,?)", Vars: []interface{}{[]int{1, 2, 3}}, WithoutParentheses: true},
    }).Find(&User{})
    // SELECT * FROM users ORDER BY FIELD(id,1,2,3)
  2. order by field 自定义排序
    使用上面的写法通过自定义字段排序时注意,WithoutParentheses为true,为false是构建的sql为order by field(column,(“f1,f2,f3,…”)),会报错

  3. 组合排序

    1
    2
    3
    select id,status,create_time
    FROM `order`
    ORDER BY FIELD(status,'s3','s2','s1')desc,create_time desc

    如上的sql使用gorm框架可以这么写:

    1
    2
    3
    4
    5
    6
    7
    8
    res:=[]*Order{}
    db.Clauses(clause.OrderBy{
    Expression: clause.Expr{
    SQL: "FIELD(status,?) DESC,create_time DESC",
    Vars: []interface{}{
    []string{"s3","s2","s1"},
    },
    WithoutParentheses: true}}).Find(&res)

    不能使用链式调用(gorm v2版本,版本号:gorm.io/gorm v1.20.11),如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    db.Clauses(clause.OrderBy{
    Expression: clause.Expr{
    SQL: "FIELD(status,?) DESC",
    Vars: []interface{}{
    []string{"s3","s2","s1"},
    },
    WithoutParentheses: true}}).
    Order("create_time DESC").
    Find(&res)
  4. 参考文档

索引

  1. 强制索引

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    import "gorm.io/hints"

    db.Clauses(hints.UseIndex("idx_user_name")).Find(&User{})
    // SELECT * FROM `users` USE INDEX (`idx_user_name`)

    db.Clauses(hints.ForceIndex("idx_user_name", "idx_user_id").ForJoin ()).Find(&User{})
    // SELECT * FROM `users` FORCE INDEX FOR JOIN (`idx_user_name`, `idx_user_id`)"

    db.Clauses(
    hints.ForceIndex("idx_user_name", "idx_user_id").ForOrderBy(),
    hints.IgnoreIndex("idx_user_name").ForGroupBy(),
    ).Find(&User{})

    Index 用于提高数据检索和 SQL 查询性能。 Index Hints 向优化器提供了在查询处理过程中如何选择索引的信息。与 optimizer 相比,它可以更灵活地选择更有效的执行计划

    • 加了join
    1
    2
    3
    4
    db.Table("`order` FORCE INDEX (order_create_time_d977ab1e,idx_demand_number,   idx_stocked_number,idx_di)").
    //Clauses(hints.CommentBefore("from", "FORCE INDEX (order_create_time_d977ab1e, idx_demand_number,idx_stocked_number,idx_di)")).
    // 这样写,生成的sql语句有问题,force index位置在where条件中间
    Joins("left join servicelist on order.service_list_id=servicelist.id").Find(& orders)

Delete

Config

ConnPool

  1. gorm 连接池配置通过sql.DB实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    gormDB,err:=gorm.Open(...)
    db,err:=gormDB.DB()
    if err!=nil{
    return
    }
    db.SetConnMaxLifetime() //连接最长复用时间
    db.SetConnMaxIdleTime() //maximum amount of time a connection may be idle,最长空闲时间
    db.SetMaxIdleConns() // 最长空闲时间 maximum number of connections in the idle connection pool
    db.SetMaxOpenConns() // 最大连接数 maximum number of open connections to the database

插件

推荐插件

  1. koroFileHeader

    • 功能: 自动在文件头或函数头增加注释

    • url: https://marketplace.visualstudio.com/items?itemName=OBKoro1.korofileheader

    • 函数

      1
      2
      3
      4
      5
      /**
      * @description:
      * @param {*}
      * @return {*}
      */
    • 文件

      1
      2
      3
      4
      5
      6
      7
      8
      <!--
      * @Author: your name
      * @Date: 2021-06-25 10:10:19
      * @LastEditTime: 2021-10-29 14:24:21
      * @LastEditors: your name
      * @Description: In User Settings Edit
      * @FilePath: /vscode-config.md
      -->

code runner

  1. golang同package下的代码undefined
1
2
3
4
在.vscode下的settigns.json增加配置
"code-runner.executorMap": {
"go": "cd $dir && go run .",
},

go path

  1. vscode同时开发多个项目,每个项目不同路径
    在不同终端下,配置不同gopath,使用 eexport GOPATH=/home/xxx/xxx设置

  1. What

    • 高性能

    • 分布式

      多个分布式节点共享分布式内存,与传统部署方式不同,节点越多,memcached的可用内存越多.

    • memory object caching system

    • key-value

    • LRU (memory manage algorithm)


阅读全文 »

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 用于staff的排序
type StaffWrapper struct {
Staffs []*Staff
Compare func(a, b *Staff) bool
}

func (sw StaffWrapper) Len() int {
return len(sw.Staffs)
}

func (sw StaffWrapper) Swap(a, b int) {
sw.Staffs[a], sw.Staffs[b] = sw.Staffs[b], sw.Staffs[a]
}
func (sw StaffWrapper) Less(i, j int) bool {
return sw.Compare(sw.Staffs[i], sw.Staffs[j])
}

func SortStaff(staffs []*Staff, by SortBy) {
sort.Sort(StaffWrapper{
Staffs: staffs,
Compare: by,
})
}

SortStaff(staffs, func(a, b *Staff) bool {
return a.BelongCorpID < b.BelongCorpID
})

//参考:https://www.cnblogs.com/wangchaowei/p/7802811.html

  • what is it
  • how it looks like
    1
    2


  • how to solve
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import "github.com/astaxie/beego/plugins/cors"
// 跨域问题尝试解决
beego.InsertFilter("*", beego.BeforeRouter, cors.Allow(&cors.Options{
//允许访问所有源
AllowAllOrigins: true,
//可选参数"GET", "POST", "PUT", "DELETE", "OPTIONS" (*为所有)
//其中Options跨域复杂请求预检
AllowMethods: []string{"*"},
//指的是允许的Header的种类
AllowHeaders: []string{"*"},
//公开的HTTP标头列表
ExposeHeaders: []string{"Content-Length"},
//如果设置,则允许共享身份验证凭据,例如cookie
AllowCredentials: true,
}))



beego.Controller.Ctx.ResponseWriter.Header().Set("Access-Control-Allow-Origin",
beego.Controller.Ctx.Request.Header.Get("Origin"))
  • why

连接

  • -i指定密钥

  • -o加option

    1
    2
    -o TCPKeepAlive=yes        //长连接
    -o ServerAliveInterval=30 //

端口转发

1
2
3
4
ssh -L local_port:localhost:remote_port -N -T user@server_address -p   server_ssh_port
如:
ssh -L 9999:localhost:8888 -N -T user_test@111.111.111.111 -p 22
将发送到本地端口9999的请求数据转发到111.111.111.111转发到8888端口

配置

  1. config文件配置: ~/.ssh/config

    1
    2
    3
    4
    5
    6
    7
    8
    #配置
    Host gitee.com
    HostName gitee.com
    IdentityFile xxx/xxx/_id_rsa
    PreferredAuthentications publickey
    User xxx
    TCPKeepAlive=yes
    ServerAliveInterval 60
  2. 配置服务端

  • 件位置,全局位置: /etc/ssh/sshd_config
  • 文件位置,termux: $PREFIX/etc/ssh/sshd_config
  • 配置:
    • PasswordAuthentication (密码验证) yes/no
    • 启用密钥验证
      • RSAAuthentication (rsa秘钥) yes/no
      • PubkeyAuthentication (公钥) yes/no
  1. 认证秘钥,将公钥写入该文件(authorized_keys),就可使用该公钥登陆
    • 位置: ~/.authorized_keys

工具

  • windows terminal

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    连接远程机器使用 ssh 配置
    {
    "guid": "{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}",
    "hidden": false,
    "name": "xxxxxxx",
    //密钥放在本地,-i 指定密钥位置
    "commandline": "ssh -i xxxxxxx_id_rsa user@host -p xxxxxxxx -o TCPKeepAlive=yes -o ServerAliveInterval=30",
    "startingDirectory": "/home/xxxxxxx",
    "icon" : "ms-appx:///ProfileIcons/{9acb9455-ca41-5af7-950f-6bca1bc9722f}.png"
    }