分类 学习笔记 下的文章

go http server安全小技巧

package main

import (
    "io"
    "log"
    "net/http"
)

func main() {
    // Hello world, the web server
    helloHandler := func(w http.ResponseWriter, req *http.Request) {
        io.WriteString(w, "Hello, world!\n")
    }

    http.HandleFunc("/hello", helloHandler)
    log.Fatal(http.ListenAndServe(":80", nil))
}

这是一个简单的go http server例子

package main

import (
    "io"
    "log"
    "net/http"
)

func main() {
    // Hello world, the web server
    helloHandler := func(w http.ResponseWriter, req *http.Request) {
        io.WriteString(w, "Hello, world!\n")
    }

    //这个可以防止直接ip访问和恶意绑定域名
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        //重定向到首页
        http.Redirect(w, r, "https://www.domain.com", http.StatusMovedPermanently)
    })

    //指定域名访问
    http.HandleFunc("www.domain.com/hello", helloHandler)
    http.HandleFunc("domain.com/hello", helloHandler)
    
    log.Fatal(http.ListenAndServe(":80", nil))
}

上面加了一些代码是防止直接ip访问和防止恶意绑定其他域名

记录golang sync.pool的错用

sync.pool的官方文档一个重要的提示是 Any item stored in the Pool may be removed automatically at any time without notification. 存储在池中的任何项目都可能随时自动删除,恕不另行通知。
我原以为只要我Get出来自己释放就行了,奈何golang在GC回收闲置时池会不通知你释放掉对象,这样就造成了泄露了。

解决办法
1、自己添加析构函数,2、换库。
我选择了2换库github.com/jolestar/go-commons-pool,这个库可以设置的选项很多,还不会自动帮你释放掉对象。

微雪4.2寸WiFi电子墨水屏GO版示例

360px-4.2inch_e-Paper_Cloud_Module_wiki.jpg

这块板子自带了充电电池、WiFi蓝牙模块、充电模块。

package main

import (
    "bytes"
    "encoding/binary"
    "errors"
    "fmt"
    "net"
    "strconv"

    "github.com/Comdex/imgo"
)

var (
    g_width       = 400
    g_hight       = 300
    g_frame_len   = 1024 //每次传输数据长度不应超过1100Byte,否则将会导致数据丢失.???
    g_sector_size = 4096 //扇区大小
)

func check_res(res []byte) (cr []byte, err error) {
    if res[0] != '$' {
        return cr, errors.New("接收头错误")
    }
    i := bytes.LastIndexByte(res, '#')
    if i == -1 {
        return cr, errors.New("接收尾错误")
    }
    return res[1:i], err
}

func send_cmd(conn net.Conn, cmd []byte, hr bool) (res []byte, err error) {
    var check byte
    for _, b := range cmd {
        check ^= b
    }
    buf := new(bytes.Buffer)
    binary.Write(buf, binary.BigEndian, ';')
    binary.Write(buf, binary.BigEndian, cmd)
    binary.Write(buf, binary.BigEndian, '/')
    binary.Write(buf, binary.BigEndian, check)
    conn.Write(buf.Bytes())

    rdata := make([]byte, 64)
    rl, _ := conn.Read(rdata)
    rd, err := check_res(rdata[:rl])
    if err != nil {
        return res, err
    }
    if len(rd) != 1 || rd[0] != check {
        return res, errors.New("发送数据错误")
    }
    if hr == false {
        return
    }
    rl, _ = conn.Read(rdata)
    return check_res(rdata[:rl])
}

func send_data(conn net.Conn, data []byte) error {
    var check byte
    for _, b := range data {
        check ^= b
    }
    buf := new(bytes.Buffer)
    err := binary.Write(buf, binary.BigEndian, uint8(0x57))
    binary.Write(buf, binary.BigEndian, data)
    binary.Write(buf, binary.BigEndian, check)
    conn.Write(buf.Bytes())

    rdata := make([]byte, 64)
    rl, _ := conn.Read(rdata)
    rd, err := check_res(rdata[:rl])
    if err != nil {
        return nil
    }
    if len(rd) != 1 || rd[0] != check {
        return errors.New("发送数据错误")
    }
    return nil
}

func flush_buffer(conn net.Conn, img []byte) {
    res, err := send_cmd(conn, []byte("F"), false)
    fmt.Println("刷写数据", string(res), err)

    for i := 0; i < len(img)/g_frame_len; i++ {
        addr := i * g_frame_len
        num := addr % g_sector_size / g_frame_len //扇区的第几块? num因版本升级而失去作用,可为恒定值???
        data := new(bytes.Buffer)
        binary.Write(data, binary.BigEndian, uint32(addr))
        binary.Write(data, binary.BigEndian, uint32(g_frame_len))
        binary.Write(data, binary.BigEndian, uint8(num))
        binary.Write(data, binary.BigEndian, img[addr:addr+g_frame_len])
        send_data(conn, data.Bytes())
    }
    if len(img)%g_frame_len != 0 {
        addr := len(img) / g_frame_len * g_frame_len
        num := addr % g_sector_size / g_frame_len //扇区的第几块? num因版本升级而失去作用,可为恒定值???
        data := new(bytes.Buffer)
        binary.Write(data, binary.BigEndian, uint32(addr))
        binary.Write(data, binary.BigEndian, uint32(len(img)-addr))
        binary.Write(data, binary.BigEndian, uint8(num))
        binary.Write(data, binary.BigEndian, img[addr:])
        send_data(conn, data.Bytes())
    }
    data := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} //当addr和len均为0时,退出刷新模式。并自动刷新屏幕。???
    send_data(conn, data)

    res, err = send_cmd(conn, []byte("D"), false)
    fmt.Println("显示数据", string(res), err)
}

func img_to_400_300_bin(p string) (bw []byte, err error) {
    img43, err := imgo.ResizeForMatrix(p, g_width, g_hight) //调整大小
    if err != nil {
        return
    }
    //imgo.SaveAsJPEG("clo.jpg", img43, 100)

    imgb := imgo.Binaryzation(img43, 127) //黑白化
    //imgo.SaveAsJPEG("bin.jpg", imgb, 100)

    bw = make([]byte, g_width/8*g_hight) //生成画布 一比特一像素

    for i := 0; i < len(imgb); i++ { //高
        for j := 0; j < len(imgb[0]); j++ { //宽
            var r uint8
            if imgb[i][j][0] == 0 { //rgba
                r = 0
            } else {
                r = 1
            }
            pos := i*len(imgb[0]) + j
            bw[pos/8] |= r << (8 - (pos % 8) - 1) //按位填充数据
        }
    }
    return
}

func doServerStuff(conn net.Conn) {
    defer conn.Close()

    res, err := send_cmd(conn, []byte("G"), true)
    fmt.Println("主机名", string(res), err)

    res, err = send_cmd(conn, []byte("C"), true)
    fmt.Println("是否有锁", string(res), err)

    res, err = send_cmd(conn, []byte("N123456"), true)
    fmt.Println("解锁结果", string(res), err)

    res, err = send_cmd(conn, []byte("b"), true)
    b, _ := strconv.Atoi(string(res))
    fmt.Println("电池电压", b*3, err)

    bw, _ := img_to_400_300_bin(`C:\123.jpg`)
    flush_buffer(conn, bw)

    for {
        res, err = send_cmd(conn, []byte("b"), true)
        b, _ := strconv.Atoi(string(res))
        fmt.Println("电池电压", b*3, err)
    }
}

func main() {
    fmt.Println("开启服务")
    listener, err := net.Listen("tcp", ":6868")
    if err != nil {
        fmt.Println("监听失败", err)
        return
    }
    defer listener.Close()
    for {
        conn, err := listener.Accept()
        if err != nil {
            fmt.Println("接收新客户失败", err)
            return
        }
        fmt.Println("接收到新客户", conn.RemoteAddr())
        go doServerStuff(conn)
    }
}

自己翻译成go语言版,非常粗糙能跑通版。
官方文档地址 https://www.waveshare.net/wiki/4.2inch_e-Paper_Cloud_Module

QT上C++和OC混编的一些记录

QT的pro配置文件里加上

#开启ARC,QT上C++和OC混编默认是没有开启ARC的。
QMAKE_OBJECTIVE_CFLAGS += -fobjc-arc

OBJECTIVE_HEADERS += \
    aaa.h \
    bbb.h

OBJECTIVE_SOURCES += \
    aaa.mm \
    bbb.m

#框架
LIBS += -framework Foundation
LIBS += -framework Cocoa

C/C++和OC混编代码要写到.mm文件里,.cpp文件要引用到的.h头文件里不能包含有OC的代码或头文件,所以一般都要封装一下导出为C/C++的头文件。

网上找的一些资料
https://awhisper.github.io/2016/05/01/%E6%B7%B7%E7%BC%96ObjectiveC/
http://zsaber.com/blog/p/147
https://blog.csdn.net/horkychen/article/details/7935910

学习OC的好文章
http://www.runoob.com/w3cnote/objective-c-tutorial.html