Go语言的p2p传输例子推荐
https://github.com/hikaricai/p2p_tun
这是一个简单的p2p打洞传输例子,非常适合入门了解,底层用到了kcp-go来提供可靠UDP传输,需要用到一台有公网ip的服务器来交换信息。
配合这篇文章食用更佳 https://arthurchiao.art/blog/how-nat-traversal-works-zh/
生命满希望 前路由我创
https://github.com/hikaricai/p2p_tun
这是一个简单的p2p打洞传输例子,非常适合入门了解,底层用到了kcp-go来提供可靠UDP传输,需要用到一台有公网ip的服务器来交换信息。
配合这篇文章食用更佳 https://arthurchiao.art/blog/how-nat-traversal-works-zh/
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,这个库可以设置的选项很多,还不会自动帮你释放掉对象。
刚换的新车,现在用的是临牌,进出停车场不便,这里记录下等待铁牌到手的过程。
07-12 星期一早上到竹子林验车,流程很简单,基本就是等。我现场选的号,推荐网上选可以排除4,现场的话50个有47个含4的号。一个多小时后就可以拿到绿本、驾驶证啥的了,铁牌选择邮寄。
07-13 星期二下午能在交管12123APP上面看到自己的车辆了(自动绑定的?),在邮证APP查的到车牌制作信息(车牌正在报制中)。
07-14 查邮证APP车牌正在报制中。
07-15 查邮证APP车牌正在报制中,但到了中午就有邮政快递说已经到了要去付到付的钱,这说明邮证APP可能不准。
至此验车到拿到铁牌用了4天时间。
这块板子自带了充电电池、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
一点也不生疏,面包虫原来是这样子的。