Skip to content

Instantly share code, notes, and snippets.

@c93614
Forked from darkhelmet/balance.go
Created September 4, 2019 03:19
Show Gist options
  • Save c93614/513d49ff80381fd2852463c656f7b57a to your computer and use it in GitHub Desktop.
Save c93614/513d49ff80381fd2852463c656f7b57a to your computer and use it in GitHub Desktop.

Revisions

  1. @darkhelmet darkhelmet created this gist Jun 16, 2013.
    80 changes: 80 additions & 0 deletions balance.go
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,80 @@
    package main

    import (
    "flag"
    "io"
    "log"
    "net"
    "strings"
    )

    type Backends struct {
    servers []string
    n int
    }

    func (b *Backends) Choose() string {
    idx := b.n % len(b.servers)
    b.n++
    return b.servers[idx]
    }

    func (b *Backends) String() string {
    return strings.Join(b.servers, ", ")
    }

    var (
    bind = flag.String("bind", "", "The address to bind on")
    balance = flag.String("balance", "", "The backend servers to balance connections across, separated by commas")
    backends *Backends
    )

    func init() {
    flag.Parse()

    if *bind == "" {
    log.Fatalln("specify the address to listen on with -bind")
    }

    servers := strings.Split(*balance, ",")
    if len(servers) == 1 && servers[0] == "" {
    log.Fatalln("please specify backend servers with -backends")
    }

    backends = &Backends{servers: servers}
    }

    func copy(wc io.WriteCloser, r io.Reader) {
    defer wc.Close()
    io.Copy(wc, r)
    }

    func handleConnection(us net.Conn, server string) {
    ds, err := net.Dial("tcp", server)
    if err != nil {
    us.Close()
    log.Printf("failed to dial %s: %s", server, err)
    return
    }

    go copy(ds, us)
    go copy(us, ds)
    }

    func main() {
    ln, err := net.Listen("tcp", *bind)
    if err != nil {
    log.Fatalf("failed to bind: %s", err)
    }

    log.Printf("listening on %s, balancing %s", *bind, backends)

    for {
    conn, err := ln.Accept()
    if err != nil {
    log.Printf("failed to accept: %s", err)
    continue
    }
    go handleConnection(conn, backends.Choose())
    }
    }