golang并发编程入门以及SOCKS5代理服务器学习

59 阅读2分钟

golang并发编程

进程与线程:在多线程系统中,进程是资源分配的基本单位,线程是系统调度的基本单位

线程与协程:一个进程可以拥有多个线程,一个线程也可以拥有多个协程。最重要的是,协程不是被操作系统内核所管理,而完全是由程序所控制(也就是在用户态中执行)。协程的开销远远小于线程的开销

Go 中使用 Goroutine 来实现并发 (能够简易的实现多线程)Goroutine 是 Go的特有名词, 区别于进程Process, 线程Thread。Goroutine 是与其他函数或方法同时进行的函数或方法。创建Goroutine的成本很小,

package main

import (
"fmt"
"time"
)

func main() {
        go calsquare()
        time.Sleep(time.Second) // 没有sleep运行错误
}

func calsquare() {
        src := make(chan int)
        dest := make(chan int, 3)

        go func() {
                defer close(src)
                for i := 0; i < 10; i++ {
                        src <- i
                }
        }()

        go func() {
                defer close(dest)
                for i := range src {
                        dest <- i * i
                }
        }()

        for i := range dest {
                fmt.Println(i)
        }
    }

go func()为什么运行不了?父级协程没有等待子协程完成就退出了。Go 提倡以 channel 方式在协程间同步信息,但如果只是强调任务是否完成,或许 WaitGroup 更好。

有无缓冲通道区别,缓冲通道有什么用?

通道和 goroutine 是 Go 语言基于 CSP并发机制的核心部分。无缓冲 channel 在消息发送时需要接收者就绪。声明无缓冲 channel 的方式是不指定缓冲大小。

SOCKS5代理服务器工作流程:

1.协商阶段

client发送给代理服务器发送请求报文(协议版本号+支持的认证种类),代理服务器返回认证方式

2.认证阶段

因为实现的是不需要认证的代理服务器,所以跳过该阶段

3.请求阶段

client向代理服务器发送connection请求,需要连接某个服务器连接。代理服务器去连接真正的服务器,并返回响应。

4.relay阶段

此时,client正常发送请求,代理服务器收到请求后,直接转发到后端服务器上。

func main() {
        server, err := net.Listen("tcp", "127.0.0.1:1080")
        if err != nil {
                panic(err)
        }

        for { // recurrent accept from server
                client, err := server.Accept()
                if err != nil {
                        log.Printf("Accept failed %v", err)
                        continue
                }

	// go routine, the key 'go'
	go process(client) // process the connection in process() function
}
}

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
        }
        log.Println("auth success")

        // 请求连接阶段
        err = connect(reader, conn)
        if err != nil {
                log.Printf("client %v connect failed: %v", conn.RemoteAddr(), err)
                return
        }
        log.Println("connect success")
}

个人体会:使用golang进行服务器编程在流程上十分清楚,错误管理方面更加清晰简洁。SOCKS5代理服务器编程作业上,对于认证、连接业务逻辑不熟练,在完成作业时复制粘贴内容较多。