golang 网络编程实践

我爱张智容 · · 459 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

webmain.go

package main

import (
    "log"
    "net/http"
    "os"
    "os/signal"
    "strings"
)

type web1Handler struct{}

func (*web1Handler) GetIp(r *http.Request) string {
    ips := r.Header.Get("x-forwarded-for")
    if ips != "" {
        ips_list := strings.Split(ips, ",")
        if len(ips_list) > 0 && ips_list[0] != "" {
            return ips_list[0]
        }
    }
    return r.RemoteAddr;
}

func (this *web1Handler) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
    //_, _ = writer.Write([]byte("web1"))
    //BasicAuth
    /*auth := request.Header.Get("Authorization")
    if auth == "" {
        writer.Header().Set("WWW-Authenticate", `Basic realm="请输入用户名密码...."`)
        writer.WriteHeader(http.StatusUnauthorized)
        return
    }

    auth_list := strings.Split(auth, " ")

    if len(auth_list) == 2 && auth_list[0] == "Basic" {
        res, err := base64.StdEncoding.DecodeString(auth_list[1])
        if err == nil && string(res) == "frans:zxc" {
            //_, _ = writer.Write([]byte("<h1>Frans Web IP:" + request.RemoteAddr + "</h1>"))
            _, _ = writer.Write([]byte("<h1>Frans Web IP:" + this.GetIp(request) + "</h1>"))
            return
        }
    }*/

    _, _ = writer.Write([]byte("web1....."))
}

type web2Handler struct{}

func (web2Handler) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
    _, _ = writer.Write([]byte("web2"))
}

type web3Handler struct{}

func (web3Handler) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
    _, _ = writer.Write([]byte("web3"))
}

func main() {

    //make信号通道
    c := make(chan os.Signal)

    go (func() {
        _ = http.ListenAndServe(":9091", &web1Handler{})
    })();
    go (func() {
        _ = http.ListenAndServe(":9092", web2Handler{})
    })();
    go (func() {
        _ = http.ListenAndServe(":9093", web3Handler{})
    })();

    //监听信号
    signal.Notify(c, os.Interrupt)

    //读取通道是否有值 (阻塞)
    s := <-c

    log.Println(s);
}

proxy.go

package main

import (
    "log"
    "net/http"
    "net/http/httputil"
    "net/url"
    "practice/util"
)

/*func cloneHeader(src http.Header, dest *http.Header) {
    for k, v := range src {
        dest.Set(k, v[0])
    }
}*/

type ProxyHandler struct{}

func (*ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {

    defer func() {
        if err := recover(); err != nil {
            w.WriteHeader(http.StatusInternalServerError)
            log.Println(err)
        }
    }()

    //target, _ := url.Parse(slb.SelectByRand().Host) //随机算法
    //target, _ := url.Parse(slb.SelectByIPHash(r.RemoteAddr).Host) //IPHash算法
    //target, _ := url.Parse(util.Slb.SelectByWeightRand().Host) //IPHash算法
    target, _ := url.Parse(util.Slb.RoundRobin().Host) //IPHash算法
    proxy := httputil.NewSingleHostReverseProxy(target)
    proxy.ServeHTTP(w, r)

    /*if r.URL.Path == "/a" {
        util.RequestUrl(w, r, "http://localhost:9091")
        return
    }
    if r.RequestURI == "/b" {
        util.RequestUrl(w, r, "http://localhost:9092")
        return
    }*/

    //遍历已经读取好了的配置文件
    /*for k, v := range util.ProxyConfig {
        if matched, _ := regexp.MatchString(k, r.URL.Path); matched == true {
            //util.RequestUrl(w, r, v)  //开始反向代理

            //使用golang内置反向代理
            target, _ := url.Parse(v)
            proxy := httputil.NewSingleHostReverseProxy(target)
            proxy.ServeHTTP(w, r)

            return
        }
    }*/

    _, _ = w.Write([]byte("Golang is Working ..."))

}

func main() {
    _ = http.ListenAndServe(":8080", &ProxyHandler{})
}

util/config.go

package util

import (
    "github.com/go-ini/ini"
    "log"
    "os"
)

var ProxyConfig map[string]string

type EnvConfig *os.File

func init() {
    ProxyConfig = make(map[string]string)

    EnvConfig, err := ini.Load("env")

    if err != nil {
        log.Println(err)
        return
    }

    proxy, _ := EnvConfig.GetSection("proxy")
    if proxy != nil {
        secs := proxy.ChildSections()
        for _, sec := range secs {
            path, _ := sec.GetKey("path")
            pass, _ := sec.GetKey("pass")
            if path != nil && pass != nil {
                ProxyConfig[path.Value()] = pass.Value()
            }
        }
    }

}

util/func.go

package util

import (
    "io/ioutil"
    "net/http"
)

func CloneHeader(src http.Header, dest *http.Header) {
    for k, v := range src {
        dest.Set(k, v[0])
    }
}

func RequestUrl(w http.ResponseWriter, r *http.Request, url string) {

    newReq, _ := http.NewRequest(r.Method, url, r.Body)
    CloneHeader(r.Header, &newReq.Header)
    //增加头信息
    newReq.Header.Add("x-forwarded-for", r.RemoteAddr)

    newResp, _ := http.DefaultClient.Do(newReq)
    getHeader := w.Header()
    CloneHeader(newResp.Header, &getHeader)

    w.WriteHeader(newResp.StatusCode)
    defer newResp.Body.Close()
    respTxt, _ := ioutil.ReadAll(newResp.Body)
    _, _ = w.Write(respTxt)

}

util/loadBalance.go (算法都在此文件)

package util

import (
    "hash/crc32"
    "math/rand"
    "time"
)

type HttpServer struct {
    Host   string
    Weight int
}

func NewHttpServer(host string, weight int) *HttpServer {
    return &HttpServer{Host: host, Weight: weight}
}

type LoadBalance struct {
    Servers   []*HttpServer
    CurrIndex int
}

func NewLoadBalance() *LoadBalance {
    return &LoadBalance{Servers: make([]*HttpServer, 0)}
}

func (this *LoadBalance) AddServer(server *HttpServer) {
    this.Servers = append(this.Servers, server)
}

//随机算法
func (this *LoadBalance) SelectByRand() *HttpServer {
    rand.Seed(time.Now().UnixNano()) //设置种子
    //fmt.Println(rand.Intn(2))        // 表示只在 2以下获取随机数 只能取到 0 1 两个数
    idx := rand.Intn(len(this.Servers));
    return this.Servers[idx]
}

//Hash算法
func (this *LoadBalance) SelectByIPHash(ip string) *HttpServer {
    idx := int(crc32.ChecksumIEEE([]byte(ip))) % len(this.Servers)
    return this.Servers[idx]
}

//随机加权重算法
func (this *LoadBalance) SelectByWeightRand() *HttpServer {
    rand.Seed(time.Now().UnixNano())
    idx := rand.Intn(len(ServerIndexes))
    return this.Servers[ServerIndexes[idx]]
}

//随机算法
func (this *LoadBalance) RoundRobin() *HttpServer {

    server := this.Servers[this.CurrIndex]
    this.CurrIndex++

    if this.CurrIndex >= len(this.Servers) {
        this.CurrIndex = 0
    }

    return server;
}

//加权随机算法
func (this *LoadBalance) RoundRobinByWeight() *HttpServer {

    server := this.Servers[ServerIndexes[this.CurrIndex]]
    this.CurrIndex = (this.CurrIndex + 1) % len(ServerIndexes)
     
    return server;
}

var (
    Slb           *LoadBalance
    ServerIndexes []int
)

//初始化
func init() {
    Slb = NewLoadBalance()

    Slb.AddServer(NewHttpServer("http://localhost:9091", 5))
    Slb.AddServer(NewHttpServer("http://localhost:9092", 15))
    Slb.AddServer(NewHttpServer("http://localhost:9093", 20))

    for index, server := range Slb.Servers {
        if server.Weight > 0 {
            for i := 0; i < server.Weight; i++ {
                ServerIndexes = append(ServerIndexes, index)
            }
        }
    }

}

复制代码可以跑起来。


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:我爱张智容

查看原文:golang 网络编程实践

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

459 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传