packagemain

import(
    "encoding/json"
    "flag"
    "fmt"
    "io"
    "log"
    "net"
    "net/http"
    "os"
    "os/signal"
    "runtime"
    "sync"
    "syscall"
    "time"
)
//监听服务地址  默认使用8000端口  服务端监听端口
varrestApiServer=flag.String("restApi","","listenaddrforrestapi")
//监听服务认证  密码
varauth=flag.String("auth","taven123","restApiPassword")
//本地监听器
vargLocalConnnet.Listener
//客户端与服务链接关系--映射
varclientSMapmap[string]net.Conn
//目标服务器和本地服务器  两个服务地址之间使用“-”链接
varforwardInfostring

funcmain(){

    clientSMap=make(map[string]net.Conn)

    //解析传入的参数
    flag.Parse()
        //默认使用8000端口  服务端监听端口
    if*restApiServer==""{
        *restApiServer="0.0.0.0:8000"
    }
       //开启监听服务
    goStartHttpServer(*restApiServer)

    log.Println("restApiServer:",*restApiServer)
    fmt.Println("------------启动成功------------")

    //开启线程同步锁
    varwsync.WaitGroup
    w.Add()

    //开一个并发线程,接收退出信号
       //下面代码  书写混乱  逻辑不清晰   但是实现了
    gofunc(){
        c:=make(chanos.Signal,)
        signal.Notify(c,os.Interrupt,syscall.SIGTERM)
        n:=
        f:=func(){
            <-c
            n++
            ifn>{
                log.Println("forceshutdown")
                os.Exit(-)
            }
            log.Println("receivedsignal,shutdown")
                     //释放相关资源
            closeAllConn()
        }
        f()
        gofunc(){
            for{
                f()
            }
        }()
        //执行完成一次,Done()等同于Add(-1),计数不为0,则阻塞
        w.Done()
    }()

    loop:=func(){
        w.Done()

    }
    loop()
    w.Wait()

    fmt.Println("------------程序执行完成------------")

}

funcStartHttpServer(addrstring){

    http.HandleFunc("/ServerSummary",ServerSummary)
    http.HandleFunc("/ForwardWork",ForwardWork)

    //
    err:=http.ListenAndServe(addr,http.DefaultServeMux)

    iferr!=nil{
        fmt.Println("ListenAndServeerror:",err.Error())
    }

}

funcServerSummary(rwhttp.ResponseWriter,req*http.Request){
    log.Println("ServerSummary")
    obj:=make(map[string]interface{})
    obj["runtime_NumGoroutine"]=runtime.NumGoroutine()
    obj["runtime_GOOS"]=runtime.GOOS
    obj["runtime_GOARCH"]=runtime.GOARCH
    obj["restApi_Addr"]=*restApiServer
    obj["server_Time"]=time.Now()
    obj["clients_Count"]=len(clientSMap)

    varclist[]string
    forcId,_:=rangeclientSMap{
        clist=append(clist,cId)
    }
    obj["clients_List"]=clist
    obj["forwardInfo"]=forwardInfo

    res,err:=json.Marshal(obj)
    iferr!=nil{
        log.Println("jsonmarshal:",err)
        return
    }

    rw.Header().Add("Content-Type","application/json;charset=utf-8")
    _,err=rw.Write(res)
    iferr!=nil{
        log.Println("writeerr:",err)
    }
    return
}

funcForwardWork(rwhttp.ResponseWriter,req*http.Request){
    req.ParseForm()

    obj:=make(map[string]interface{})
    obj["code"]=
    obj["msg"]=""

    paramAuth,hasAuth:=req.Form["auth"]
    if!hasAuth{
        log.Println("requestnoauth")
        obj["code"]=
        obj["msg"]="requestnoauth"
        responseResult(obj,rw)
        return

    }

    ifparamAuth[]!=*auth{
        log.Println("requestauthfailed")
        obj["code"]=
        obj["msg"]="requestauthfailed"
        responseResult(obj,rw)

        return
    }

    paramStatus,hasStatus:=req.Form["status"]
    if!hasStatus{
        return

    }

    log.Println("param_status:",paramStatus)

    ifparamStatus[]=="1"{
        //启动服务
        paramFromAddr,hasFromAddr:=req.Form["fromAddr"]
        paramToAddr,hasToAddr:=req.Form["toAddr"]
        ifgLocalConn!=nil{
            gLocalConn.Close()
        }

        ifhasFromAddr&&hasToAddr{
            goforwardPort(paramFromAddr[],paramToAddr[])
        }
    }

    ifparamStatus[]=="0"{
        //关闭服务
        closeAllConn()
        forwardInfo=""
    }

    responseResult(obj,rw)

    return

}

funcresponseResult(datamap[string]interface{},rwhttp.ResponseWriter){
    res,err:=json.Marshal(data)
    iferr!=nil{
        log.Println("jsonmarshal:",err)
        return
    }

    rw.Header().Add("Content-Type","application/json;charset=utf-8")
    _,err=rw.Write(res)
    iferr!=nil{
        log.Println("writeerr:",err)
    }
}

funccloseAllConn(){
    forcId,conn:=rangeclientSMap{
        log.Println("clientMapid:",cId)
        conn.Close()
        delete(clientSMap,cId)
    }

    ifgLocalConn!=nil{
        gLocalConn.Close()
        log.Println("ListenerClose")
    }else{
        gLocalConn=nil
        log.Println("Listenersettonil",gLocalConn)
    }
}
//通读全部代码 发现这里存在未释放资源 targetPort 。准确说 需要先释放sourcePort 资源  再释放targetPort 资源
funcforwardPort(sourcePortstring,targetPortstring){

    fmt.Println("sourcePort:",sourcePort,"targetPort:",targetPort)

    localConn,err:=net.Listen("tcp",sourcePort)

    iferr!=nil{
        fmt.Println(err.Error())
        return
    }

    gLocalConn=localConn

    fmt.Println("服务启动成功,服务地址:",sourcePort)

    forwardInfo=fmt.Sprintf("%s-%s",sourcePort,targetPort)

    for{
        fmt.Println("ReadytoAccept...")
        sourceConn,err:=gLocalConn.Accept()

        iferr!=nil{
            log.Println("servererr:",err.Error())
            break
        }
        //log.Println("client",sc.id,"createsession",sessionId)

        id:=sourceConn.RemoteAddr().String()
        clientSMap[id]=sourceConn

        fmt.Println("conn.RemoteAddr().String():",id)

        //targetPort:="172.16.128.83:22"
        targetConn,err:=net.DialTimeout("tcp",targetPort,*time.Second)

        gofunc(){
            _,err=io.Copy(targetConn,sourceConn)
            iferr!=nil{
                //log.Fatalf("io.Copyfailed:%v",err)
                fmt.Println("io.Copyfailed:",err.Error())
            }
        }()

        gofunc(){
            _,err=io.Copy(sourceConn,targetConn)
            iferr!=nil{
                //log.Fatalf("io.Copyfailed:%v",err)
                fmt.Println("io.Copyfailed:",err.Error())
            }
        }()

    }

    //
    log.Println("forwardPortend.")

}

<wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">

 
 
 
 

forwardPort.go的更多相关文章

  1. appium的几点总结

    原文链接:http://blog.csdn.net/bear_w/article/details/50345283 1. 建立session时常用命令: DesiredCapabilities cap ...

  2. github之git基本命令介绍的简单整理

    git 格式: git [--version] [--exec-path[=<path>]] [--html-path] [--info-path] [-p|--paginate|--no ...

  3. Linux防火墙配置(iptables, firewalld)

    netfilter和底层实现 iptables firealld Linux中的防火墙 RHEL中有几种防火墙共存: iptables firewalld ip6tables ebtables 这些软 ...

  4. 我的第一个GitHub仓库

    GitHub 仓库地址 https://github.com/FBean/test.git GitHub 常用命令 add--Add file contents to the index bisect ...

  5. 创建 Web 前端开发环境

    Web 前端开发涉及多种工具,这里将常用工具的安装和配置进行说明,提供了详细的说明,为后继的开发创建一个坚实的基础. 本文介绍的工具有:NodeJS, NPM, Bower, Git 和 Grunt. ...

  6. Consul 启动命令

    服务端: nohup consul agent -server -bootstrap-expect 1 -config-dir /etc/consul.d/ -data-dir /var/opt/co ...

  7. Git的常用命令的使用方法和解释

    我们常用的git命令: add        Add file contents to the index(将文件添加到暂存区)  用法: 保存某个文件到暂缓区:git add 文件名 保存当前路径的 ...

  8. Httptunnel教程

    hts --forward-port localhost:22 80 htc -F 6789 192.168.10.1:80

  9. Git - Tutorial官方【转】

    转自:http://www.vogella.com/tutorials/Git/article.html#git_rename_branch Lars Vogel Version 5.8 Copyri ...

随机推荐

  1. Java工程师成神之路思维导图

    前面看Hollis的微信公众号更新了Java工程师成神之路的文档,感觉里面的内容清晰.齐全,可以用来审视自己,也能够知道自己在那些方面可以继续前行,想着有时间把它画下来,画下来之后分享出来. 主要内容 ...

  2. 锋利的Jquery摘要

    一本好书值得去反复回味 第一章: jquery中的$(document).ready(function(){})与js中的windows.onload()的比较   $(document).ready ...

  3. Mysql精华版(命令大全)

    数据库的操作 a) 创建数据库:create database 库名[库选项]; b) 查看数据库:show databases;  show create database 库名; c) 删除数据库 ...

  4. Construct Binary Tree from Preorder and Inorder Traversal(根据前序中序构建二叉树)

    根据前序中序构建二叉树. 1 / \ 2 3 / \ / \ 4 5 6 7对于上图的树来说, index: 0 1 2 3 4 5 6 先序遍历为: 6 3 7为了清晰表示,我给节点上了颜色,红色是 ...

  5. python单线程,多线程和协程速度对比

    在某些应用场景下,想要提高python的并发能力,可以使用多线程,或者协程.比如网络爬虫,数据库操作等一些IO密集型的操作.下面对比python单线程,多线程和协程在网络爬虫场景下的速度. 一,单线程 ...

  6. 一个resin启动bug的解决

    这个bug的问题后来被确认为Resin所在目录层有中文目录名.--------------------------------------------------------------------- ...

  7. java数据库之JDBC

    任何一个项目,都离不开数据,而对于数据的存储以及其他操作,就会用到数据库了. 在这里是主要针对MySQL数据库的操作. 1.软件 当然首先要下载MySQL,为了操作起来更加方便,这里推荐一个比较方便的 ...

  8. AE、AS调用时用代码提供许可(不需要添加LicenseControl控件)

    private void CheckBindLicense() { ESRI.ArcGIS.RuntimeManager.Bind(ESRI.ArcGIS.ProductCode.EngineOrDe ...

  9. QT https post请求(QNetworkRequest要设置SSL证书,而SSL证书认证有三种)

    因为https访问需要用到SSL认证,而QT默认是不支持SSL认证,所以在使用之前必须先做一些准备工作: 需要安装OpenSSL库: 1.首先打开http://slproweb.com/product ...

  10. 构建基础的SpringMVC+Hibernate+SpringloC项目

    一. SpringMVC 阅读我的上一篇文章<使用MyEclipse2015构建SpringMVC项目>,知道基本的构建方法,先构建一个纯springmvc项目,再对web.xml按照本文 ...