1什么是代理服务器:
所谓代理服务器就是位于发起请求的客户端与原始服务器端之间的一台跳板服务器,正向代理可以隐藏客户端,反向代理可以隐藏原始服务器。

2正向代理:
用户知道目标服务器地址,但由于网络限制等原因,无法直接访问。这时候需要先连接代理服务器,然后再由代理服务器访问目标服务器。
在这里插入图片描述

3反向代理:
反向代理对用户则是不可知的,比如我们访问百度网站,百度的代理服务器对外的域名为 https://www.baidu.com 。具体内部的服务器节点我们不知道,现实中我们通过访问百度的代理服务器后,代理服务器给我们转发请求到他们N多的服务器节点中的一个给我们进行搜索后将结果返回。
在这里插入图片描述

下面是一个正向代理服务器demo:

package main

import (
	"fmt"
	"io"
	"net"
	"os"
	"strings"
	"sync"

	"github.com/urfave/cli/v2"
	"golang.org/x/sys/unix"
)

type tcpproxy struct {
	lock sync.Mutex
	dsts []string
	src  string
}

var TcpProxy = &cli.Command{
	Name:      "tcpproxy",
	Aliases:   []string{""},
	Usage:     "tcp port proxy",
	UsageText: "tcpproxy [--src=0.0.0.0:7777] [--dst=136.19.188.100:9999,136.19.188.110:9999,136.19.188.120:9999]",
	Flags: []cli.Flag{
		&cli.StringFlag{
			Name:   "src",
			Hidden: true,
		},
		&cli.StringFlag{
			Name:   "dst",
			Hidden: true,
		},
	},

	Action: func(cctx *cli.Context) error {
		src := cctx.String("src")
		dst := cctx.String("dst")
		if src == "" || dst == "" {
			fmt.Println(cctx.Command.UsageText)
			return nil
		}

		tp := &tcpproxy{
			src:  src,
			dsts: strings.Split(dst, ","),
		}
		tp.server()

		return nil
	},
}

func main() {
	local := []*cli.Command{
		TcpProxy,
	}

	app := &cli.App{
		Name:                 "proxy",
		Usage:                "proxy tcpproxy",
		Version:              "v0.0.1",
		EnableBashCompletion: true,
		Flags: []cli.Flag{
			&cli.StringFlag{
				Name:    "configfile",
				EnvVars: []string{""},
				Hidden:  true,
				Value:   "cfg.toml",
			},
		},
		Commands: local,
	}

	if err := app.Run(os.Args); err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: %s\n\n", err) // nolint:errcheck
		os.Exit(1)
	}
}

func unixSetLimit(soft uint64, max uint64) error {
	rlimit := unix.Rlimit{
		Cur: soft,
		Max: max,
	}
	return unix.Setrlimit(unix.RLIMIT_NOFILE, &rlimit)
}

func (p *tcpproxy) server() {
	unixSetLimit(60000, 60000)
	listen, err := net.Listen("tcp", p.src)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer listen.Close()
	fmt.Println("listen at:", p.src)
	for {
		conn, err := listen.Accept()
		if err != nil {
			fmt.Printf("接受客户端连接错误:%v\n", err)
			continue
		}
		fmt.Println("build new proxy connect. ", "client address =", conn.RemoteAddr(), " local server address=", conn.LocalAddr())
		go p.handle(conn)
	}
}

func (p *tcpproxy) handle(sconn net.Conn) {
	defer sconn.Close()
	dst, ok := p.select_dst()
	if !ok {
		return
	}
	dconn, err := net.Dial("tcp", dst)
	if err != nil {
		fmt.Printf("连接%v失败:%v\n", dst, err)
		return
	}
	defer dconn.Close()

	ExitChan := make(chan bool, 1)
	// 转发到目标服务器
	go func(sconn net.Conn, dconn net.Conn, Exit chan bool) {
		_, err := io.Copy(dconn, sconn)
		if err != nil {
			fmt.Printf("往%v发送数据失败:%v\n", dst, err)
			ExitChan <- true
		}
	}(sconn, dconn, ExitChan)

	// 从目标服务器返回数据到客户端
	go func(sconn net.Conn, dconn net.Conn, Exit chan bool) {
		_, err := io.Copy(sconn, dconn)
		if err != nil {
			fmt.Printf("从%v接收数据失败:%v\n", dst, err)
			ExitChan <- true
		}
	}(sconn, dconn, ExitChan)
	<-ExitChan
}

// ip 轮询
func (p *tcpproxy) select_dst() (string, bool) {
	p.lock.Lock()
	defer p.lock.Unlock()

	if len(p.dsts) < 1 {
		fmt.Println("failed select_dst()")
		return "", false
	}
	dst := p.dsts[0]
	p.dsts = append(p.dsts[1:], dst)
	return dst, true
}

开起正向代理服务:

root@ubuntu:~/zz/proxy# ./proxy tcpproxy --src=0.0.0.0:7766 --dst=136.19.188.100:9999,136.19.188.110:9999,136.19.188.120:9999
listen at: 0.0.0.0:7777
build new proxy connect.  client address = 127.0.0.1:40012  local server address= 127.0.0.1:7777
build new proxy connect.  client address = 127.0.0.1:40016  local server address= 127.0.0.1:7777
build new proxy connect.  client address = 127.0.0.1:40020  local server address= 127.0.0.1:7777
build new proxy connect.  client address = 127.0.0.1:40024  local server address= 127.0.0.1:7777
build new proxy connect.  client address = 127.0.0.1:40028  local server address= 127.0.0.1:7777
build new proxy connect.  client address = 127.0.0.1:40032  local server address= 127.0.0.1:7777
build new proxy connect.  client address = 127.0.0.1:40036  local server address= 127.0.0.1:7777
build new proxy connect.  client address = 127.0.0.1:40040  local server address= 127.0.0.1:7777
build new proxy connect.  client address = 127.0.0.1:40044  local server address= 127.0.0.1:7777
build new proxy connect.  client address = 127.0.0.1:40048  local server address= 127.0.0.1:7777
build new proxy connect.  client address = 127.0.0.1:40052  local server address= 127.0.0.1:7777

curl客户端压测脚本

#!/bin/bash

for (( i=0; i<2000; i++ ))
do
        curl http://0.0.0.0:7766 &
done