forwardport--源码笔记--注释
package main
import (
"encoding/json"
"flag"
"fmt"
"io"
"log"
"net"
"net/http"
"os"
"os/signal"
"runtime"
"sync"
"syscall"
"time"
)
var restApiServer = flag.String("restApi", "", "listen addr for restapi") //监听rest full api 地址 ip+端口 默认值 0.0.0.0:8000 参见参数判断
var auth = flag.String("auth", "taven123", "restApi Password") //身份认证 默认rest api 是 taven123
var gLocalConn net.Listener //监听地址
var clientSMap map[string]net.Conn
var forwardInfo string
func main() {
clientSMap = make(map[string]net.Conn) //key 为 ip value 为 ip+端口创建的链接
//解析传入的参数
flag.Parse()
if *restApiServer == "" { //默认监听地址设置
*restApiServer = "0.0.0.0:8000" //默认值
}
go StartHttpServer(*restApiServer)//开启http 监听
log.Println("restApiServer:", *restApiServer)
fmt.Println("------------启动成功------------")
//开启线程同步锁
var w sync.WaitGroup
w.Add(2) //默认监听两个链接
//开一个并发线程,接收退出信号
go func() {
c := make(chan os.Signal, 1) //信号量通道
signal.Notify(c, os.Interrupt, syscall.SIGTERM) //监听系统信号
n := 0
f := func() {
<-c
n++
if n > 2 {
log.Println("force shutdown")
os.Exit(-1)
}
log.Println("received signal,shutdown")
closeAllConn() //关闭对应客户端ip 对应的链接
}
f()
go func() {
for {
f()
}
}()
//执行完成一次,Done() 等同于 Add(-1),计数不为0,则阻塞
w.Done()
}()
loop := func() {
w.Done()
}
loop()
w.Wait()
fmt.Println("------------程序执行完成------------")
}
func StartHttpServer(addr string) { //开启服务器端的信息监听
http.HandleFunc("/ServerSummary", ServerSummary) //获取服务状态
http.HandleFunc("/ForwardWork", ForwardWork) //端口映射服务
//
err := http.ListenAndServe(addr, http.DefaultServeMux)
if err != nil {
fmt.Println("ListenAndServe error: ", err.Error())
}
}
func ServerSummary(rw http.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 //请求rest服务
obj["server_Time"] = time.Now()
obj["clients_Count"] = len(clientSMap) //客户端数量
var clist []string
for cId, _ := range clientSMap { //迭代客户端来链接map
clist = append(clist, cId)
}
obj["clients_List"] = clist //客户端列表
obj["forwardInfo"] = forwardInfo //转向服务器信息
res, err := json.Marshal(obj) //生成json数据
if err != nil {
log.Println("json marshal:", err)
return
}
rw.Header().Add("Content-Type", "application/json;charset=utf-8") //添加响应数据头 数据格式
_, err = rw.Write(res)
if err != nil {
log.Println("write err:", err)
}
return
}
func ForwardWork(rw http.ResponseWriter, req *http.Request) {
req.ParseForm() //解析请求参数
obj := make(map[string]interface{}) //存储状态信息
obj["code"] = 0
obj["msg"] = ""
paramAuth, hasAuth := req.Form["auth"] //获取参数 密码
if !hasAuth { //情况一 不存在密码
log.Println("request no auth")
obj["code"] = 1
obj["msg"] = "request no auth"
responseResult(obj, rw) //json数据格式 响应数据
return
}
if paramAuth[0] != *auth { //情况二 存在密码 但是密码不匹配
log.Println("request auth failed")
obj["code"] = 1
obj["msg"] = "request auth failed"
responseResult(obj, rw)//json数据格式 响应数据
return
}
paramStatus, hasStatus := req.Form["status"] //status:如果是开启转发,则为1,如果是关闭转发,则为0
if !hasStatus { //没有开启转发 直接返回
return
}
log.Println("param_status:", paramStatus)
if paramStatus[0] == "1" { //开启转发
//启动服务
paramFromAddr, hasFromAddr := req.Form["fromAddr"] //要用来在A机器上监听的一个端口,用来给客户端连接 =====服务器
paramToAddr, hasToAddr := req.Form["toAddr"] //把fromAddr端口的数据转发到哪个IP的端口上 ===转发到的服务器
if gLocalConn != nil { //目标服务器是否存在链接 不存在 直接拒接
gLocalConn.Close() //释放资源
}
if hasFromAddr && hasToAddr { //目标服务器 和 转发到服务器存在
go forwardPort(paramFromAddr[0], paramToAddr[0])
}
}
if paramStatus[0] == "0" { //转发状态为0 时 直接释放资源
//关闭服务
closeAllConn()
forwardInfo = ""
}
responseResult(obj, rw)// json格式数据响应客户端
return
}
func responseResult(data map[string]interface{}, rw http.ResponseWriter) {// json格式数据响应客户端
res, err := json.Marshal(data) //生成json数据格式
if err != nil {
log.Println("json marshal:", err)
return
}
rw.Header().Add("Content-Type", "application/json;charset=utf-8") //响应头数据格式设置
_, err = rw.Write(res) //响应写入数据
if err != nil {
log.Println("write err:", err)
}
}
func closeAllConn() {// 关闭连接
for cId, conn := range clientSMap {
log.Println("clientMap id:", cId)
conn.Close() //关闭连接 conn
delete(clientSMap, cId) //从客户端map中删除对应的数据
}
if gLocalConn != nil { //关闭元数据链接【服务端】
gLocalConn.Close()
log.Println("Listener Close")
} else {
gLocalConn = nil
log.Println("Listener set to nil", gLocalConn)
}
}
func forwardPort(sourcePort string, targetPort string) { //转发服务
fmt.Println("sourcePort:", sourcePort, "targetPort:", targetPort)
localConn, err := net.Listen("tcp", sourcePort) //目标服务器 监听服务器
if err != nil {
fmt.Println(err.Error())
return
}
gLocalConn = localConn
fmt.Println("服务启动成功,服务地址:", sourcePort)
forwardInfo = fmt.Sprintf("%s - %s", sourcePort, targetPort)
for {
fmt.Println("Ready to Accept ...")
sourceConn, err := gLocalConn.Accept() //获取监听服务链接
if err != nil {
log.Println("server err:", err.Error())
break
}
//log.Println("client", sc.id, "create session", sessionId)
id := sourceConn.RemoteAddr().String() //获取客户端ip地址
clientSMap[id] = sourceConn
fmt.Println("conn.RemoteAddr().String() :", id)
//targetPort := "172.16.128.83:22"
targetConn, err := net.DialTimeout("tcp", targetPort, 30*time.Second)//获取转发服务链接
//开启协程 支持从客户端 到服务端 以及 从 服务端到客户端数据 读写
go func() {
_, err = io.Copy(targetConn, sourceConn) //从sourceConn读取数据 写入到targetConn中
if err != nil {
//log.Fatalf("io.Copy 1 failed: %v", err)
fmt.Println("io.Copy 1 failed:", err.Error())
}
}()
go func() {
_, err = io.Copy(sourceConn, targetConn)//从targetConn读取数据 写入到sourceConn中
if err != nil {
//log.Fatalf("io.Copy 2 failed: %v", err)
fmt.Println("io.Copy 2 failed:", err.Error())
}
}()
}
//
log.Println("forwardPort end.")
}
forwardport--源码笔记--注释的更多相关文章
- AsyncTask源码笔记
AsyncTask源码笔记 AsyncTask在注释中建议只用来做短时间的异步操作,也就是只有几秒的操作:如果是长时间的操作,建议还是使用java.util.concurrent包中的工具类,例如Ex ...
- Java Arrays 源码 笔记
Arrays.java是Java中用来操作数组的类.使用这个工具类可以减少平常很多的工作量.了解其实现,可以避免一些错误的用法. 它提供的操作包括: 排序 sort 查找 binarySearch() ...
- Tomcat8源码笔记(六)连接器Connector分析
根据 Tomcat8源码笔记(五)组件Container分析 前文分析,StandardService的初始化重心由 StandardEngine转移到了Connector的初始化,本篇记录下Conn ...
- Golang构建HTTP服务(一)--- net/http库源码笔记
搭建一个简单的Go Web服务器 Go语言标准库 - net/http 在学习Go语言有一个很好的起点,Go语言官方文档很详细,今天我们学习的Go Web服务器的搭建就需要用到Go语言官方提供的标准库 ...
- Zepto源码笔记(一)
最近在研究Zepto的源码,这是第一篇分析,欢迎大家继续关注,第一次写源码笔记,希望大家多指点指点,第一篇文章由于首次分析原因不会有太多干货,希望后面的文章能成为各位大大心目中的干货. Zepto是一 ...
- robotlegs2.0框架实例源码带注释
robotlegs2.0框架实例源码带注释 Robotlegs2的Starling扩展 有个老外写了robotleges2的starling扩展,地址是 https://github.com/brea ...
- redis源码笔记(一) —— 从redis的启动到command的分发
本作品采用知识共享署名 4.0 国际许可协议进行许可.转载联系作者并保留声明头部与原文链接https://luzeshu.com/blog/redis1 本博客同步在http://www.cnblog ...
- Tomcat8源码笔记(八)明白Tomcat怎么部署webapps下项目
以前没想过这么个问题:Tomcat怎么处理webapps下项目,并且我访问浏览器ip: port/项目名/请求路径,以SSM为例,Tomcat怎么就能将请求找到项目呢,项目还是个文件夹类型的? Tom ...
- Tomcat8源码笔记(七)组件启动Server Service Engine Host启动
一.Tomcat启动的入口 Tomcat初始化简单流程前面博客介绍了一遍,组件除了StandardHost都有博客,欢迎大家指文中错误.Tomcat启动类是Bootstrap,而启动容器启动入口位于 ...
- Tomcat8源码笔记(五)组件Container分析
Tomcat8源码笔记(四)Server和Service初始化 介绍过Tomcat中Service的初始化 最先初始化就是Container,而Container初始化过程是咋样的? 说到Contai ...
随机推荐
- VS Code python初体验笔记
之前一直都是使用Notepad++来编写Python代码,后来想起来之前查资料的时候有个VS Code可以编写一些的脚本语言(js,node.js)甚至是高级编程语言(C#,PHP,JAVA,Pyth ...
- Hibernate的二级缓存策略
Hibernate的二级缓存策略的一般过程如下: 1) 条件查询的时候,总是发出一条select * from table_name where …. (选择所有字段)这样的SQL语句查询数据库,一次 ...
- MinGW安装与使用简介
MinGW 安装与使用简介 安装方法:其实很简单,如下: Step one: 到这里下载 MinGW, 网速慢的话可能打不开, 是个外国网站 (上面的网站镜像可能 出了点问题 , 有的东西下载下来却不 ...
- 前端Mahsup异步依赖方式不能做业务数据依赖
很久之前流行mashup方式做内容集成,之前为了IP定位的方便,引用了第三方的IP定位JS,然后根据其内容与服务器同步地址数据并写入Cookie,可是这种方式一旦,第三方的库反应缓慢时,就会出现大问题 ...
- 2013-8:SDCE大会笔记
百度移动云三大开发框架:Clouda,SiteApp,AppBuilder MBaaS解决高性能Server很难的问题 百度开放云的区域运营服务于创业者 Pinterest架构变迁: 互联网就是把线下 ...
- c# 多线程编程中AutoResetEvent和ManualResetEvent
作为等同于Java的wait,notify,notifyAll的存在,AutoResetEvent和ManualResetEvent分别实现了notify和notifyAll的功能,下面的代码简单讲解 ...
- 佛祖镇楼,BUG避易
def FZZL(): print(" _ooOoo_ ") print(" o8888888o ") print(" 88 . 88 ") ...
- java后台服务器实现极光推送
一.添加极光推送所需要的jar包,项目使用的maven,所以只需要在pom文件里添加jar包依赖 <dependency> <groupId>cn.jpush.api</ ...
- Spring Data JPA 初体验
一,JPA相关的概念 JPA概述 全称是:JavaPersistence API.是SUN公司推出的一套基于ORM的规范. Hibernate框架中提供了JPA的实现. JPA通过JDK 5.0注解或 ...
- 【转】高效利用Fundebug追踪Node.js日志发现问题
不管使用哪个语言做项目开发,我们都会自觉地用日志来做相关记录.比如,HTTP请求,报错信息.某些关键节点埋点记录等等.在Java中有大名鼎鼎的Log4J,于是在Node.js中也有了log4js. 日 ...