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