(续接上文)
在了解了defer之后,我们再来看process函数。在main函数中,我们已经获取了一个server,并通过server.Accept得到client,也就是Conn链接。在process函数中,先将关闭Conn链接的操作放入defer中,用于释放资源。也就是在这个函数结束的时候,这个链接的生命周期也就随之结束。
接下来使用bufio.NewReader(conn)创建一个只读的缓冲流,此时,我们可以使用eader.ReadByte()对缓冲流中的数据进行读取,并通过conn.Write([]byte{b})将读取的信息输出至控制台,以便校验。
func process(conn net.Conn) {
defer conn.Close()
reader := bufio.NewReader(conn)
for {
b, err := reader.ReadByte()
if err != nil {
break
}
_, err = conn.Write([]byte{b})
if err != nil {
break
}
}
}
注: 这里测试时我们不仅要使用go run XX.go启动程序(XX.go为你对该程序的命名),也要用nc命令创建一个tcp连接,比如现在我们使用的ip和端口号是127.0.0.1:1080,则创建命令为nc 127.0.0.1 1080,此时你就可以在控制台输入一些字符以验证该程序的正确性了,比如输入hello world,那么服务器就会同时返回一个hello world。(不一样的语言,一样的hello world!)
2. 认证阶段
在验证完上述实验,是不是一个大大的amazing,给自己点个赞之后,我们继续下一步。刚刚我们已经做了一个可以返回你输入信息的TCP Server。但代理服务器肯定不可能这么简单,我们要一步一步为它添加功能,我们来看一下鉴权。我们先对process函数的程序稍稍做一下改动。
func process(conn net.Conn) {
defer conn.Close()
reader := bufio.NewReader(conn)
err := auth(reader, conn)
if err != nil {
log.Printf("client %v auth failed:%v", conn.RemoteAddr(), err)
return
}
err = connect(reader, conn)
if err != nil {
log.Printf("client %v auth failed:%v", conn.RemoteAddr(), err)
return
}
}
与之前process函数相比,我们通过使用auth(reader, conn)函数,对链接信息进行鉴权,如果失败,那自然不可能进行下一步操作,直接输出err,退出程序即可。若验证成功,则进行链接,同样,若失败,则打印err信息,退出程序;若成功,则Socks5代理服务器功能已经实现。