go conn.Read() 的阻塞问题

golang 主张使用协程代替回调处理web请求,我们可能会写出这样的代码: ``` golang package main import ( "bufio" "fmt" "net" "time" ) func main() { go func() { time.Sleep(time.Second) conn, err := net.Dial("tcp", "127.0.0.1:8080") if err != nil { return } defer conn.Close() n, e := conn.Write([]byte("xxxx;")) fmt.Println("client write ", "xxxx;", n, e) r := bufio.NewReader(conn) msg, e := r.ReadString('\n') fmt.Println("client read ", msg, e) }() go func() { l, e := net.Listen("tcp", ":8080") if e != nil { return } defer l.Close() for { c, e := l.Accept() fmt.Println("accept", e) if e != nil { continue } defer c.Close() r := bufio.NewReader(c) msg, e := r.ReadString('\n') fmt.Println("server rece ", msg) c.Write([]byte("succeed")) fmt.Println("server send ", "succeed") } }() select {} } conn.Read([]byte) ```` 有什么问题呢,事实上这段代码产生了死锁,由于客户端msg不以'\n'结尾,导致r.ReadString('\n')将会阻塞! 换言之, bufio.NewReader 破坏了tcp传输的全双工特性,如果客户端不断开连接,r.ReadString('\n')不会返回 io.EOF ,倘若客户端需要接收消息的话,conn将无法释放! 使用 conn.Read([]byte) 会在msg无数据时阻塞!! 面对数据如何处理: 协议msg格式,规定必须以'\n'结尾,那么可以据此伪造大量异常连接耗尽服务端资源 如果限定长度同样不能保证,超时关闭连接是一种办法,但是tcp本身已经是阻塞读取的情况下,直接读取全部可用值就好啦嘛

link

html 移动端调试

h5 移动页面的维护实在是个问题,虽说pc端有所谓模拟调试,但和真实设备之前还是存在差异,比如: <img style="width:100%" src="https://impuss-1254389633.cos.ap-shanghai.myqcloud.com/h5/QQ%E5%9B%BE%E7%89%8720190901172316.jpg"> <img style="width:100%" src="https://impuss-1254389633.cos.ap-shanghai.myqcloud.com/h5/QQ%E5%9B%BE%E7%89%8720190901172355.jpg"> 模拟设备显示对象height为78px,可实际移动端根本没渲染出来 chrome 支持对移动设备的远程调试,打开usb 远程,在 <a herf="chrome://inspect/#devices">chrome://inspect/#devices</a> 里就可以对手机进行操作,非常nice

link

windows下使用gdb进行调试

MinGW目前最新的GDB版本为8.1,用它来调试go程序是有问题的。 比如说,对于下面几行代码,使用gdb调试时,run,breakpoint都是没问题的,但是你要list一下 gdb就要报错退出了 ``` package main import ( "fmt" "time" ) func main() { for i := 0; i < 10; i++ { fmt.Println(time.Now()) } } ``` 报错如下: gdb-8.1/gdb/buildsym.c:1764: internal-error: void buildsym_init(): Assertion `free_pendings == NULL' failed. A problem internal to GDB has been detected, further debugging may prove unreliable. 经过多方查阅,发现这是gdb8.1多年的bug,讨论地址如下: [GDB on windows with golang](https://sourceware.org/bugzilla/show_bug.cgi?id=18624#c17) 15年的问题,18年才解决,win果真没人关注。。。 那就只能自己编译gdb了,最新版本8.3,文件可自行下载 win下编译可以使用msys2,时间稍微有点长,不过需要同时加载msys-2.0.dll, 我这里设置的 target=x86_64-w64-mingw32 不想编译的同学可以直接下载 下载地址: [gdb.exe](https://fullstack.love/static/file/gdb.exe) [msys-2.0.dll](https://fullstack.love/static/file/msys-2.0.dll) 当然也有折中(偷懒)的方法,cgo编译后符号表是可以正常调试的,所以你只需开头加入: ``` import "C" ``` 或者干脆,使用dlv调试嘛!

link

关于函数式编程

函数式编程与面向对象地位类似。不得不说,函数式作为一种思想是有其价值的,然而其本质是什么? haskell 中的各种特性,惰性求值也好,类型系统也好,能够成为其函数式的理由么?java中添加了 λ 就脱离了面向对象?显然不是。 函数作为一等公民在很多场合下是适用的,然后又有了纯函数式的说法,不修改变量就能算作函数式编程了么?代价则是描述能力的下降,譬如计时过程。而一些其他的概念,又可以在其他地方看到影子。 其实还是有些收获的,haskell类型的无穷递归emm,有点类似null?然鹅并没有看到最后。 函数式的精髓应当在于其对解决问题的证明,然而这一方面关乎测试,另一方面要求代码的可读性高。而目前来看,过程式的命令似乎更符合人们的认知规律。

link

gopls——及时的代码补全

升级Go1.12之后虽然可以使用go mod在GOPATH之外构建工程,同时却带来了诸多开发工具兼容性问题 这里无意介绍有关包管理的使用,对我而言,最头疼的是VSCode自动补全基本残废,自动提示已经追 不上我的输入了( ﹁ ﹁ ) ~→ 网上也没有什么解决方法,经过重新编译工具->查看issue->重搭环境之后,决定使用微软力推的lsp 总之就是启用useLanguageServer,需要预先编译gopls,然后启用ExperimentalFeatures,关闭server Format,为了支持格式化,设置defaultFormatter,超快的代码提示又回来啦( ̄▽ ̄)" 贴一下我的配置 ``` { "files.autoSave": "afterDelay", "go.goroot": "C:/Go", "go.gopath": "C:/Code/MyGoWorks", "go.useLanguageServer": true, "go.languageServerExperimentalFeatures": { "format": false, "autoComplete": true, "rename": true, "goToDefinition": true, "hover": true, "signatureHelp": true, "goToTypeDefinition": true, "goToImplementation": true, "documentSymbols": true, "workspaceSymbols": true, "findReferences": true, "diagnostics": false }, "http.proxy": "http://127.0.0.1:1080", "[go]": { "editor.defaultFormatter": "ms-vscode.Go" }, } ``` PS. 看到bingo作者的声明,一时些许感慨 > I am very sorry that I have planned not continue to maintain this project. > > According to the issue #13 collaborating on golsp, I hope that we will eventually have a unified language server: gopls. > > It is Google's upcoming Go language server. It is in the best interests of the community to only have a single language server.

link

使用StartTLS

我们知道smtp是邮件传输协议,传输过程中往往需要加密 直接使用TLS/SSL加密当然简单明白,但是为了兼容传统的传输方式,出现了StartTLS 简单说就是先使用明文通信,如果双方支持加密的话升级为TLS加密通信 当然,前提是邮箱服务器支持StartTLS(各服务商支持并不相同),目前来看,还是老老实实tls吧 放一下标准库里的StartTLS实现 ``` // StartTLS sends the STARTTLS command and encrypts all further communication. // Only servers that advertise the STARTTLS extension support this function. func (c *Client) StartTLS(config *tls.Config) error { if err := c.hello(); err != nil { return err } _, _, err := c.cmd(220, "STARTTLS") if err != nil { return err } c.conn = tls.Client(c.conn, config) c.Text = textproto.NewConn(c.conn) c.tls = true return c.ehlo() } ``` 如果服务端仅支持TLS,c.hello()会无法收到正确信息,c.cmd()报错

link

关于interface{}

编译下列代码,哪些行会出现编译错误 ``` package main type Books struct { } func foo1(x interface{}) { } func foo2(x *interface{}) { } func main() { s := Books{} p := &s foo1(s) //line:1 foo2(s) //line:2 foo1(p) //line:3 foo2(p) //line:4 } ``` 编译提示line2,line4出错,*interface {} is pointer to interface, not interface 即指向接口的指针不是接口 怎么理解呢,空接口可以是任意类型,当然可以是指针,所以line1,3是没有问题的 最终在[stackoverflow](https://stackoverflow.com/questions/44370277/type-is-pointer-to-interface-not-interface-confusion)上找到了答案 接口保持了传入值的指针和类型,本身相当于指针了 s呢?是一个Book类型,Book实现了空接口(他还有可能实现其他接口), 但Book不是空接口啊,这时传入foo2(s),便会提示s不是空接口指针类型 同样的,p是指向Book的指针,并不是指向接口的指针,故也无法编译 Golang接口是一个方法集,实现了其全部方法的类型即实现了此接口,但接口和普通类型仍有区别 如: ``` type Books interface { foo() } type book struct{ name string } func (b book)foo(){ // 方式1 } func (b *book)foo(){ // 方式2 } ``` 方式1可以实现Books接口,但无法修改其内部变量,换言之,b是值传递 方式2也实现了Books接口,但是为指针传递传递,使用中会隐式进行指针类型转换 即: 方式1可用(book).foo() 方式2可用(*book1).foo() , (book).foo()

link

又是一年春招季

大概今年经济总体形势低迷,尤其互联网公司裁员成了常态 春节期间打车,司机师傅拐弯抹脚地找我们发红包,后来竟直接张口: “今年实体经济不好做,你们多支持一下” 想起来上一次听到这话大概是某个开网店的亲戚这么说 是果真如此,还是人云亦云,亦或者得了便宜卖乖? 又是一年春招,不同的是,自己准备投身其中了 大概是因为理想吧 风口终究会平静,真正有价值的东西更有可能留下来 总的来说,还是看好互联网前景的,毕竟当初可是说好让计算机取代各行各业的 总不能自己先栽跟头 套一句话,我们拭目以待

link

Golang数据库驱动

SQLite3驱动,参考: https://www.sqlite.org https://golang.org/pkg/database/sql/driver https://www.cnblogs.com/5211314jackrose/p/5816532.html https://github.com/astaxie/build-web-application-with-golang/blob/master/zh/05.1.md 不得不说C语言真的强大,SQLite3也仅提供了一组接口 试着读了一下源码,果断选择使用Cgo,面向接口编程/白眼 总之参考各方资料,简单实现了基本功能,bug多多,纯属自用 最近在学习算法相关的知识,果然先要有理论基础才能处变不慌

link

雪意留君君不住,知道故人相念否

新年快乐

link