udp轉(zhuǎn)tcp再轉(zhuǎn)udp工具

相關文章: http://www.reibang.com/p/44eded155258
前面分享了一個udp端口轉(zhuǎn)發(fā)工具, 但是在實際使用中經(jīng)常會出現(xiàn)發(fā)送出了數(shù)據(jù)但是收不到數(shù)據(jù)的情況(應該是因為運營商的ipv6網(wǎng)絡還不夠完善),為了解決這個問題于是決定在用ipv6傳數(shù)據(jù)部分采用tcp協(xié)議解決.

這兩個工具要配合使用,且只能udp轉(zhuǎn)tcp再轉(zhuǎn)udp,直接上代碼

udp轉(zhuǎn)tcp:

package main

import (
    "errors"
    "fmt"
    "io"
    "log"
    "net"
    "os"
    "strings"
    "time"
)

var (
    maxDTime = 0.0
    timeOut  = time.Second * 60 * 2
)

func main() {
    println("入?yún)⒈O(jiān)聽地址和轉(zhuǎn)發(fā)地址: " + strings.Join(os.Args[1:], " "))
    listenerAddress := ":1701"
    forwardAddress := "127.0.0.1:1701"
    if len(os.Args) == 3 {
        listenerAddress = os.Args[1]
        forwardAddress = os.Args[2]
    }
    log.SetFlags(log.LstdFlags | log.Lshortfile)

    udpForwardBean := Start(listenerAddress, forwardAddress)
    if udpForwardBean != nil {
        for {
            println(udpForwardBean.String())
            println()
            time.Sleep(time.Second * 60)
        }
    }
}

func Start(listenerAddress string, forwardAddress string) *UdpForwardBean {
    message := listenerAddress + "=>" + forwardAddress
    log.Println(message)

    listenerAddr, err := net.ResolveUDPAddr("udp", listenerAddress)
    if err != nil {
        log.Println(err)
        return nil
    }
    network := "udp"
    if listenerAddr.IP.To4() != nil {
        network = "udp4"
    } else if listenerAddr.IP.To16() != nil {
        network = "udp6"
    }
    listenerConn, err := net.ListenUDP(network, listenerAddr)
    if err != nil {
        log.Println(err)
        return nil
    }
    forwardMap := map[string]*ForwardBean{}
    udpForwardBean := &UdpForwardBean{isClosed: false, listenerAddress: listenerAddress,
        forwardAddress: forwardAddress, listenerConn: listenerConn, forwardMap: forwardMap}
    buffer := make([]byte, 1024*64)
    go func() {
        defer listenerConn.Close()
        for {
            n, clientAddr, err := listenerConn.ReadFromUDP(buffer)
            if err != nil {
                if errors.Is(err, net.ErrClosed) {
                    break
                }
                log.Println(err)
                time.Sleep(time.Second)
                continue
            }
            forwardBean := handleClientRequest(clientAddr, listenerConn, forwardAddress, forwardMap)
            if forwardBean != nil {
                data := append([]byte{byte(n / 256), byte(n % 256)}, buffer[:n]...)
                // log.Println("客戶端消息:", n, clientAddr.String())
                forwardBean.bufferedCh <- data
            }
        }
        udpForwardBean.isClosed = true
    }()
    return udpForwardBean
}

func handleClientRequest(clientAddr *net.UDPAddr, listenerConn *net.UDPConn, forwardAddress string, forwardMap map[string]*ForwardBean) *ForwardBean {
    if clientAddr == nil {
        return nil
    }
    clientAddrString := clientAddr.String()
    forwardBean := forwardMap[clientAddrString]
    if forwardBean != nil {
        return forwardBean
    }
    forwardAddr, err := net.ResolveTCPAddr("tcp", forwardAddress)
    if err != nil {
        log.Println(err)
        return nil
    }
    forwardConn, err := net.DialTCP("tcp", nil, forwardAddr)
    if err != nil {
        log.Println(err)
        return nil
    }
    bufferedCh := make(chan []byte, 50)
    infoStr := clientAddrString + "=>" + forwardAddress + "=>" + forwardConn.LocalAddr().String() + "=>" + forwardConn.RemoteAddr().String()
    log.Println("添加U2T轉(zhuǎn)發(fā):", infoStr)
    lengthBuffer := make([]byte, 2)
    go func() {
        defer forwardConn.Close()
        startTime := time.Now()
        forwardSuccess := false
        for {
            forwardConn.SetReadDeadline(time.Now().Add(timeOut))
            n, err := io.ReadFull(forwardConn, lengthBuffer)
            if err != nil || n != 2 {
                log.Println(n, err)
                break
            }
            length := int(lengthBuffer[0])*256 + int(lengthBuffer[1])
            data := make([]byte, length)
            n, err = io.ReadFull(forwardConn, data)
            if err != nil || n != length {
                log.Println(n, length, err)
                break
            }
            dTime := time.Since(startTime).Seconds()
            startTime = time.Now()
            if dTime > maxDTime {
                maxDTime = dTime
            }
            if !forwardSuccess {
                forwardSuccess = true
                log.Println("U2T轉(zhuǎn)發(fā)成功:", n, forwardConn.RemoteAddr().String()+"=>"+clientAddrString)
            }
            // log.Println("服務端消息:", n, forwardConn.RemoteAddr().String()+"=>"+clientAddrString)
            listenerConn.WriteToUDP(data, clientAddr)
        }
        log.Println("移除U2T:" + infoStr)
        delete(forwardMap, clientAddrString)
        close(bufferedCh)
    }()
    go func() {
        for data := range bufferedCh {
            forwardConn.SetWriteDeadline(time.Now().Add(timeOut))
            forwardConn.Write(data)
        }
    }()
    forwardBean = &ForwardBean{bufferedCh, forwardConn}
    forwardMap[clientAddrString] = forwardBean
    return forwardBean
}

type ForwardBean struct {
    bufferedCh  chan []byte
    forwardConn *net.TCPConn
}

type UdpForwardBean struct {
    isClosed        bool
    listenerAddress string
    forwardAddress  string
    listenerConn    *net.UDPConn
    forwardMap      map[string]*ForwardBean
}

func (bean *UdpForwardBean) String() string {
    var keys []string
    for key, value := range bean.forwardMap {
        keys = append(keys, ",\n"+key+"=>"+value.forwardConn.LocalAddr().String()+"=>"+value.forwardConn.RemoteAddr().String())
    }
    return fmt.Sprintf("U2T轉(zhuǎn)發(fā)中: %s %s %t %.2f %s", bean.listenerAddress, bean.forwardAddress, bean.isClosed, maxDTime, strings.Join(keys, ""))
}

func (bean *UdpForwardBean) Close() {
    bean.listenerConn.Close()
    for _, v := range bean.forwardMap {
        close(v.bufferedCh)
        v.forwardConn.Close()
    }
}

tcp轉(zhuǎn)udp:

package main

import (
    "errors"
    "fmt"
    "io"
    "log"
    "net"
    "os"
    "strings"
    "time"
)

var (
    maxDTime = 0.0
    timeOut  = time.Second * 60 * 2
)

func main() {
    println("入?yún)⒈O(jiān)聽地址和轉(zhuǎn)發(fā)地址: " + strings.Join(os.Args[1:], " "))
    listenerAddress := ":1701"
    forwardAddress := "192.168.1.8:1701"
    if len(os.Args) == 3 {
        listenerAddress = os.Args[1]
        forwardAddress = os.Args[2]
    }
    log.SetFlags(log.LstdFlags | log.Lshortfile)

    tcpForwardBean := Start(listenerAddress, forwardAddress)
    if tcpForwardBean != nil {
        for {
            println(tcpForwardBean.String())
            println()
            time.Sleep(time.Second * 60)
        }
    }
}

func Start(listenerAddress string, forwardAddress string) *TcpForwardBean {
    message := listenerAddress + "=>" + forwardAddress
    log.Println(message)

    listenerAddr, err := net.ResolveTCPAddr("tcp", listenerAddress)
    if err != nil {
        log.Println(err)
        return nil
    }
    network := "tcp"
    if listenerAddr.IP.To4() != nil {
        network = "tcp4"
    } else if listenerAddr.IP.To16() != nil {
        network = "tcp6"
    }
    tcpListener, err := net.ListenTCP(network, listenerAddr)
    if err != nil {
        log.Println(err)
        return nil
    }
    forwardMap := map[*net.TCPConn]*net.UDPConn{}
    tcpForwardBean := &TcpForwardBean{isClosed: false, listenerAddress: listenerAddress,
        forwardAddress: forwardAddress, tcpListener: tcpListener, forwardMap: forwardMap}
    go func() {
        defer tcpListener.Close()
        for {
            client, err := tcpListener.AcceptTCP()
            if err != nil {
                if errors.Is(err, net.ErrClosed) {
                    break
                }
                log.Println(err)
                time.Sleep(time.Second)
                continue
            }
            go forward(client, forwardAddress, forwardMap)
        }
        tcpForwardBean.isClosed = true
    }()
    return tcpForwardBean
}

func forward(client *net.TCPConn, forwardAddress string, forwardMap map[*net.TCPConn]*net.UDPConn) {
    if client == nil {
        return
    }
    // log.Println("客戶端地址:", client.RemoteAddr(), "服務端地址:", client.LocalAddr())
    defer client.Close()
    forwardAddr, err := net.ResolveUDPAddr("udp", forwardAddress)
    if err != nil {
        log.Println(err)
        return
    }
    forwardConn, err := net.DialUDP("udp", nil, forwardAddr)
    if err != nil {
        log.Println(err)
        return
    }
    defer forwardConn.Close()
    forwardMap[client] = forwardConn
    defer delete(forwardMap, client)

    infoStr := client.RemoteAddr().String() + "=>" + client.LocalAddr().String() + "=>" + forwardConn.LocalAddr().String() + "=>" + forwardConn.RemoteAddr().String()
    log.Println("添加T2U轉(zhuǎn)發(fā):", infoStr)

    buffer := make([]byte, 1024*64)
    go func() {
        defer forwardConn.Close()
        defer client.Close()
        startTime := time.Now()
        forwardSuccess := false
        bufferedCh := make(chan []byte, 50)
        go func() {
            for data := range bufferedCh {
                client.SetWriteDeadline(time.Now().Add(timeOut))
                client.Write(data)
            }
        }()
        for {
            forwardConn.SetReadDeadline(time.Now().Add(timeOut))
            n, serverAddr, err := forwardConn.ReadFromUDP(buffer)
            if err != nil {
                if errors.Is(err, net.ErrClosed) {
                    break
                }
                if nerr, ok := err.(net.Error); ok && nerr.Timeout() {
                    break
                }
                log.Println(err)
                time.Sleep(time.Second)
                continue
            }
            if serverAddr.Port != forwardAddr.Port || serverAddr.IP.String() != forwardAddr.IP.String() {
                log.Println("異常消息:", serverAddr.String(), forwardAddr.String())
                continue
            }
            dTime := time.Since(startTime).Seconds()
            startTime = time.Now()
            if dTime > maxDTime {
                maxDTime = dTime
            }
            if !forwardSuccess {
                forwardSuccess = true
                log.Println("T2U轉(zhuǎn)發(fā)成功:", n, serverAddr.String()+"=>"+client.RemoteAddr().String())
            }
            // log.Println("服務端消息:", n, serverAddr.String()+"=>"+client.RemoteAddr().String())
            bufferedCh <- append([]byte{byte(n / 256), byte(n % 256)}, buffer[:n]...)
        }
        close(bufferedCh)
        log.Println("移除T2U:", infoStr)
    }()

    lengthBuffer := make([]byte, 2)
    for {
        client.SetReadDeadline(time.Now().Add(timeOut))
        n, err := io.ReadFull(client, lengthBuffer)
        if err != nil || n != 2 {
            log.Println(n, err)
            break
        }
        length := int(lengthBuffer[0])*256 + int(lengthBuffer[1])
        data := make([]byte, length)
        n, err = io.ReadFull(client, data)
        if err != nil || n != length {
            log.Println(n, length, err)
            break
        }
        // log.Println("服務端消息:", n, client.RemoteAddr().String())
        forwardConn.Write(data)
    }
}

type TcpForwardBean struct {
    isClosed        bool
    listenerAddress string
    forwardAddress  string
    tcpListener     *net.TCPListener
    forwardMap      map[*net.TCPConn]*net.UDPConn
}

func (bean *TcpForwardBean) String() string {
    var keys []string
    for key, value := range bean.forwardMap {
        keys = append(keys, ",\n"+key.RemoteAddr().String()+"=>"+key.LocalAddr().String()+"=>"+value.LocalAddr().String()+"=>"+value.RemoteAddr().String())
    }
    return fmt.Sprintf("T2U轉(zhuǎn)發(fā)中: %s %s %t %.2f %s", bean.listenerAddress, bean.forwardAddress, bean.isClosed, maxDTime, strings.Join(keys, ""))
}

func (bean *TcpForwardBean) Close() {
    bean.tcpListener.Close()
    for k, v := range bean.forwardMap {
        k.Close()
        v.Close()
    }
}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末瓦侮,一起剝皮案震驚了整個濱河市寺鸥,隨后出現(xiàn)的幾起案子猎唁,更是在濱河造成了極大的恐慌,老刑警劉巖蚊俺,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鼓拧,死亡現(xiàn)場離奇詭異掘托,居然都是意外死亡,警方通過查閱死者的電腦和手機逗物,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瑟俭,“玉大人翎卓,你說我怎么就攤上這事“诩模” “怎么了失暴?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長微饥。 經(jīng)常有香客問我逗扒,道長,這世上最難降的妖魔是什么欠橘? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任矩肩,我火速辦了婚禮,結(jié)果婚禮上简软,老公的妹妹穿的比我還像新娘蛮拔。我一直安慰自己,他們只是感情好痹升,可當我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布建炫。 她就那樣靜靜地躺著,像睡著了一般疼蛾。 火紅的嫁衣襯著肌膚如雪肛跌。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天,我揣著相機與錄音衍慎,去河邊找鬼转唉。 笑死,一個胖子當著我的面吹牛稳捆,可吹牛的內(nèi)容都是我干的赠法。 我是一名探鬼主播,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼乔夯,長吁一口氣:“原來是場噩夢啊……” “哼砖织!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起末荐,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤侧纯,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后甲脏,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體眶熬,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年块请,在試婚紗的時候發(fā)現(xiàn)自己被綠了娜氏。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡负乡,死狀恐怖牍白,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情抖棘,我是刑警寧澤茂腥,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站切省,受9級特大地震影響最岗,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜朝捆,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一般渡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧芙盘,春花似錦驯用、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至驮樊,卻和暖如春薇正,著一層夾襖步出監(jiān)牢的瞬間片酝,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工挖腰, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留雕沿,地道東北人。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓猴仑,卻偏偏與公主長得像审轮,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子宁脊,可洞房花燭夜當晚...
    茶點故事閱讀 44,619評論 2 354

推薦閱讀更多精彩內(nèi)容