diff --git a/client/client.go b/client/client.go
index 1659b5c..f27fb16 100755
--- a/client/client.go
+++ b/client/client.go
@@ -1,13 +1,17 @@
 package client
 
 import (
+	"bufio"
 	"github.com/cnlh/nps/lib/common"
 	"github.com/cnlh/nps/lib/config"
 	"github.com/cnlh/nps/lib/conn"
+	"github.com/cnlh/nps/lib/crypt"
 	"github.com/cnlh/nps/lib/mux"
 	"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
 	"github.com/cnlh/nps/vender/github.com/xtaci/kcp"
 	"net"
+	"net/http"
+	"strconv"
 	"time"
 )
 
@@ -16,6 +20,7 @@ type TRPClient struct {
 	bridgeConnType string
 	proxyUrl       string
 	vKey           string
+	p2pAddr        map[string]string
 	tunnel         *mux.Mux
 	signal         *conn.Conn
 	ticker         *time.Ticker
@@ -26,6 +31,7 @@ type TRPClient struct {
 func NewRPClient(svraddr string, vKey string, bridgeConnType string, proxyUrl string, cnf *config.Config) *TRPClient {
 	return &TRPClient{
 		svrAddr:        svraddr,
+		p2pAddr:        make(map[string]string, 0),
 		vKey:           vKey,
 		bridgeConnType: bridgeConnType,
 		proxyUrl:       proxyUrl,
@@ -71,18 +77,30 @@ func (s *TRPClient) handleMain() {
 				logs.Warn(err)
 				return
 			} else if pwd, err := s.signal.GetShortLenContent(); err == nil {
-				go s.newUdpConn(string(lAddr), string(pwd))
+				var localAddr string
+				//The local port remains unchanged for a certain period of time
+				if v, ok := s.p2pAddr[crypt.Md5(string(pwd)+strconv.Itoa(int(time.Now().Unix()/100)))]; !ok {
+					tmpConn, err := common.GetLocalUdpAddr()
+					if err != nil {
+						logs.Error(err)
+						return
+					}
+					localAddr = tmpConn.LocalAddr().String()
+				} else {
+					localAddr = v
+				}
+				go s.newUdpConn(localAddr, string(lAddr), string(pwd))
 			}
 		}
 	}
 	s.Close()
 }
 
-func (s *TRPClient) newUdpConn(rAddr string, md5Password string) {
+func (s *TRPClient) newUdpConn(localAddr, rAddr string, md5Password string) {
 	var localConn net.PacketConn
 	var err error
 	var remoteAddress string
-	if remoteAddress, localConn, err = handleP2PUdp(rAddr, md5Password, common.WORK_P2P_PROVIDER); err != nil {
+	if remoteAddress, localConn, err = handleP2PUdp(localAddr, rAddr, md5Password, common.WORK_P2P_PROVIDER); err != nil {
 		logs.Error(err)
 		return
 	}
@@ -92,7 +110,6 @@ func (s *TRPClient) newUdpConn(rAddr string, md5Password string) {
 		return
 	}
 	logs.Trace("start local p2p udp listen, local address", localConn.LocalAddr().String())
-	//接收新的监听,得到conn,
 	for {
 		udpTunnel, err := l.AcceptKCP()
 		if err != nil {
@@ -104,14 +121,10 @@ func (s *TRPClient) newUdpConn(rAddr string, md5Password string) {
 			conn.SetUdpSession(udpTunnel)
 			logs.Trace("successful connection with client ,address %s", udpTunnel.RemoteAddr().String())
 			//read link info from remote
-			l := mux.NewMux(udpTunnel, s.bridgeConnType)
-			for {
-				connMux, err := l.Accept()
-				if err != nil {
-					continue
-				}
-				go s.handleChan(connMux)
-			}
+			conn.Accept(mux.NewMux(udpTunnel, s.bridgeConnType), func(c net.Conn) {
+				go s.handleChan(c)
+			})
+			break
 		}
 	}
 }
@@ -144,7 +157,31 @@ func (s *TRPClient) handleChan(src net.Conn) {
 	}
 	//host for target processing
 	lk.Host = common.FormatAddress(lk.Host)
-	//connect to target
+	//if Conn type is http, read the request and log
+	if lk.ConnType == "http" {
+		if targetConn, err := net.Dial(common.CONN_TCP, lk.Host); err != nil {
+			logs.Warn("connect to %s error %s", lk.Host, err.Error())
+			src.Close()
+		} else {
+			go func() {
+				common.CopyBuffer(src, targetConn)
+				src.Close()
+				targetConn.Close()
+			}()
+			for {
+				if r, err := http.ReadRequest(bufio.NewReader(src)); err != nil {
+					src.Close()
+					targetConn.Close()
+					break
+				} else {
+					logs.Trace("http request, method %s, host %s, url %s, remote address %s", r.Method, r.Host, r.URL.Path, r.RemoteAddr)
+					r.Write(targetConn)
+				}
+			}
+		}
+		return
+	}
+	//connect to target if conn type is tcp or udp
 	if targetConn, err := net.Dial(lk.ConnType, lk.Host); err != nil {
 		logs.Warn("connect to %s error %s", lk.Host, err.Error())
 		src.Close()
@@ -154,6 +191,7 @@ func (s *TRPClient) handleChan(src net.Conn) {
 	}
 }
 
+// Whether the monitor channel is closed
 func (s *TRPClient) ping() {
 	s.ticker = time.NewTicker(time.Second * 5)
 loop:
diff --git a/client/control.go b/client/control.go
index 6613c84..53f1958 100644
--- a/client/control.go
+++ b/client/control.go
@@ -4,17 +4,19 @@ import (
 	"encoding/base64"
 	"encoding/binary"
 	"errors"
+	"fmt"
 	"github.com/cnlh/nps/lib/common"
 	"github.com/cnlh/nps/lib/config"
 	"github.com/cnlh/nps/lib/conn"
 	"github.com/cnlh/nps/lib/crypt"
 	"github.com/cnlh/nps/lib/version"
 	"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
-	"github.com/cnlh/nps/vender/github.com/ccding/go-stun/stun"
 	"github.com/cnlh/nps/vender/github.com/xtaci/kcp"
 	"github.com/cnlh/nps/vender/golang.org/x/net/proxy"
 	"io/ioutil"
 	"log"
+	"math"
+	"math/rand"
 	"net"
 	"net/http"
 	"net/http/httputil"
@@ -276,108 +278,137 @@ func basicAuth(username, password string) string {
 	return base64.StdEncoding.EncodeToString([]byte(auth))
 }
 
-func handleP2PUdp(rAddr, md5Password, role string) (remoteAddress string, c net.PacketConn, err error) {
-	tmpConn, err := common.GetLocalUdpAddr()
+func getRemoteAddressFromServer(rAddr string, localConn *net.UDPConn, md5Password, role string, add int) error {
+	rAddr, err := getNextAddr(rAddr, add)
+	if err != nil {
+		logs.Error(err)
+		return err
+	}
+	addr, err := net.ResolveUDPAddr("udp", rAddr)
+	if err != nil {
+		return err
+	}
+	if _, err := localConn.WriteTo(common.GetWriteStr(md5Password, role), addr); err != nil {
+		return err
+	}
+	return nil
+}
+
+func handleP2PUdp(localAddr, rAddr, md5Password, role string) (remoteAddress string, c net.PacketConn, err error) {
+	localConn, err := newUdpConnByAddr(localAddr)
+	if err != nil {
+		return
+	}
+	err = getRemoteAddressFromServer(rAddr, localConn, md5Password, role, 0)
 	if err != nil {
 		logs.Error(err)
 		return
 	}
-	localConn, err := newUdpConnByAddr(tmpConn.LocalAddr().String())
+	err = getRemoteAddressFromServer(rAddr, localConn, md5Password, role, 1)
 	if err != nil {
 		logs.Error(err)
 		return
 	}
-	localKcpConn, err := kcp.NewConn(rAddr, nil, 150, 3, localConn)
+	err = getRemoteAddressFromServer(rAddr, localConn, md5Password, role, 2)
 	if err != nil {
 		logs.Error(err)
 		return
 	}
-	conn.SetUdpSession(localKcpConn)
-	localToolConn := conn.NewConn(localKcpConn)
-	//get local nat type
-	//localNatType, host, err := stun.NewClient().Discover()
-	//if err != nil || host == nil {
-	//	err = errors.New("get nat type error")
-	//	return
-	//}
-	localNatType := stun.NATRestricted
-	//write password
-	if _, err = localToolConn.Write([]byte(md5Password)); err != nil {
+	var remoteAddr1, remoteAddr2, remoteAddr3 string
+	for {
+		buf := make([]byte, 1024)
+		if n, addr, er := localConn.ReadFromUDP(buf); er != nil {
+			err = er
+			return
+		} else {
+			rAddr2, _ := getNextAddr(rAddr, 1)
+			rAddr3, _ := getNextAddr(rAddr, 2)
+			switch addr.String() {
+			case rAddr:
+				remoteAddr1 = string(buf[:n])
+			case rAddr2:
+				remoteAddr2 = string(buf[:n])
+			case rAddr3:
+				remoteAddr3 = string(buf[:n])
+			}
+		}
+		if remoteAddr1 != "" && remoteAddr2 != "" && remoteAddr3 != "" {
+			break
+		}
+	}
+	if remoteAddress, err = sendP2PTestMsg(localConn, remoteAddr1, remoteAddr2, remoteAddr3); err != nil {
 		return
 	}
-	//write role
-	if _, err = localToolConn.Write([]byte(role)); err != nil {
-		return
-	}
-	if err = binary.Write(localToolConn, binary.LittleEndian, int32(localNatType)); err != nil {
-		return
-	}
-	//get another type address and nat type from server
-	var remoteAddr []byte
-	var remoteNatType int32
-	if remoteAddr, err = localToolConn.GetShortLenContent(); err != nil {
-		return
-	}
-	if err = binary.Read(localToolConn, binary.LittleEndian, &remoteNatType); err != nil {
-		return
-	}
-	localConn.Close()
-	//logs.Trace("remote nat type %d,local nat type %s", remoteNatType, localNatType)
-	if remoteAddress, err = sendP2PTestMsg(string(remoteAddr), tmpConn.LocalAddr().String()); err != nil {
-		return
-	}
-	c, err = newUdpConnByAddr(tmpConn.LocalAddr().String())
+	c, err = newUdpConnByAddr(localAddr)
 	return
 }
 
-func handleP2P(natType1, natType2 int, addr1, addr2 string, role string) (string, error) {
-	switch natType1 {
-	case int(stun.NATFull):
-		return sendP2PTestMsg(addr2, addr1)
-	case int(stun.NATRestricted):
-		switch natType2 {
-		case int(stun.NATFull), int(stun.NATRestricted), int(stun.NATPortRestricted), int(stun.NATSymetric):
-			return sendP2PTestMsg(addr2, addr1)
-		}
-	case int(stun.NATPortRestricted):
-		switch natType2 {
-		case int(stun.NATFull), int(stun.NATRestricted), int(stun.NATPortRestricted):
-			return sendP2PTestMsg(addr2, addr1)
-		}
-	case int(stun.NATSymetric):
-		switch natType2 {
-		case int(stun.NATFull), int(stun.NATRestricted):
-			return sendP2PTestMsg(addr2, addr1)
-		}
-	}
-	return "", errors.New("not support p2p")
-}
-
-func sendP2PTestMsg(remoteAddr string, localAddr string) (string, error) {
-	remoteUdpAddr, err := net.ResolveUDPAddr("udp", remoteAddr)
-	if err != nil {
-		return "", err
-	}
-	localConn, err := newUdpConnByAddr(localAddr)
-	if err != nil {
-		return "", err
-	}
+func sendP2PTestMsg(localConn *net.UDPConn, remoteAddr1, remoteAddr2, remoteAddr3 string) (string, error) {
+	logs.Trace(remoteAddr3, remoteAddr2, remoteAddr1)
 	defer localConn.Close()
-	ticker := time.NewTicker(time.Millisecond * 500)
-	go func(ticker *time.Ticker) {
+	isClose := false
+	defer func() { isClose = true }()
+	interval, err := getAddrInterval(remoteAddr1, remoteAddr2, remoteAddr3)
+	if err != nil {
+		return "", err
+	}
+	go func() {
+		addr, err := getNextAddr(remoteAddr3, interval)
+		if err != nil {
+			return
+		}
+		remoteUdpAddr, err := net.ResolveUDPAddr("udp", addr)
+		if err != nil {
+			return
+		}
+		logs.Trace("try send test packet to target %s", addr)
+		ticker := time.NewTicker(time.Millisecond * 500)
 		for {
 			select {
 			case <-ticker.C:
-				logs.Trace("try send test packet to target %s", remoteAddr)
+				if isClose {
+					return
+				}
 				if _, err := localConn.WriteTo([]byte(common.WORK_P2P_CONNECT), remoteUdpAddr); err != nil {
 					return
 				}
 			}
 		}
-	}(ticker)
+	}()
+	if interval != 0 {
+		ip := common.GetIpByAddr(remoteAddr2)
+		go func() {
+			ports := getRandomPortArr(common.GetPortByAddr(remoteAddr3), common.GetPortByAddr(remoteAddr3)+interval*50)
+			for i := 0; i <= 50; i ++ {
+				go func(port int) {
+					trueAddress := ip + ":" + strconv.Itoa(port)
+					logs.Trace("try send test packet to target %s", trueAddress)
+					remoteUdpAddr, err := net.ResolveUDPAddr("udp", trueAddress)
+					if err != nil {
+						return
+					}
+					ticker := time.NewTicker(time.Second * 2)
+					for {
+						select {
+						case <-ticker.C:
+							if isClose {
+								return
+							}
+							if _, err := localConn.WriteTo([]byte(common.WORK_P2P_CONNECT), remoteUdpAddr); err != nil {
+								return
+							}
+						}
+					}
+				}(ports[i])
+				time.Sleep(time.Millisecond * 10)
+			}
+		}()
+
+	}
+
 	buf := make([]byte, 10)
 	for {
-		localConn.SetReadDeadline(time.Now().Add(time.Second * 30))
+		localConn.SetReadDeadline(time.Now().Add(time.Second * 10))
 		n, addr, err := localConn.ReadFromUDP(buf)
 		localConn.SetReadDeadline(time.Time{})
 		if err != nil {
@@ -397,7 +428,7 @@ func sendP2PTestMsg(remoteAddr string, localAddr string) (string, error) {
 		case common.WORK_P2P_CONNECT:
 			go func() {
 				for i := 20; i > 0; i-- {
-					logs.Trace("try send receive success packet to target %s", remoteAddr)
+					logs.Trace("try send receive success packet to target %s", addr.String())
 					if _, err = localConn.WriteTo([]byte(common.WORK_P2P_SUCCESS), addr); err != nil {
 						return
 					}
@@ -407,9 +438,7 @@ func sendP2PTestMsg(remoteAddr string, localAddr string) (string, error) {
 		default:
 			continue
 		}
-		ticker.Stop()
 	}
-	ticker.Stop()
 	return "", errors.New("connect to the target failed, maybe the nat type is not support p2p")
 }
 
@@ -424,3 +453,66 @@ func newUdpConnByAddr(addr string) (*net.UDPConn, error) {
 	}
 	return udpConn, nil
 }
+
+func getNextAddr(addr string, n int) (string, error) {
+	arr := strings.Split(addr, ":")
+	if len(arr) != 2 {
+		return "", errors.New(fmt.Sprintf("the format of %s incorrect", addr))
+	}
+	if p, err := strconv.Atoi(arr[1]); err != nil {
+		return "", err
+	} else {
+		return arr[0] + ":" + strconv.Itoa(p+n), nil
+	}
+}
+
+func getAddrInterval(addr1, addr2, addr3 string) (int, error) {
+	arr1 := strings.Split(addr1, ":")
+	if len(arr1) != 2 {
+		return 0, errors.New(fmt.Sprintf("the format of %s incorrect", addr1))
+	}
+	arr2 := strings.Split(addr2, ":")
+	if len(arr2) != 2 {
+		return 0, errors.New(fmt.Sprintf("the format of %s incorrect", addr2))
+	}
+	arr3 := strings.Split(addr3, ":")
+	if len(arr3) != 2 {
+		return 0, errors.New(fmt.Sprintf("the format of %s incorrect", addr3))
+	}
+	p1, err := strconv.Atoi(arr1[1])
+	if err != nil {
+		return 0, err
+	}
+	p2, err := strconv.Atoi(arr2[1])
+	if err != nil {
+		return 0, err
+	}
+	p3, err := strconv.Atoi(arr3[1])
+	if err != nil {
+		return 0, err
+	}
+	interVal := int(math.Floor(math.Min(math.Abs(float64(p3-p2)), math.Abs(float64(p2-p1)))))
+	if p3-p1 < 0 {
+		return -interVal, nil
+	}
+	return interVal, nil
+}
+
+func getRandomPortArr(min, max int) []int {
+	if min > max {
+		min, max = max, min
+	}
+	addrAddr := make([]int, max-min+1)
+	for i := min; i <= max; i++ {
+		addrAddr[max-i] = i
+	}
+	rand.Seed(time.Now().UnixNano())
+	var r, temp int
+	for i := max - min; i > 0; i-- {
+		r = rand.Int() % i
+		temp = addrAddr[i]
+		addrAddr[i] = addrAddr[r]
+		addrAddr[r] = temp
+	}
+	return addrAddr
+}
diff --git a/client/local.go b/client/local.go
index 480e0a9..b9afe5c 100644
--- a/client/local.go
+++ b/client/local.go
@@ -7,22 +7,36 @@ import (
 	"github.com/cnlh/nps/lib/crypt"
 	"github.com/cnlh/nps/lib/file"
 	"github.com/cnlh/nps/lib/mux"
+	"github.com/cnlh/nps/server/proxy"
 	"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
 	"github.com/cnlh/nps/vender/github.com/xtaci/kcp"
 	"net"
 	"net/http"
-	"sync"
 )
 
 var (
-	LocalServer []*net.TCPListener
-	udpConn     net.Conn
-	muxSession  *mux.Mux
-	fileServer  []*http.Server
-	lock        sync.Mutex
-	hasP2PTry   bool
+	LocalServer  []*net.TCPListener
+	udpConn      net.Conn
+	muxSession   *mux.Mux
+	fileServer   []*http.Server
+	p2pNetBridge *p2pBridge
 )
 
+type p2pBridge struct {
+}
+
+func (p2pBridge *p2pBridge) SendLinkInfo(clientId int, link *conn.Link, t *file.Tunnel) (target net.Conn, err error) {
+	nowConn, err := muxSession.NewConn()
+	if err != nil {
+		udpConn = nil
+		return nil, err
+	}
+	if _, err := conn.NewConn(nowConn).SendInfo(link, ""); err != nil {
+		return nil, err
+	}
+	return nowConn, nil
+}
+
 func CloseLocalServer() {
 	for _, v := range LocalServer {
 		v.Close()
@@ -48,20 +62,58 @@ func startLocalFileServer(config *config.CommonConfig, t *file.Tunnel, vkey stri
 }
 
 func StartLocalServer(l *config.LocalServer, config *config.CommonConfig) error {
-	listener, err := net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP("0.0.0.0"), l.Port, ""})
+	tmpConn, err := common.GetLocalUdpAddr()
 	if err != nil {
-		logs.Error("local listener startup failed port %d, error %s", l.Port, err.Error())
 		return err
 	}
-	LocalServer = append(LocalServer, listener)
-	logs.Info("successful start-up of local monitoring, port", l.Port)
-	conn.Accept(listener, func(c net.Conn) {
-		if l.Type == "secret" {
-			handleSecret(c, config, l)
-		} else {
-			handleP2PVisitor(c, config, l)
+	for i := 0; i < 10; i++ {
+		logs.Notice("try to connect to the server", i+1)
+		newUdpConn(tmpConn.LocalAddr().String(), config, l)
+		if udpConn != nil {
+			break
 		}
-	})
+	}
+	task := &file.Tunnel{
+		Port:     l.Port,
+		ServerIp: "0.0.0.0",
+		Status:   true,
+		Client: &file.Client{
+			Cnf: &file.Config{
+				U:        "",
+				P:        "",
+				Compress: config.Client.Cnf.Compress,
+			},
+			Status:    true,
+			RateLimit: 0,
+			Flow:      &file.Flow{},
+		},
+		Flow:   &file.Flow{},
+		Target: &file.Target{},
+	}
+	switch l.Type {
+	case "p2ps":
+		logs.Info("successful start-up of local socks5 monitoring, port", l.Port)
+		return proxy.NewSock5ModeServer(p2pNetBridge, task).Start()
+	case "p2pt":
+		logs.Info("successful start-up of local tcp trans monitoring, port", l.Port)
+		return proxy.NewTunnelModeServer(proxy.HandleTrans, p2pNetBridge, task).Start()
+	case "p2p", "secret":
+		listener, err := net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP("0.0.0.0"), l.Port, ""})
+		if err != nil {
+			logs.Error("local listener startup failed port %d, error %s", l.Port, err.Error())
+			return err
+		}
+		LocalServer = append(LocalServer, listener)
+		logs.Info("successful start-up of local tcp monitoring, port", l.Port)
+		conn.Accept(listener, func(c net.Conn) {
+			logs.Trace("new %s connection", l.Type)
+			if l.Type == "secret" {
+				handleSecret(c, config, l)
+			} else if l.Type == "p2p" {
+				handleP2PVisitor(c, config, l)
+			}
+		})
+	}
 	return nil
 }
 
@@ -79,41 +131,22 @@ func handleSecret(localTcpConn net.Conn, config *config.CommonConfig, l *config.
 }
 
 func handleP2PVisitor(localTcpConn net.Conn, config *config.CommonConfig, l *config.LocalServer) {
-restart:
-	lock.Lock()
 	if udpConn == nil {
-		if !hasP2PTry {
-			hasP2PTry = true
-			newUdpConn(config, l)
-		}
-		if udpConn == nil {
-			lock.Unlock()
-			logs.Notice("new conn, P2P can not penetrate successfully, traffic will be transferred through the server")
-			handleSecret(localTcpConn, config, l)
-			return
-		} else {
-			muxSession = mux.NewMux(udpConn, "kcp")
-		}
+		logs.Notice("new conn, P2P can not penetrate successfully, traffic will be transferred through the server")
+		handleSecret(localTcpConn, config, l)
 	}
-	lock.Unlock()
 	logs.Trace("start trying to connect with the server")
-	nowConn, err := muxSession.NewConn()
-	if err != nil {
-		udpConn = nil
-		logs.Error(err, "reconnect......")
-		goto restart
-		return
-	}
 	//TODO just support compress now because there is not tls file in client packages
 	link := conn.NewLink(common.CONN_TCP, l.Target, false, config.Client.Cnf.Compress, localTcpConn.LocalAddr().String(), false)
-	if _, err := conn.NewConn(nowConn).SendInfo(link, ""); err != nil {
+	if target, err := p2pNetBridge.SendLinkInfo(0, link, nil); err != nil {
 		logs.Error(err)
 		return
+	} else {
+		conn.CopyWaitGroup(target, localTcpConn, false, config.Client.Cnf.Compress, nil, nil, false, nil)
 	}
-	conn.CopyWaitGroup(nowConn, localTcpConn, false, config.Client.Cnf.Compress, nil, nil, false, nil)
 }
 
-func newUdpConn(config *config.CommonConfig, l *config.LocalServer) {
+func newUdpConn(localAddr string, config *config.CommonConfig, l *config.LocalServer) {
 	remoteConn, err := NewConn(config.Tp, config.VKey, config.Server, common.WORK_P2P, config.ProxyUrl)
 	if err != nil {
 		logs.Error("Local connection server failed ", err.Error())
@@ -131,7 +164,7 @@ func newUdpConn(config *config.CommonConfig, l *config.LocalServer) {
 	}
 	var localConn net.PacketConn
 	var remoteAddress string
-	if remoteAddress, localConn, err = handleP2PUdp(string(rAddr), crypt.Md5(l.Password), common.WORK_P2P_VISITOR); err != nil {
+	if remoteAddress, localConn, err = handleP2PUdp(localAddr, string(rAddr), crypt.Md5(l.Password), common.WORK_P2P_VISITOR); err != nil {
 		logs.Error(err)
 		return
 	}
@@ -143,4 +176,6 @@ func newUdpConn(config *config.CommonConfig, l *config.LocalServer) {
 	logs.Trace("successful create a connection with server", remoteAddress)
 	conn.SetUdpSession(udpTunnel)
 	udpConn = udpTunnel
+	muxSession = mux.NewMux(udpConn, "kcp")
+	p2pNetBridge = &p2pBridge{}
 }
diff --git a/cmd/npc/npc.go b/cmd/npc/npc.go
index ffadb9d..f2c7b7c 100644
--- a/cmd/npc/npc.go
+++ b/cmd/npc/npc.go
@@ -60,7 +60,7 @@ func main() {
 	if *logType == "stdout" {
 		logs.SetLogger(logs.AdapterConsole, `{"level":`+*logLevel+`,"color":true}`)
 	} else {
-		logs.SetLogger(logs.AdapterFile, `{"level":`+*logLevel+`,"filename":"`+*logPath+`","daily":false,"color":true}`)
+		logs.SetLogger(logs.AdapterFile, `{"level":`+*logLevel+`,"filename":"`+*logPath+`","daily":false,"maxlines":100000,"color":true}`)
 	}
 	//p2p or secret command
 	if *password != "" {
diff --git a/cmd/nps/nps.go b/cmd/nps/nps.go
index e9b4d37..2cb9a28 100644
--- a/cmd/nps/nps.go
+++ b/cmd/nps/nps.go
@@ -50,7 +50,7 @@ func main() {
 	if *logType == "stdout" {
 		logs.SetLogger(logs.AdapterConsole, `{"level":`+level+`,"color":true}`)
 	} else {
-		logs.SetLogger(logs.AdapterFile, `{"level":`+level+`,"filename":"`+beego.AppConfig.String("log_path")+`","daily":false,"color":true}`)
+		logs.SetLogger(logs.AdapterFile, `{"level":`+level+`,"filename":"`+beego.AppConfig.String("log_path")+`","daily":false,"maxlines":100000,"color":true}`)
 	}
 	task := &file.Tunnel{
 		Mode: "webServer",
diff --git a/lib/common/util.go b/lib/common/util.go
index c0e101c..ce4381d 100755
--- a/lib/common/util.go
+++ b/lib/common/util.go
@@ -163,6 +163,13 @@ func TestUdpPort(port int) bool {
 //Length prevents sticking
 //# Characters are used to separate data
 func BinaryWrite(raw *bytes.Buffer, v ...string) {
+	b := GetWriteStr(v...)
+	binary.Write(raw, binary.LittleEndian, int32(len(b)))
+	binary.Write(raw, binary.LittleEndian, b)
+}
+
+// get seq str
+func GetWriteStr(v ...string) []byte {
 	buffer := new(bytes.Buffer)
 	var l int32
 	for _, v := range v {
@@ -170,8 +177,7 @@ func BinaryWrite(raw *bytes.Buffer, v ...string) {
 		binary.Write(buffer, binary.LittleEndian, []byte(v))
 		binary.Write(buffer, binary.LittleEndian, []byte(CONN_DATA_SEQ))
 	}
-	binary.Write(raw, binary.LittleEndian, l)
-	binary.Write(raw, binary.LittleEndian, buffer.Bytes())
+	return buffer.Bytes()
 }
 
 //inArray str interface
@@ -244,6 +250,19 @@ func GetIpByAddr(addr string) string {
 	return arr[0]
 }
 
+//get port from the complete address
+func GetPortByAddr(addr string) int {
+	arr := strings.Split(addr, ":")
+	if len(arr) < 2 {
+		return 0
+	}
+	p, err := strconv.Atoi(arr[1])
+	if err != nil {
+		return 0
+	}
+	return p
+}
+
 func CopyBuffer(dst io.Writer, src io.Reader) (written int64, err error) {
 	buf := pool.GetBufPoolCopy()
 	defer pool.PutBufPoolCopy(buf)
diff --git a/lib/install/install.go b/lib/install/install.go
index 323d563..5b2a515 100644
--- a/lib/install/install.go
+++ b/lib/install/install.go
@@ -13,6 +13,9 @@ import (
 
 func InstallNps() {
 	path := common.GetInstallPath()
+	if common.FileExists(path) {
+		log.Fatalf("the path %s has exist, does not support install", path)
+	}
 	MkidrDirAll(path, "conf", "web/static", "web/views")
 	//复制文件到对应目录
 	if err := CopyDir(filepath.Join(common.GetAppPath(), "web", "views"), filepath.Join(path, "web", "views")); err != nil {
diff --git a/lib/version/version.go b/lib/version/version.go
index a8e21dd..6a7d0d5 100644
--- a/lib/version/version.go
+++ b/lib/version/version.go
@@ -1,6 +1,6 @@
 package version
 
-const VERSION = "0.22.5"
+const VERSION = "0.23.0"
 
 // Compulsory minimum version, Minimum downward compatibility to this version
 func GetVersion() string {
diff --git a/server/proxy/base.go b/server/proxy/base.go
index ba7568f..2509dbd 100644
--- a/server/proxy/base.go
+++ b/server/proxy/base.go
@@ -17,10 +17,14 @@ type Service interface {
 	Close() error
 }
 
+type NetBridge interface {
+	SendLinkInfo(clientId int, link *conn.Link, t *file.Tunnel) (target net.Conn, err error)
+}
+
 //BaseServer struct
 type BaseServer struct {
 	id           int
-	bridge       *bridge.Bridge
+	bridge       NetBridge
 	task         *file.Tunnel
 	errorContent []byte
 	sync.Mutex
diff --git a/server/proxy/http.go b/server/proxy/http.go
index f8e0a24..84026ff 100644
--- a/server/proxy/http.go
+++ b/server/proxy/http.go
@@ -147,7 +147,7 @@ func (s *httpServer) httpHandle(c *conn.Conn, r *http.Request) {
 				logs.Warn(err.Error())
 				break
 			}
-			lk = conn.NewLink(common.CONN_TCP, targetAddr, host.Client.Cnf.Crypt, host.Client.Cnf.Compress, r.RemoteAddr, host.Target.LocalProxy)
+			lk = conn.NewLink("http", targetAddr, host.Client.Cnf.Crypt, host.Client.Cnf.Compress, r.RemoteAddr, host.Target.LocalProxy)
 			if target, err = s.bridge.SendLinkInfo(host.Client.Id, lk, nil); err != nil {
 				logs.Notice("connect to target %s error %s", lk.Host, err)
 				break
diff --git a/server/proxy/https.go b/server/proxy/https.go
index 7fc3ee9..9ccce29 100644
--- a/server/proxy/https.go
+++ b/server/proxy/https.go
@@ -1,7 +1,6 @@
 package proxy
 
 import (
-	"github.com/cnlh/nps/bridge"
 	"github.com/cnlh/nps/lib/cache"
 	"github.com/cnlh/nps/lib/common"
 	"github.com/cnlh/nps/lib/conn"
@@ -22,7 +21,7 @@ type HttpsServer struct {
 	httpsListenerMap sync.Map
 }
 
-func NewHttpsServer(l net.Listener, bridge *bridge.Bridge, useCache bool, cacheLen int) *HttpsServer {
+func NewHttpsServer(l net.Listener, bridge NetBridge, useCache bool, cacheLen int) *HttpsServer {
 	https := &HttpsServer{listener: l}
 	https.bridge = bridge
 	https.useCache = useCache
diff --git a/server/proxy/p2p.go b/server/proxy/p2p.go
index e553ffb..44cdea3 100644
--- a/server/proxy/p2p.go
+++ b/server/proxy/p2p.go
@@ -1,28 +1,24 @@
 package proxy
 
 import (
-	"encoding/binary"
 	"github.com/cnlh/nps/lib/common"
-	"github.com/cnlh/nps/lib/conn"
+	"github.com/cnlh/nps/lib/pool"
 	"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
 	"net"
-	"strconv"
+	"strings"
 	"time"
 )
 
 type P2PServer struct {
 	BaseServer
-	p2pPort int
-	p2p     map[string]*p2p
+	p2pPort  int
+	p2p      map[string]*p2p
+	listener *net.UDPConn
 }
 
 type p2p struct {
-	provider        *conn.Conn
-	visitor         *conn.Conn
-	visitorAddr     string
-	providerAddr    string
-	providerNatType int32
-	visitorNatType  int32
+	visitorAddr  *net.UDPAddr
+	providerAddr *net.UDPAddr
 }
 
 func NewP2PServer(p2pPort int) *P2PServer {
@@ -33,62 +29,52 @@ func NewP2PServer(p2pPort int) *P2PServer {
 }
 
 func (s *P2PServer) Start() error {
-	return conn.NewKcpListenerAndProcess(":"+strconv.Itoa(s.p2pPort), func(c net.Conn) {
-		s.p2pProcess(conn.NewConn(c))
-	})
+	logs.Info("start p2p server port", s.p2pPort)
+	var err error
+	s.listener, err = net.ListenUDP("udp", &net.UDPAddr{net.ParseIP("0.0.0.0"), s.p2pPort, ""})
+	if err != nil {
+		return err
+	}
+	for {
+		buf := pool.BufPoolUdp.Get().([]byte)
+		n, addr, err := s.listener.ReadFromUDP(buf)
+		if err != nil {
+			if strings.Contains(err.Error(), "use of closed network connection") {
+				break
+			}
+			continue
+		}
+		go s.handleP2P(addr, string(buf[:n]))
+	}
+	return nil
 }
 
-func (s *P2PServer) p2pProcess(c *conn.Conn) {
+func (s *P2PServer) handleP2P(addr *net.UDPAddr, str string) {
 	var (
-		f       string
-		b       []byte
-		err     error
-		v       *p2p
-		ok      bool
-		natType int32
+		v  *p2p
+		ok bool
 	)
-	if b, err = c.GetShortContent(32); err != nil {
+	arr := strings.Split(str, common.CONN_DATA_SEQ)
+	if len(arr) < 2 {
 		return
 	}
-	//get role
-	if f, err = c.ReadFlag(); err != nil {
-		return
-	}
-	//get nat type
-	if err := binary.Read(c, binary.LittleEndian, &natType); err != nil {
-		return
-	}
-	if v, ok = s.p2p[string(b)]; !ok {
+	if v, ok = s.p2p[arr[0]]; !ok {
 		v = new(p2p)
-		s.p2p[string(b)] = v
+		s.p2p[arr[0]] = v
 	}
-	logs.Trace("new p2p connection ,role %s , password %s, nat type %s ,local address %s", f, string(b), strconv.Itoa(int(natType)), c.RemoteAddr().String())
-	//存储
-	if f == common.WORK_P2P_VISITOR {
-		v.visitorAddr = c.Conn.RemoteAddr().String()
-		v.visitorNatType = natType
-		v.visitor = c
+	logs.Trace("new p2p connection ,role %s , password %s ,local address %s", arr[1], arr[0], addr.String())
+	if arr[1] == common.WORK_P2P_VISITOR {
+		v.visitorAddr = addr
 		for i := 20; i > 0; i-- {
-			if v.provider != nil {
-				v.provider.WriteLenContent([]byte(v.visitorAddr))
-				binary.Write(v.provider, binary.LittleEndian, v.visitorNatType)
+			if v.providerAddr != nil {
+				s.listener.WriteTo([]byte(v.providerAddr.String()), v.visitorAddr)
+				s.listener.WriteTo([]byte(v.visitorAddr.String()), v.providerAddr)
 				break
 			}
 			time.Sleep(time.Second)
 		}
-		v.provider = nil
+		delete(s.p2p, arr[0])
 	} else {
-		v.providerAddr = c.Conn.RemoteAddr().String()
-		v.providerNatType = natType
-		v.provider = c
-		for i := 20; i > 0; i-- {
-			if v.visitor != nil {
-				v.visitor.WriteLenContent([]byte(v.providerAddr))
-				binary.Write(v.visitor, binary.LittleEndian, v.providerNatType)
-				break
-			}
-			time.Sleep(time.Second)
-		}
-		v.visitor = nil
+		v.providerAddr = addr
 	}
 }
diff --git a/server/proxy/socks5.go b/server/proxy/socks5.go
index 1ab20a9..5af021b 100755
--- a/server/proxy/socks5.go
+++ b/server/proxy/socks5.go
@@ -3,7 +3,6 @@ package proxy
 import (
 	"encoding/binary"
 	"errors"
-	"github.com/cnlh/nps/bridge"
 	"github.com/cnlh/nps/lib/common"
 	"github.com/cnlh/nps/lib/conn"
 	"github.com/cnlh/nps/lib/file"
@@ -264,7 +263,7 @@ func (s *Sock5ModeServer) Start() error {
 }
 
 //new
-func NewSock5ModeServer(bridge *bridge.Bridge, task *file.Tunnel) *Sock5ModeServer {
+func NewSock5ModeServer(bridge NetBridge, task *file.Tunnel) *Sock5ModeServer {
 	s := new(Sock5ModeServer)
 	s.bridge = bridge
 	s.task = task
@@ -274,4 +273,4 @@ func NewSock5ModeServer(bridge *bridge.Bridge, task *file.Tunnel) *Sock5ModeServ
 //close
 func (s *Sock5ModeServer) Close() error {
 	return s.listener.Close()
-}
+}
\ No newline at end of file
diff --git a/server/proxy/tcp.go b/server/proxy/tcp.go
index 89f4edd..0cda27a 100755
--- a/server/proxy/tcp.go
+++ b/server/proxy/tcp.go
@@ -13,6 +13,7 @@ import (
 	"net/http"
 	"path/filepath"
 	"strconv"
+	"syscall"
 )
 
 type TunnelModeServer struct {
@@ -22,7 +23,7 @@ type TunnelModeServer struct {
 }
 
 //tcp|http|host
-func NewTunnelModeServer(process process, bridge *bridge.Bridge, task *file.Tunnel) *TunnelModeServer {
+func NewTunnelModeServer(process process, bridge NetBridge, task *file.Tunnel) *TunnelModeServer {
 	s := new(TunnelModeServer)
 	s.bridge = bridge
 	s.process = process
@@ -114,3 +115,35 @@ func ProcessHttp(c *conn.Conn, s *TunnelModeServer) error {
 	}
 	return s.DealClient(c, s.task.Client, addr, rb, common.CONN_TCP, nil, s.task.Flow, s.task.Target.LocalProxy)
 }
+
+func HandleTrans(c *conn.Conn, s *TunnelModeServer) error {
+	if addr, err := getAddress(c.Conn); err != nil {
+		return err
+	} else {
+		return s.DealClient(c, s.task.Client, addr, nil, common.CONN_TCP, nil, s.task.Flow, s.task.Target.LocalProxy)
+	}
+}
+
+const SO_ORIGINAL_DST = 80
+
+func getAddress(conn net.Conn) (string, error) {
+	sysrawconn, f := conn.(syscall.Conn)
+	if !f {
+		return "", nil
+	}
+	rawConn, err := sysrawconn.SyscallConn()
+	if err != nil {
+		return "", nil
+	}
+	var ip string
+	var port uint16
+	err = rawConn.Control(func(fd uintptr) {
+		addr, err := syscall.GetsockoptIPv6Mreq(int(fd), syscall.IPPROTO_IP, SO_ORIGINAL_DST)
+		if err != nil {
+			return
+		}
+		ip = net.IP(addr.Multiaddr[4:8]).String()
+		port = uint16(addr.Multiaddr[2])<<8 + uint16(addr.Multiaddr[3])
+	})
+	return ip + ":" + strconv.Itoa(int(port)), nil
+}
diff --git a/server/server.go b/server/server.go
index d5d0f63..31e6f18 100644
--- a/server/server.go
+++ b/server/server.go
@@ -90,8 +90,9 @@ func StartNewServer(bridgePort int, cnf *file.Tunnel, bridgeType string) {
 		}
 	}()
 	if p, err := beego.AppConfig.Int("p2p_port"); err == nil {
-		logs.Info("start p2p server port", p)
 		go proxy.NewP2PServer(p).Start()
+		go proxy.NewP2PServer(p + 1).Start()
+		go proxy.NewP2PServer(p + 2).Start()
 	}
 	go DealBridgeTask()
 	go dealClientFlow()
@@ -125,6 +126,8 @@ func NewMode(Bridge *bridge.Bridge, c *file.Tunnel) proxy.Service {
 		service = proxy.NewSock5ModeServer(Bridge, c)
 	case "httpProxy":
 		service = proxy.NewTunnelModeServer(proxy.ProcessHttp, Bridge, c)
+	case "tcpTrans":
+		service = proxy.NewTunnelModeServer(proxy.HandleTrans, Bridge, c)
 	case "udp":
 		service = proxy.NewUdpModeServer(Bridge, c)
 	case "webServer":
diff --git a/web/views/index/list.html b/web/views/index/list.html
index 90d6742..5537f67 100755
--- a/web/views/index/list.html
+++ b/web/views/index/list.html
@@ -70,7 +70,11 @@
                     + '<b langtag="info-web-auth-username">basic权限认证用户名</b>:' + row.Client.Cnf.U + `&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp`
                     + '<b langtag="info-web-auth-password">basic权限认证密码</b>:' + row.Client.Cnf.P + `&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp`
             if (row.Mode == "p2p") {
-                return tmp + "<br/><br>" + '<b langtag="info-command">访问端命令</b>:' + "<code>./npc{{.win}} -server={{.ip}}:{{.p}} -vkey=" + row.Client.VerifyKey + " -type=" +{{.bridgeType}} +" -password=" + row.Password + " -target=" + row.Target.TargetStr + "</code>"
+                return tmp + "<br/><br>"
+                        + '<b langtag="info-command">访问端命令(tcp)</b>:' + "<code>./npc{{.win}} -server={{.ip}}:{{.p}} -vkey=" + row.Client.VerifyKey + " -type=" +{{.bridgeType}} +" -password=" + row.Password + " -target=" + row.Target.TargetStr + "</code>" + "<br/><br>"
+                        + '<b langtag="info-command">访问端命令(socks5)</b>:' + "<code>./npc{{.win}} -server={{.ip}}:{{.p}} -vkey=" + row.Client.VerifyKey + " -type=" +{{.bridgeType}} +" -password=" + row.Password + " -local_type=p2ps" + "</code>" + "<br/><br>"
+                        + '<b langtag="info-command">访问端命令(透明代理)</b>:' + "<code>./npc{{.win}} -server={{.ip}}:{{.p}} -vkey=" + row.Client.VerifyKey + " -type=" +{{.bridgeType}} +" -password=" + row.Password + " -local_type=p2pt" + "</code>"
+
             }
             if (row.Mode = "secret") {
                 return tmp + "<br/><br>" + '<b langtag="info-command">访问端命令</b>:' + "<code>./npc{{.win}} -server={{.ip}}:{{.p}} -vkey=" + row.Client.VerifyKey + " -type=" +{{.bridgeType}} +" -password=" + row.Password + " -local_type=secret" + "</code>"