golang源码剖析-网络库的基础实现-1

转自: http://skoo.me/go/2014/04/21/go-net-core
偶遇大神写的文章, 分析的很透彻, 转过来学习了.

Go语言的出现,让我见到了一门语言把网络编程这件事情给做“正确”了,当然,除了Go语言以外,还有很多语言也把这件事情做”正确”了。我一直坚持着这样的理念——要做”正确”的事情,而不是”高性能”的事情;很多时候,我们在做系统设计、技术选型的时候,都被“高性能”这三个字给绑架了,当然不是说性能不重要,你懂的。

目前很多高性能的基础网络服务器都是采用的C语言开发的,比如:Nginx、Redis、memcached等,它们都是基于”事件驱动 + 事件回掉函数”的方式实现,也就是采用epoll等作为网络收发数据包的核心驱动。不少人(包括我自己)都认为“事件驱动 + 事件回掉函数”的编程方法是“反人类”的;因为大多数人都更习惯线性的处理一件事情,做完第一件事情再做第二件事情,并不习惯在N件事情之间频繁的切换干活。为了解决程序员在开发服务器时需要自己的大脑不断的“上下文切换”的问题,Go语言引入了一种用户态线程goroutine来取代编写异步的事件回掉函数,从而重新回归到多线程并发模型的线性、同步的编程方式上。

用Go语言写一个最简单的echo服务器

package main

import (
    "log"
    "net"
)

func main() {
    ln, err := net.Listen("tcp", ":8080")
    if err != nil {
            log.Println(err)
            return
    }
    for {
            conn, err := ln.Accept()
            if err != nil {
                log.Println(err)
                continue
            }

            go echoFunc(conn)
    }
}

func echoFunc(c net.Conn) {
    buf := make([]byte, 1024)

    for {
            n, err := c.Read(buf)
            if err != nil {
                log.Println(err)
                return
            }

            c.Write(buf[:n])
    }
}

main函数的过程就是首先创建一个监听套接字,然后用一个for循环不断的从监听套接字上Accept新的连接,最后调用echoFunc函数在建立的连接上干活。关键代码是:

go echoFunc(conn)

每收到一个新的连接,就创建一个“线程”去服务这个连接,因此所有的业务逻辑都可以同步、顺序的编写到echoFunc函数中,再也不用去关心网络IO是否会阻塞的问题。不管业务多复杂,Go语言的并发服务器的编程模型都是长这个样子。可以肯定的是,在linux上Go语言写的网络服务器也是采用的epoll作为最底层的数据收发驱动,Go语言网络的底层实现中同样存在“上下文切换”的工作,只是这个切换工作由runtime的调度器来做了,减少了程序员的负担。

今天就先学习,这四个函数了:

Listen、Accept、Read、Write

猜你喜欢

转载自blog.csdn.net/robertkun/article/details/80087304