diff --git a/client/config.go b/client/config.go index fbafa30ea..6f7392b53 100644 --- a/client/config.go +++ b/client/config.go @@ -29,39 +29,39 @@ import ( // Config for client type Config struct { - LocalAddr string `json:"localaddr"` - RemoteAddr string `json:"remoteaddr"` - Key string `json:"key"` - Crypt string `json:"crypt"` - Mode string `json:"mode"` - Conn int `json:"conn"` - AutoExpire int `json:"autoexpire"` - ScavengeTTL int `json:"scavengettl"` - MTU int `json:"mtu"` - SndWnd int `json:"sndwnd"` - RcvWnd int `json:"rcvwnd"` - DataShard int `json:"datashard"` - ParityShard int `json:"parityshard"` - DSCP int `json:"dscp"` - NoComp bool `json:"nocomp"` - AckNodelay bool `json:"acknodelay"` - NoDelay int `json:"nodelay"` - Interval int `json:"interval"` - Resend int `json:"resend"` - NoCongestion int `json:"nc"` - SockBuf int `json:"sockbuf"` - SmuxVer int `json:"smuxver"` - SmuxBuf int `json:"smuxbuf"` - StreamBuf int `json:"streambuf"` - KeepAlive int `json:"keepalive"` - Log string `json:"log"` - SnmpLog string `json:"snmplog"` - SnmpPeriod int `json:"snmpperiod"` - Quiet bool `json:"quiet"` - TCP bool `json:"tcp"` - Pprof bool `json:"pprof"` - QPP bool `json:"qpp"` - QPPCount int `json:"qpp-count"` + LocalAddr string `json:"localaddr"` + RemoteAddr []string `json:"remoteaddr"` + Key string `json:"key"` + Crypt string `json:"crypt"` + Mode string `json:"mode"` + Conn int `json:"conn"` + AutoExpire int `json:"autoexpire"` + ScavengeTTL int `json:"scavengettl"` + MTU int `json:"mtu"` + SndWnd int `json:"sndwnd"` + RcvWnd int `json:"rcvwnd"` + DataShard int `json:"datashard"` + ParityShard int `json:"parityshard"` + DSCP int `json:"dscp"` + NoComp bool `json:"nocomp"` + AckNodelay bool `json:"acknodelay"` + NoDelay int `json:"nodelay"` + Interval int `json:"interval"` + Resend int `json:"resend"` + NoCongestion int `json:"nc"` + SockBuf int `json:"sockbuf"` + SmuxVer int `json:"smuxver"` + SmuxBuf int `json:"smuxbuf"` + StreamBuf int `json:"streambuf"` + KeepAlive int `json:"keepalive"` + Log string `json:"log"` + SnmpLog string `json:"snmplog"` + SnmpPeriod int `json:"snmpperiod"` + Quiet bool `json:"quiet"` + TCP bool `json:"tcp"` + Pprof bool `json:"pprof"` + QPP bool `json:"qpp"` + QPPCount int `json:"qpp-count"` } func parseJSONConfig(config *Config, path string) error { diff --git a/client/dial.go b/client/dial.go index ffb4c38c2..6693183ea 100644 --- a/client/dial.go +++ b/client/dial.go @@ -35,8 +35,8 @@ import ( ) // dial connects to the remote address -func dial(config *Config, block kcp.BlockCrypt) (*kcp.UDPSession, error) { - mp, err := std.ParseMultiPort(config.RemoteAddr) +func dial(config *Config, block kcp.BlockCrypt, idx uint16) (*kcp.UDPSession, error) { + mp, err := std.ParseMultiPort(config.RemoteAddr[idx]) if err != nil { return nil, err } diff --git a/client/main.go b/client/main.go index 279016578..60be11525 100644 --- a/client/main.go +++ b/client/main.go @@ -32,6 +32,7 @@ import ( "net/http" _ "net/http/pprof" "os" + "strings" "time" "golang.org/x/crypto/pbkdf2" @@ -76,7 +77,7 @@ func main() { cli.StringFlag{ Name: "remoteaddr, r", Value: "vps:29900", - Usage: `kcp server address, eg: "IP:29900" a for single port, "IP:minport-maxport" for port range`, + Usage: `kcp server address, eg: "IP:29900" a for single server/port, "IP1:minport-maxport_IP2:minport-maxport..." for multi server and port range`, }, cli.StringFlag{ Name: "key", @@ -238,7 +239,7 @@ func main() { myApp.Action = func(c *cli.Context) error { config := Config{} config.LocalAddr = c.String("localaddr") - config.RemoteAddr = c.String("remoteaddr") + config.RemoteAddr = strings.Split(c.String("remoteaddr"), "_") // remote address split by "_" config.Key = c.String("key") config.Crypt = c.String("crypt") config.Mode = c.String("mode") @@ -403,8 +404,8 @@ func main() { block, _ = kcp.NewAESBlockCrypt(pass) } - createConn := func() (*smux.Session, error) { - kcpconn, err := dial(&config, block) + createConn := func(idx uint16) (*smux.Session, error) { + kcpconn, err := dial(&config, block, idx) if err != nil { return nil, errors.Wrap(err, "dial()") } @@ -449,9 +450,9 @@ func main() { } // wait until a connection is ready - waitConn := func() *smux.Session { + waitConn := func(idx uint16) *smux.Session { for { - if session, err := createConn(); err == nil { + if session, err := createConn(idx); err == nil { return session } else { log.Println("re-connecting:", err) @@ -475,7 +476,8 @@ func main() { } // start listener - numconn := uint16(config.Conn) + rlen := (uint16)(len(config.RemoteAddr)) + numconn := uint16(config.Conn * int(rlen)) muxes := make([]timedSession, numconn) rr := uint16(0) @@ -491,11 +493,12 @@ func main() { log.Fatalf("%+v", err) } idx := rr % numconn + ridx := rr % rlen // do auto expiration && reconnection if muxes[idx].session == nil || muxes[idx].session.IsClosed() || (config.AutoExpire > 0 && time.Now().After(muxes[idx].expiryDate)) { - muxes[idx].session = waitConn() + muxes[idx].session = waitConn(ridx) muxes[idx].expiryDate = time.Now().Add(time.Duration(config.AutoExpire) * time.Second) if config.AutoExpire > 0 { // only when autoexpire set chScavenger <- muxes[idx]