Posted on 2014-02-28 16:49:03 network
在此博客运行的云主机上,使用SMTP客户端发送邮件到国内的SMTP服务器,报如下错误:
2014/02/28 16:17:29 551 User not local; please try <forward-path>
说明:这个错误和邮件内容、标题等完全没有关系,而是GFW的原因。Google到如下答案:
中国政府的国家防火墙(GFW,又名`金盾工程`)做了过滤的原因,它(金盾工程)定义了大陆的IP连接到大陆以外(如香港、台湾、欧洲等)的邮件服务器是不可以自己发邮件给自己的!只要大陆所在客户端用大陆的IP发送邮件,马上就会提示551 User not local; please try这样的错误信息!
本人实际遇到的问题,是在国外的主机上使用大陆的邮件服务器,发送邮件给自己。应该也是GFW在作怪。
解决办法有两个:
在使用了Gmail的SMTP服务器发送邮件到QQ的SMTP邮件服务器之后,错误不再出现。
Posted on 2014-02-23 13:41:38 golang
在C语言中,字符串的内存模型定义为以NUL
(\x0)结尾的字节数组。这是为大家所熟知的。
但是在Golang中并不是如此,Golang中的字符串abc
和abc\x0\x0
并不相当,所以说Golang明确规定了字符串的长度,而不是以\x0
为结尾来判断的。
下面看示例代码:
package main
import (
"fmt"
"os"
)
func main() {
var a[5]byte = [5]byte{'a','b','c'}
var b[]byte = []byte{'a','b','c'}
fmt.Printf("len(a): %d, %q\n", len(a), a)
fmt.Printf("len(b): %d, %q\n", len(b), b)
slice_a := a[:]
str_a := string(slice_a)
str_b := string(b)
fmt.Printf("len(str_a): %d, %q:%s\n", len(str_a), str_a, str_a)
fmt.Printf("len(str_b): %d, %q:%s\n", len(str_b), str_b, str_b)
if str_a == str_b {
fmt.Println("str_a == str_b")
} else {
fmt.Println("str_a != str_b")
}
file, err := os.Create(str_a)
if err != nil {
fmt.Println(err)
}
fmt.Println(file)
}
代码输出为:
len(a): 5, "abc\x00\x00"
len(b): 3, "abc"
len(str_a): 5, "abc\x00\x00":abc
len(str_b): 3, "abc":abc
str_a != str_b
open abc: invalid argument
<nil>
数组a
长度为5,最后两个字节为\x00
。切片b
长度为3,有效内容为abc
。
分别将a和b转换为string类型后,数组a
中包含的\x00
也被保留下来,所以在对比时,这两者的长度不可能相等的。
当然这还不是最关键的,问题处在当用str_a作为文件名创建文件时file, err := os.Create(str_a)
,系统会报错:open abc: invalid argument
。说明这不是一个有效的路径名称。
Golang是一种强类的语言,对于数组来说[3]byte
和[5]byte
并不是同一个类型,不能通用。
当然,数组和切片也更不可能是同一个类型。
解决办法是,迭代数组中的字节,跳过为0
的字节:
func GetValidByte(src []byte) []byte {
var str_buf []byte
for _, v := range src {
if v != 0 {
str_buf = append(str_buf, v)
}
}
return str_buf
}
Posted on 2014-02-22 07:59:54 network
摘要:我认为,想要熟练掌握Linux下的TCP/IP网络编程,至少有三个层面的知识需要熟悉:
1. TCP/IP协议(如连接的建立和终止、重传和确认、滑动窗口和拥塞控制等等)
2. Socket I/O系统调用(重点如read/write),这是TCP/IP协议在应用层表现出来的行为。
3. 编写Performant, Scalable的服务器程序。包括多线程、IO Multiplexing、非阻塞、异步等各种技术。
关于TCP/IP协议,建议参考Richard Stevens的《TCP/IP Illustrated,vol1》(TCP/IP详解卷1)。
关于第二层面,依然建议Richard Stevens的《Unix network proggramming,vol1》(Unix网络编程卷1),这两本书公认是Unix网络编程的圣经。
至于第三个层面,UNP的书中有所提及,也有著名的C10K问题,业界也有各种各样的框架和解决方案,本人才疏学浅,在这里就不一一敷述。
本文的重点在于第二个层面,主要总结一下Linux下TCP/IP网络编程中的read/write系统调用的行为,知识来源于自己网络编程的粗浅经验和对《Unix网络编程卷1》相关章节的总结。由于本人接触Linux下网络编程时间不长,错误和疏漏再所难免,望看官不吝赐教。
阅读全文Posted on 2014-02-13 16:41:10 gevent
摘要:hub是gevent中核心,依靠libev这个事件库,来调度所有的greenlet。
hub也是一个greenlet,就是所谓的’main’ greenlet。
hub会首先启动,然后马上启动事件循环。也就是libev的loop。
hub对应到实际的代码就是hub.py,其中最关键的是Hub类。
hub保存在线程的本地数据中,所以说每个线程中只存在一个’main’ hub。
从main greenlet切换到普通greenlet之后,main greenlet是停止执行的。greenlet是安排合理的串行,从而看起来像是并行。
切换到main greenlet是指首先切换到hub.wait,然后在greenlet.so中执行真正的greenlet切换。 即切换到需要运行的那个greenlet。
所谓的’由hub决定运行哪个greenlet’,实际上是loop检测到greenlet感兴趣的事件后,首先切换到hub,再由hub.switch切换到发生事件的那个greenlet。主导整个过程的是libev的loop。
Posted on 2014-02-12 08:11:23 python
摘要:一个 greenlet 是一个很小的独立微线程。可以把它想像成一个堆栈帧,栈底是初始调用,而栈顶是当前greenlet的暂停位置。你使用greenlet创建一堆这样的堆 栈,然后在他们之间跳转执行。跳转不是绝对的:一个greenlet必须选择跳转到选择好的另一个greenlet,这会让前一个挂起,而后一个恢复。两 个greenlet之间的跳转称为 切换(switch) 。
当你创建一个greenlet,它得到一个初始化过的空堆栈;当你第一次切换到它,他会启动指定的函数,然后切换跳出greenlet。当最终栈底 函数结束时,greenlet的堆栈又编程空的了,而greenlet也就死掉了。greenlet也会因为一个未捕捉的异常死掉。
阅读全文Posted on 2014-02-12 07:36:22 c
摘要:libev是Marc Lehmann用C写的高性能事件循环库。通过libev,可以灵活地把各种事件组织管理起来,如:时钟、io、信号等。libev在业界内也是广受好评,不少项目都采用它来做底层的事件循环。
阅读全文Posted on 2014-02-10 09:30:13 c
摘要:每个文件描述符都有一个close-on-exec标志。默认情况下,这个标志最后一位被设置为 0。这个标志符的具体作用在于当开辟其他进程调用exec()族函数时,在调用exec函数之前为exec族函数释放对应的文件描述符。
阅读全文Posted on 2014-02-10 08:43:22 golang
摘要:Golang有自带的net/rpc和net/rpc/jsonrpc,前者是基于Gob编码协议的RPC,后者在前者基础上使用JSON编码。
在Python的世界,RESTful的框架比比皆是。由于Golang标准库没有自带,但有许多优秀的第三方库,例如下面要介绍的这个库,go-json-rest.
阅读全文