Merge pull request #360 from ehang-io/dev

Dev
This commit is contained in:
ffdfgdfg 2020-01-08 23:33:31 +08:00 committed by GitHub
commit a8c0f1653d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
70 changed files with 1622 additions and 450 deletions

View File

@ -1,10 +1,10 @@
FROM golang as builder FROM golang as builder
WORKDIR /go/src/github.com/cnlh/nps WORKDIR /go/src/ehang.io/nps
COPY . . COPY . .
RUN go get -d -v ./... RUN go get -d -v ./...
RUN CGO_ENABLED=0 go build -ldflags="-w -s -extldflags -static" ./cmd/npc/npc.go RUN CGO_ENABLED=0 go build -ldflags="-w -s -extldflags -static" ./cmd/npc/npc.go
FROM scratch FROM scratch
COPY --from=builder /go/src/github.com/cnlh/nps/npc / COPY --from=builder /go/src/ehang.io/nps/npc /
VOLUME /conf VOLUME /conf
ENTRYPOINT ["/npc"] ENTRYPOINT ["/npc"]

View File

@ -1,11 +1,11 @@
FROM golang as builder FROM golang as builder
WORKDIR /go/src/github.com/cnlh/nps WORKDIR /go/src/ehang.io/nps
COPY . . COPY . .
RUN go get -d -v ./... RUN go get -d -v ./...
RUN CGO_ENABLED=0 go build -ldflags="-w -s -extldflags -static" ./cmd/nps/nps.go RUN CGO_ENABLED=0 go build -ldflags="-w -s -extldflags -static" ./cmd/nps/nps.go
FROM scratch FROM scratch
COPY --from=builder /go/src/github.com/cnlh/nps/nps / COPY --from=builder /go/src/ehang.io/nps/nps /
COPY --from=builder /go/src/github.com/cnlh/nps/web /web COPY --from=builder /go/src/ehang.io/nps/web /web
VOLUME /conf VOLUME /conf
CMD ["/nps"] CMD ["/nps"]

102
README.md
View File

@ -1,78 +1,76 @@
# nps # NPS
![](https://img.shields.io/github/stars/cnlh/nps.svg) ![](https://img.shields.io/github/forks/cnlh/nps.svg) ![](https://img.shields.io/github/stars/ehang-io/nps.svg) ![](https://img.shields.io/github/forks/ehang-io/nps.svg)
[![Gitter](https://badges.gitter.im/cnlh-nps/community.svg)](https://gitter.im/cnlh-nps/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![Gitter](https://badges.gitter.im/cnlh-nps/community.svg)](https://gitter.im/cnlh-nps/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
[![Build Status](https://travis-ci.org/cnlh/nps.svg?branch=master)](https://travis-ci.org/cnlh/nps) [![Build Status](https://travis-ci.org/ehang-io/nps.svg?branch=master)](https://travis-ci.org/ehang-io/nps)
![GitHub All Releases](https://img.shields.io/github/downloads/cnlh/nps/total) ![GitHub All Releases](https://img.shields.io/github/downloads/ehang-io/nps/total)
nps是一款轻量级、高性能、功能强大的**内网穿透**代理服务器。目前支持**tcp、udp流量转发**,可支持任何**tcp、udp**上层协议访问内网网站、本地支付接口调试、ssh访问、远程桌面内网dns解析等等……此外还**支持内网http代理、内网socks5代理**、**p2p等**并带有功能强大的web管理端。 [README](https://github.com/ehang-io/nps/blob/master/README.md)|[中文文档](https://github.com/ehang-io/nps/blob/master/README_zh.md)
NPS is a lightweight, high-performance, powerful **intranet penetration** proxy server, with a powerful web management terminal.
## 背景 ![image](https://github.com/ehang-io/nps/blob/master/image/web.png?raw=true)
![image](https://github.com/cnlh/nps/blob/master/image/web.png?raw=true)
1. 做微信公众号开发、小程序开发等----> 域名代理模式 ## Feature
2. 想在外网通过ssh连接内网的机器做云服务器到内网服务器端口的映射----> tcp代理模式 - Comprehensive protocol support, compatible with almost all commonly used protocols, such as tcp, udp, http(s), socks5, p2p, http proxy ...
- Full platform compatibility (linux, windows, macos, Qunhui, etc.), support installation as a system service simply.
- Comprehensive control, both client and server control are allowed.
- Https integration, support to convert backend proxy and web services to https, and support multiple certificates.
- Just simple configuration on web ui can complete most requirements.
- Complete information display, such as traffic, system information, real-time bandwidth, client version, etc.
- Powerful extension functions, everything is available (cache, compression, encryption, traffic limit, bandwidth limit, port reuse, etc.)
- Domain name resolution has functions such as custom headers, 404 page configuration, host modification, site protection, URL routing, and pan-resolution.
- Multi-user and user registration support on server.
3. 在非内网环境下使用内网dns或者需要通过udp访问内网机器等----> udp代理模式 **Didn't find the feature you want? It doesn't matter, click [Enter the document](https://ehang-io.github.io/nps/) to find it!**
4. 在外网使用HTTP代理访问内网站点----> http代理模式 ## Quick start
5. 搭建一个内网穿透ss在外网如同使用内网vpn一样访问内网资源或者设备----> socks5代理模式 ### Installation
## 特点
- 协议支持全面兼容几乎所有常用协议例如tcp、udp、http(s)、socks5、p2p、http代理...
- 全平台兼容(linux、windows、macos、群辉等),支持一键安装为系统服务
- 控制全面,同时支持服务端和客户端控制
- https集成支持将后端代理和web服务转成https同时支持多证书
- 操作简单只需简单的配置即可在web ui上完成其余操作
- 展示信息全面,流量、系统信息、即时带宽、客户端版本等
- 扩展功能强大,该有的都有了(缓存、压缩、加密、流量限制、带宽限制、端口复用等等)
- 域名解析具备自定义header、404页面配置、host修改、站点保护、URL路由、泛解析等功能
- 服务端支持多用户和用户注册功能
**没找到你想要的功能?不要紧,点击[进入文档](https://ehang-io.github.io/nps)查找吧** > [releases](https://github.com/ehang-io/nps/releases)
## 快速开始
### 安装 Download the corresponding system version, the server and client are separate.
> [releases](https://github.com/cnlh/nps/releases)
下载对应的系统版本即可,服务端和客户端是单独的 ### Server start
### 服务端启动 After downloading the server compressed package, unzip it, and then enter the unzipped folder.
下载完服务器压缩包后,解压,然后进入解压后的文件夹
- 执行安装命令 - execute installation command
对于linux|darwin ```sudo ./nps install``` For linux、darwin ```sudo ./nps install```
对于windows管理员身份运行cmd进入安装目录 ```nps.exe install``` For windows, run cmd as administrator and enter the installation directory ```nps.exe install```
- 启动 - start up
对于linux|darwin ```sudo nps start``` For linux、darwin ```sudo nps start```
对于windows管理员身份运行cmd进入程序目录 ```nps.exe start``` For windows, run cmd as administrator and enter the program directory ```nps.exe start```
```安装后windows配置文件位于 C:\Program Files\npslinux和darwin位于/etc/nps``` ```After installation, the windows configuration file is located at C:\Program Files\nps, linux or darwin is located at /etc/nps```
**如果发现没有启动成功,可以查看日志(Windows日志文件位于当前运行目录下linux和darwin位于/var/log/nps.log)** **If you don't find it started successfully, you can check the log (Windows log files are located in the current running directory, linux and darwin are located in /var/log/nps.log).**
- 访问服务端ip:web服务端口默认为8080
- 使用用户名和密码登陆默认admin/123正式使用一定要更改
- 创建客户端
### 客户端连接 - Access server IP:web service port (default is 8080).
- 点击web管理中客户端前的+号,复制启动命令 - Login with username and password (default is admin/123, must be modified when officially used).
- 执行启动命令linux直接执行即可windows将./npc换成npc.exe用cmd执行 - Create a client.
如果需要注册到系统服务可查看[注册到系统服务](https://ehang-io.github.io/nps/#/use?id=注册到系统服务) ### Client connection
- Click the + sign in front of the client in web management and copy the startup command.
- Execute the startup command, Linux can be executed directly, Windows will replace ./npc with npc.exe and execute it with cmd.
### 配置
- 客户端连接后在web中配置对应穿透服务即可
- 更多高级用法见[完整文档](https://ehang-io.github.io/nps)
## 贡献 If you need to register to the system service, you can check [Register to the system service](https://ehang-io.github.io/nps/#/use?id=注册到系统服务)
- 如果遇到bug可以直接提交至dev分支
- 使用遇到问题可以通过issues反馈 ### Configuration
- 项目处于开发阶段,还有很多待完善的地方,如果可以贡献代码,请提交 PR 至 dev 分支 - After the client connects, configure the corresponding penetration service in the web.
- 如果有新的功能特性反馈可以通过issues或者qq群反馈 - For more advanced usage, see [Complete Documentation](https://ehang-io.github.io/nps/)
## Contribution
- If you encounter a bug, you can submit it to the dev branch directly.
- If you encounter a problem, you can feedback through the issue.
- The project is under development, and there is still a lot of room for improvement. If you can contribute code, please submit PR to the dev branch.
- If there is feedback on new features, you can feedback via issues or qq group.

80
README_zh.md Normal file
View File

@ -0,0 +1,80 @@
# nps
![](https://img.shields.io/github/stars/ehang-io/nps.svg) ![](https://img.shields.io/github/forks/ehang-io/nps.svg)
[![Gitter](https://badges.gitter.im/cnlh-nps/community.svg)](https://gitter.im/cnlh-nps/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
[![Build Status](https://travis-ci.org/ehang-io/nps.svg?branch=master)](https://travis-ci.org/ehang-io/nps)
![GitHub All Releases](https://img.shields.io/github/downloads/ehang-io/nps/total)
[README](https://github.com/ehang-io/nps/blob/master/README.md)|[中文文档](https://github.com/ehang-io/nps/blob/master/README_zh.md)
nps是一款轻量级、高性能、功能强大的**内网穿透**代理服务器。目前支持**tcp、udp流量转发**,可支持任何**tcp、udp**上层协议访问内网网站、本地支付接口调试、ssh访问、远程桌面内网dns解析等等……此外还**支持内网http代理、内网socks5代理**、**p2p等**并带有功能强大的web管理端。
## 背景
![image](https://github.com/ehang-io/nps/blob/master/image/web.png?raw=true)
1. 做微信公众号开发、小程序开发等----> 域名代理模式
2. 想在外网通过ssh连接内网的机器做云服务器到内网服务器端口的映射----> tcp代理模式
3. 在非内网环境下使用内网dns或者需要通过udp访问内网机器等----> udp代理模式
4. 在外网使用HTTP代理访问内网站点----> http代理模式
5. 搭建一个内网穿透ss在外网如同使用内网vpn一样访问内网资源或者设备----> socks5代理模式
## 特点
- 协议支持全面兼容几乎所有常用协议例如tcp、udp、http(s)、socks5、p2p、http代理...
- 全平台兼容(linux、windows、macos、群辉等),支持一键安装为系统服务
- 控制全面,同时支持服务端和客户端控制
- https集成支持将后端代理和web服务转成https同时支持多证书
- 操作简单只需简单的配置即可在web ui上完成其余操作
- 展示信息全面,流量、系统信息、即时带宽、客户端版本等
- 扩展功能强大,该有的都有了(缓存、压缩、加密、流量限制、带宽限制、端口复用等等)
- 域名解析具备自定义header、404页面配置、host修改、站点保护、URL路由、泛解析等功能
- 服务端支持多用户和用户注册功能
**没找到你想要的功能?不要紧,点击[进入文档](https://ehang-io.github.io/nps)查找吧**
## 快速开始
### 安装
> [releases](https://github.com/ehang-io/nps/releases)
下载对应的系统版本即可,服务端和客户端是单独的
### 服务端启动
下载完服务器压缩包后,解压,然后进入解压后的文件夹
- 执行安装命令
对于linux|darwin ```sudo ./nps install```
对于windows管理员身份运行cmd进入安装目录 ```nps.exe install```
- 启动
对于linux|darwin ```sudo nps start```
对于windows管理员身份运行cmd进入程序目录 ```nps.exe start```
```安装后windows配置文件位于 C:\Program Files\npslinux和darwin位于/etc/nps```
**如果发现没有启动成功,可以查看日志(Windows日志文件位于当前运行目录下linux和darwin位于/var/log/nps.log)**
- 访问服务端ip:web服务端口默认为8080
- 使用用户名和密码登陆默认admin/123正式使用一定要更改
- 创建客户端
### 客户端连接
- 点击web管理中客户端前的+号,复制启动命令
- 执行启动命令linux直接执行即可windows将./npc换成npc.exe用cmd执行
如果需要注册到系统服务可查看[注册到系统服务](https://ehang-io.github.io/nps/#/use?id=注册到系统服务)
### 配置
- 客户端连接后在web中配置对应穿透服务即可
- 更多高级用法见[完整文档](https://ehang-io.github.io/nps/)
## 贡献
- 如果遇到bug可以直接提交至dev分支
- 使用遇到问题可以通过issues反馈
- 项目处于开发阶段,还有很多待完善的地方,如果可以贡献代码,请提交 PR 至 dev 分支
- 如果有新的功能特性反馈可以通过issues或者qq群反馈

View File

@ -11,16 +11,16 @@ import (
"sync" "sync"
"time" "time"
"ehang.io/nps/lib/common"
"ehang.io/nps/lib/conn"
"ehang.io/nps/lib/crypt"
"ehang.io/nps/lib/file"
"ehang.io/nps/lib/mux"
"ehang.io/nps/lib/version"
"ehang.io/nps/server/connection"
"ehang.io/nps/server/tool"
"github.com/astaxie/beego" "github.com/astaxie/beego"
"github.com/astaxie/beego/logs" "github.com/astaxie/beego/logs"
"github.com/cnlh/nps/lib/common"
"github.com/cnlh/nps/lib/conn"
"github.com/cnlh/nps/lib/crypt"
"github.com/cnlh/nps/lib/file"
"github.com/cnlh/nps/lib/mux"
"github.com/cnlh/nps/lib/version"
"github.com/cnlh/nps/server/connection"
"github.com/cnlh/nps/server/tool"
) )
type Client struct { type Client struct {

View File

@ -14,16 +14,16 @@ git checkout v1.2.0
go install -v ./cmd/fyne go install -v ./cmd/fyne
#fyne package -os android fyne.io/fyne/cmd/hello #fyne package -os android fyne.io/fyne/cmd/hello
echo "fyne install success" echo "fyne install success"
mkdir -p /go/src/github.com/cnlh/nps mkdir -p /go/src/ehang.io/nps
cp -R /app/* /go/src/github.com/cnlh/nps cp -R /app/* /go/src/ehang.io/nps
cd /go/src/github.com/cnlh/nps cd /go/src/ehang.io/nps
#go get -u fyne.io/fyne fyne.io/fyne/cmd/fyne #go get -u fyne.io/fyne fyne.io/fyne/cmd/fyne
rm cmd/npc/sdk.go rm cmd/npc/sdk.go
#go get -u ./... #go get -u ./...
#go mod tidy #go mod tidy
#rm -rf /go/src/golang.org/x/mobile #rm -rf /go/src/golang.org/x/mobile
echo "tidy success" echo "tidy success"
cd /go/src/github.com/cnlh/nps cd /go/src/ehang.io/nps
go mod vendor go mod vendor
cd vendor cd vendor
cp -R * /go/src cp -R * /go/src

View File

@ -1,5 +1,5 @@
#/bash/sh #/bash/sh
export VERSION=0.25.4 export VERSION=0.26.0
sudo apt-get install gcc-mingw-w64-i686 sudo apt-get install gcc-mingw-w64-i686
env GOOS=windows GOARCH=386 CGO_ENABLED=1 CC=i686-w64-mingw32-gcc go build -ldflags "-s -w -extldflags -static -extldflags -static" -buildmode=c-shared -o npc_sdk.dll cmd/npc/sdk.go env GOOS=windows GOARCH=386 CGO_ENABLED=1 CC=i686-w64-mingw32-gcc go build -ldflags "-s -w -extldflags -static -extldflags -static" -buildmode=c-shared -o npc_sdk.dll cmd/npc/sdk.go

View File

@ -11,11 +11,11 @@ import (
"github.com/astaxie/beego/logs" "github.com/astaxie/beego/logs"
"github.com/xtaci/kcp-go" "github.com/xtaci/kcp-go"
"github.com/cnlh/nps/lib/common" "ehang.io/nps/lib/common"
"github.com/cnlh/nps/lib/config" "ehang.io/nps/lib/config"
"github.com/cnlh/nps/lib/conn" "ehang.io/nps/lib/conn"
"github.com/cnlh/nps/lib/crypt" "ehang.io/nps/lib/crypt"
"github.com/cnlh/nps/lib/mux" "ehang.io/nps/lib/mux"
) )
type TRPClient struct { type TRPClient struct {
@ -44,6 +44,7 @@ func NewRPClient(svraddr string, vKey string, bridgeConnType string, proxyUrl st
var NowStatus int var NowStatus int
var CloseClient bool var CloseClient bool
//start //start
func (s *TRPClient) Start() { func (s *TRPClient) Start() {
CloseClient = false CloseClient = false

View File

@ -19,12 +19,12 @@ import (
"strings" "strings"
"time" "time"
"ehang.io/nps/lib/common"
"ehang.io/nps/lib/config"
"ehang.io/nps/lib/conn"
"ehang.io/nps/lib/crypt"
"ehang.io/nps/lib/version"
"github.com/astaxie/beego/logs" "github.com/astaxie/beego/logs"
"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/xtaci/kcp-go" "github.com/xtaci/kcp-go"
"golang.org/x/net/proxy" "golang.org/x/net/proxy"
) )

View File

@ -7,10 +7,10 @@ import (
"strings" "strings"
"time" "time"
"ehang.io/nps/lib/conn"
"ehang.io/nps/lib/file"
"ehang.io/nps/lib/sheap"
"github.com/astaxie/beego/logs" "github.com/astaxie/beego/logs"
"github.com/cnlh/nps/lib/conn"
"github.com/cnlh/nps/lib/file"
"github.com/cnlh/nps/lib/sheap"
"github.com/pkg/errors" "github.com/pkg/errors"
) )

View File

@ -8,14 +8,14 @@ import (
"sync" "sync"
"time" "time"
"ehang.io/nps/lib/common"
"ehang.io/nps/lib/config"
"ehang.io/nps/lib/conn"
"ehang.io/nps/lib/crypt"
"ehang.io/nps/lib/file"
"ehang.io/nps/lib/mux"
"ehang.io/nps/server/proxy"
"github.com/astaxie/beego/logs" "github.com/astaxie/beego/logs"
"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/file"
"github.com/cnlh/nps/lib/mux"
"github.com/cnlh/nps/server/proxy"
"github.com/xtaci/kcp-go" "github.com/xtaci/kcp-go"
) )

View File

@ -5,7 +5,7 @@ import (
"log" "log"
"os" "os"
"github.com/cnlh/nps/lib/common" "ehang.io/nps/lib/common"
) )
func RegisterLocalIp(server string, vKey string, tp string, proxyUrl string, hour int) { func RegisterLocalIp(server string, vKey string, tp string, proxyUrl string, hour int) {

View File

@ -1,16 +1,16 @@
package main package main
import ( import (
"ehang.io/nps/client"
"ehang.io/nps/lib/common"
"ehang.io/nps/lib/config"
"ehang.io/nps/lib/file"
"ehang.io/nps/lib/install"
"ehang.io/nps/lib/version"
"flag" "flag"
"fmt" "fmt"
"github.com/astaxie/beego/logs" "github.com/astaxie/beego/logs"
"github.com/ccding/go-stun/stun" "github.com/ccding/go-stun/stun"
"github.com/cnlh/nps/client"
"github.com/cnlh/nps/lib/common"
"github.com/cnlh/nps/lib/config"
"github.com/cnlh/nps/lib/file"
"github.com/cnlh/nps/lib/install"
"github.com/cnlh/nps/lib/version"
"github.com/kardianos/service" "github.com/kardianos/service"
"os" "os"
"runtime" "runtime"
@ -114,7 +114,7 @@ func main() {
} }
err := service.Control(s, os.Args[1]) err := service.Control(s, os.Args[1])
if err != nil { if err != nil {
logs.Error("Valid actions: %q\n", service.ControlAction, err.Error()) logs.Error("Valid actions: %q\n%s", service.ControlAction, err.Error())
} }
return return
} }

View File

@ -2,10 +2,10 @@ package main
import ( import (
"C" "C"
"ehang.io/nps/client"
"ehang.io/nps/lib/common"
"ehang.io/nps/lib/version"
"github.com/astaxie/beego/logs" "github.com/astaxie/beego/logs"
"github.com/cnlh/nps/client"
"github.com/cnlh/nps/lib/common"
"github.com/cnlh/nps/lib/version"
) )
var cl *client.TRPClient var cl *client.TRPClient

View File

@ -1,26 +1,26 @@
package main package main
import ( import (
"ehang.io/nps/lib/install"
"flag" "flag"
"github.com/cnlh/nps/lib/install"
"log" "log"
"os" "os"
"path/filepath" "path/filepath"
"runtime" "runtime"
"strings" "strings"
"ehang.io/nps/lib/common"
"ehang.io/nps/lib/crypt"
"ehang.io/nps/lib/daemon"
"ehang.io/nps/lib/file"
"ehang.io/nps/lib/version"
"ehang.io/nps/server"
"ehang.io/nps/server/connection"
"ehang.io/nps/server/tool"
"github.com/astaxie/beego" "github.com/astaxie/beego"
"github.com/astaxie/beego/logs" "github.com/astaxie/beego/logs"
"github.com/cnlh/nps/lib/common"
"github.com/cnlh/nps/lib/crypt"
"github.com/cnlh/nps/lib/daemon"
"github.com/cnlh/nps/lib/file"
"github.com/cnlh/nps/lib/version"
"github.com/cnlh/nps/server"
"github.com/cnlh/nps/server/connection"
"github.com/cnlh/nps/server/tool"
"github.com/cnlh/nps/web/routers" "ehang.io/nps/web/routers"
"github.com/kardianos/service" "github.com/kardianos/service"
) )
@ -94,13 +94,13 @@ func main() {
} }
err = service.Control(s, os.Args[1]) err = service.Control(s, os.Args[1])
if err != nil { if err != nil {
logs.Error("Valid actions: %q\n", service.ControlAction, err.Error()) logs.Error("Valid actions: %q\n%s", service.ControlAction, err.Error())
} }
return return
case "start", "restart", "stop", "uninstall": case "start", "restart", "stop", "uninstall":
err := service.Control(s, os.Args[1]) err := service.Control(s, os.Args[1])
if err != nil { if err != nil {
logs.Error("Valid actions: %q\n", service.ControlAction, err.Error()) logs.Error("Valid actions: %q\n%s", service.ControlAction, err.Error())
} }
return return
case "update": case "update":

View File

@ -7,7 +7,7 @@ nps是一款轻量级、高性能、功能强大的**内网穿透**代理服务
## 背景 ## 背景
![image](https://github.com/cnlh/nps/blob/master/image/web.png?raw=true) ![image](https://github.com/ehang-io/nps/blob/master/image/web.png?raw=true)
1. 做微信公众号开发、小程序开发等----> 域名代理模式 1. 做微信公众号开发、小程序开发等----> 域名代理模式

View File

@ -1,6 +1,6 @@
![logo](logo.svg) ![logo](logo.svg)
# NPS <small>0.25.4</small> # NPS <small>0.26.0</small>
> 一款轻量级、高性能、功能强大的内网穿透代理服务器 > 一款轻量级、高性能、功能强大的内网穿透代理服务器
@ -12,5 +12,5 @@
- 全平台兼容,一键注册为服务 - 全平台兼容,一键注册为服务
[GitHub](https://github.com/cnlh/nps/) [GitHub](https://github.com/ehang-io/nps/)
[开始使用](#nps) [开始使用](#nps)

View File

@ -43,4 +43,4 @@ POST /auth/getauthkey
- **此文档近期可能更新较慢,建议自行抓包** - **此文档近期可能更新较慢,建议自行抓包**
为方便第三方扩展在web模式下可利用webAPI进行相关操作详情见 为方便第三方扩展在web模式下可利用webAPI进行相关操作详情见
[webAPI文档](https://github.com/cnlh/nps/wiki/webAPI%E6%96%87%E6%A1%A3) [webAPI文档](https://github.com/ehang-io/nps/wiki/webAPI%E6%96%87%E6%A1%A3)

View File

@ -2,6 +2,6 @@
如果您觉得nps对你有帮助欢迎给予我们一定捐助也是帮助nps更好的发展。 如果您觉得nps对你有帮助欢迎给予我们一定捐助也是帮助nps更好的发展。
## 支付宝 ## 支付宝
![image](https://github.com/cnlh/nps/blob/master/image/donation_zfb.png?raw=true) ![image](https://github.com/ehang-io/nps/blob/master/image/donation_zfb.png?raw=true)
## 微信 ## 微信
![image](https://github.com/cnlh/nps/blob/master/image/donation_wx.png?raw=true) ![image](https://github.com/ehang-io/nps/blob/master/image/donation_wx.png?raw=true)

View File

@ -29,7 +29,7 @@
hideOtherSidebarContent: true, // whether or not to hide other sidebar content hideOtherSidebarContent: true, // whether or not to hide other sidebar content
}, },
plugins: [ plugins: [
EditOnGithubPlugin.create("https://github.com/cnlh/nps/tree/master/docs/", "", "在github上编辑"), EditOnGithubPlugin.create("https://github.com/ehang-io/nps/tree/master/docs/", "", "在github上编辑"),
] ]
} }

View File

@ -1,13 +1,12 @@
# 安装 # 安装
## 安装包安装 ## 安装包安装
[releases](https://github.com/cnlh/nps/releases) [releases](https://github.com/ehang-io/nps/releases)
下载对应的系统版本即可,服务端和客户端是单独的 下载对应的系统版本即可,服务端和客户端是单独的
## 源码安装 ## 源码安装
- 安装源码 - 安装源码
```go get -u github.com/cnlh/nps... ```go get -u ehang.io/nps...```
```
- 编译 - 编译
服务端```go build cmd/nps/nps.go``` 服务端```go build cmd/nps/nps.go```

View File

@ -1,4 +1,4 @@
![image](https://github.com/cnlh/nps/blob/master/image/web2.png?raw=true) ![image](https://github.com/ehang-io/nps/blob/master/image/web2.png?raw=true)
# 介绍 # 介绍
可在网页上配置和管理各个tcp、udp隧道、内网站点代理http、https解析等功能强大操作方便。 可在网页上配置和管理各个tcp、udp隧道、内网站点代理http、https解析等功能强大操作方便。

View File

@ -44,7 +44,7 @@ npc-update.exe update
./npc -config=npc配置文件路径 ./npc -config=npc配置文件路径
``` ```
## 配置文件说明 ## 配置文件说明
[示例配置文件](https://github.com/cnlh/nps/tree/master/conf/npc.conf) [示例配置文件](https://github.com/ehang-io/nps/tree/master/conf/npc.conf)
#### 全局配置 #### 全局配置
```ini ```ini
[common] [common]

233
docs/webapi.md Normal file
View File

@ -0,0 +1,233 @@
获取客户端列表
```
POST /client/list/
```
| 参数 | 含义 |
| --- | --- |
| search | 搜索 |
| order | 排序asc 正序 desc倒序 |
| offset | 分页(第几页) |
| limit | 条数(分页显示的条数) |
***
获取单个客户端
```
POST /client/getclient/
```
| 参数 | 含义 |
| --- | --- |
| id | 客户端id |
***
添加客户端
```
POST /client/add/
```
| 参数 | 含义 |
| --- | --- |
| remark | 备注 |
| u | basic权限认证用户名 |
| p | basic权限认证密码 |
| limit | 条数(分页显示的条数) |
| vkey | 客户端验证密钥 |
| config\_conn\_allow | 是否允许客户端以配置文件模式连接 1允许 0不允许 |
| compress | 压缩1允许 0不允许 |
| crypt | 是否加密1或者01允许 0不允许 |
| rate\_limit | 带宽限制 单位KB/S 空则为不限制 |
| flow\_limit | 流量限制 单位M 空则为不限制 |
| max\_conn | 客户端最大连接数量 空则为不限制 |
| max\_tunnel | 客户端最大隧道数量 空则为不限制 |
***
修改客户端(25.4版本有问题暂时不能用)
```
POST /client/edit/
```
| 参数 | 含义 |
| --- | --- |
| remark | 备注 |
| u | basic权限认证用户名 |
| p | basic权限认证密码 |
| limit | 条数(分页显示的条数) |
| vkey | 客户端验证密钥 |
| config\_conn\_allow | 是否允许客户端以配置文件模式连接 1允许 0不允许 |
| compress | 压缩1允许 0不允许 |
| crypt | 是否加密1或者01允许 0不允许 |
| rate\_limit | 带宽限制 单位KB/S 空则为不限制 |
| flow\_limit | 流量限制 单位M 空则为不限制 |
| max\_conn | 客户端最大连接数量 空则为不限制 |
| max\_tunnel | 客户端最大隧道数量 空则为不限制 |
| id | 要修改的客户端id |
***
删除客户端
```
POST /client/del/
```
| 参数 | 含义 |
| --- | --- |
| id | 要删除的客户端id |
***
获取域名解析列表
```
POST /index/hostlist/
```
| 参数 | 含义 |
| --- | --- |
| search | 搜索(可以搜域名/备注什么的) |
| offset | 分页(第几页) |
| limit | 条数(分页显示的条数) |
***
添加域名解析
```
POST /index/addhost/
```
| 参数 | 含义 |
| --- | --- |
| remark | 备注 |
| host | 域名 |
| scheme | 协议类型(三种 all http https) |
| location | url路由 空则为不限制 |
| client\_id | 客户端id |
| target | 内网目标(ip:端口) |
| header | request header 请求头 |
| hostchange | request host 请求主机 |
***
修改域名解析
```
POST /index/edithost/
```
| 参数 | 含义 |
| --- | --- |
| remark | 备注 |
| host | 域名 |
| scheme | 协议类型(三种 all http https) |
| location | url路由 空则为不限制 |
| client\_id | 客户端id |
| target | 内网目标(ip:端口) |
| header | request header 请求头 |
| hostchange | request host 请求主机 |
| id | 需要修改的域名解析id |
***
删除域名解析
```
POST /index/delhost/
```
| 参数 | 含义 |
| --- | --- |
| id | 需要删除的域名解析id |
***
获取单条隧道信息
```
POST /index/getonetunnel/
```
| 参数 | 含义 |
| --- | --- |
| id | 隧道的id |
***
获取隧道列表
```
POST /index/gettunnel/
```
| 参数 | 含义 |
| --- | --- |
| client\_id | 穿透隧道的客户端id |
| type | 类型tcp udp httpProx socks5 secret p2p |
| search | 搜索 |
| offset | 分页(第几页) |
| limit | 条数(分页显示的条数) |
***
添加隧道
```
POST /index/add/
```
| 参数 | 含义 |
| --- | --- |
| type | 类型tcp udp httpProx socks5 secret p2p |
| remark | 备注 |
| port | 服务端端口 |
| target | 目标(ip:端口) |
| client\_id | 客户端id |
***
修改隧道
```
POST /index/edit/
```
| 参数 | 含义 |
| --- | --- |
| type | 类型tcp udp httpProx socks5 secret p2p |
| remark | 备注 |
| port | 服务端端口 |
| target | 目标(ip:端口) |
| client\_id | 客户端id |
| id | 隧道id |
***
删除隧道
```
POST /index/del/
```
| 参数 | 含义 |
| --- | --- |
| id | 隧道id |
***
隧道停止工作
```
POST /index/stop/
```
| 参数 | 含义 |
| --- | --- |
| id | 隧道id |
***
隧道开始工作
```
POST /index/start/
```
| 参数 | 含义 |
| --- | --- |
| id | 隧道id |

2
go.mod
View File

@ -1,4 +1,4 @@
module github.com/cnlh/nps module ehang.io/nps
go 1.13 go 1.13

View File

@ -2,7 +2,7 @@
<manifest <manifest
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1" android:versionCode="1"
android:versionName="0.25.4" android:versionName="0.26.0"
package="org.nps.client" package="org.nps.client"
platformBuildVersionCode="15" platformBuildVersionCode="15"
platformBuildVersionName="4.0.4-1406430"> platformBuildVersionName="4.0.4-1406430">

View File

@ -1,16 +1,16 @@
package main package main
import ( import (
"ehang.io/nps/client"
"ehang.io/nps/lib/common"
"ehang.io/nps/lib/daemon"
"ehang.io/nps/lib/version"
"fmt" "fmt"
"fyne.io/fyne" "fyne.io/fyne"
"fyne.io/fyne/app" "fyne.io/fyne/app"
"fyne.io/fyne/layout" "fyne.io/fyne/layout"
"fyne.io/fyne/widget" "fyne.io/fyne/widget"
"github.com/astaxie/beego/logs" "github.com/astaxie/beego/logs"
"github.com/cnlh/nps/client"
"github.com/cnlh/nps/lib/common"
"github.com/cnlh/nps/lib/daemon"
"github.com/cnlh/nps/lib/version"
"io/ioutil" "io/ioutil"
"os" "os"
"path" "path"

821
image/work_flow.svg Normal file
View File

@ -0,0 +1,821 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- 由 Microsoft Visio, SVG Export 生成 工作图.svg Page-1 -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="11.6929in" height="8.26772in"
viewBox="0 0 841.89 595.276" xml:space="preserve" color-interpolation-filters="sRGB" class="st17">
<v:documentProperties v:langID="2052" v:metric="true" v:viewMarkup="false">
<v:userDefs>
<v:ud v:nameU="msvNoAutoConnect" v:prompt="" v:val="VT0(0):26"/>
</v:userDefs>
</v:documentProperties>
<style type="text/css">
<![CDATA[
.st1 {fill:#5b9bd5;stroke:#ffffff;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.5}
.st2 {stroke:#ffffff;stroke-linecap:butt;stroke-width:0.5}
.st3 {fill:#1e4a73;font-family:Calibri;font-size:1.5em}
.st4 {fill:#aad288;stroke:#ffffff;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.5}
.st5 {fill:#ffffff}
.st6 {font-size:1em}
.st7 {fill:#5b9bd5}
.st8 {stroke:#ffffff;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.5}
.st9 {fill:#a5a5a5}
.st10 {marker-end:url(#mrkr4-135);marker-start:url(#mrkr4-133);stroke:#5592c9;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.5}
.st11 {fill:#5592c9;fill-opacity:1;stroke:#5592c9;stroke-opacity:1;stroke-width:0.37313432835821}
.st12 {fill:#ffffff;stroke:none;stroke-linecap:butt;stroke-width:7.2}
.st13 {fill:#41729d;font-family:Calibri;font-size:1.5em}
.st14 {fill:none;stroke:#42829e;stroke-dasharray:45,27;stroke-linecap:round;stroke-linejoin:round;stroke-width:3}
.st15 {fill:none;stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.5}
.st16 {fill:#5b9bd5;font-family:Calibri;font-size:1.99999em}
.st17 {fill:none;fill-rule:evenodd;font-size:12px;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
]]>
</style>
<defs id="Markers">
<g id="lend4">
<path d="M 2 1 L 0 0 L 2 -1 L 2 1 " style="stroke:none"/>
</g>
<marker id="mrkr4-133" class="st11" v:arrowType="4" v:arrowSize="2" v:setback="5.12" refX="5.12" orient="auto"
markerUnits="strokeWidth" overflow="visible">
<use xlink:href="#lend4" transform="scale(2.68) "/>
</marker>
<marker id="mrkr4-135" class="st11" v:arrowType="4" v:arrowSize="2" v:setback="5.36" refX="-5.36" orient="auto"
markerUnits="strokeWidth" overflow="visible">
<use xlink:href="#lend4" transform="scale(-2.68,-2.68) "/>
</marker>
</defs>
<g v:mID="0" v:index="1" v:groupContext="foregroundPage">
<v:userDefs>
<v:ud v:nameU="msvThemeOrder" v:val="VT0(0):26"/>
</v:userDefs>
<title>页-1</title>
<v:pageProperties v:drawingScale="0.0393701" v:pageScale="0.0393701" v:drawingUnits="24" v:shadowOffsetX="8.50394"
v:shadowOffsetY="-8.50394"/>
<v:layer v:name="连接线" v:index="0"/>
<g id="group1-1" transform="translate(418.11,-311.811)" v:mID="1" v:groupContext="group">
<v:custProps>
<v:cp v:nameU="AssetNumber" v:lbl="资产号" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="SerialNumber" v:lbl="序列号" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Location" v:lbl="位置" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Building" v:lbl="构建" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Room" v:lbl="空间" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false" v:ask="false"
v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Manufacturer" v:lbl="制造商" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="ProductNumber" v:lbl="产品编号" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="PartNumber" v:lbl="部件号" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="ProductDescription" v:lbl="产品说明" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(设备)"/>
<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(设备)"/>
<v:cp v:nameU="SubShapeType" v:lbl="SubShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(防火墙)"/>
</v:custProps>
<v:userDefs>
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
</v:userDefs>
<title>防火墙</title>
<desc>NAT</desc>
<g id="shape2-2" v:mID="2" v:groupContext="shape" transform="translate(0.545123,-7.63784)">
<title>工作表.2</title>
<rect x="0" y="539.685" width="69.7759" height="55.5905" class="st1"/>
</g>
<g id="shape3-4" v:mID="3" v:groupContext="shape" transform="translate(0.795123,-7.88784)">
<title>工作表.3</title>
<v:userDefs>
<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(1)"/>
<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(#5b9bd5)"/>
</v:userDefs>
<path d="M0 587.41 L69.28 587.41" class="st2"/>
<path d="M0 579.54 L69.28 579.54" class="st2"/>
<path d="M0 571.67 L69.28 571.67" class="st2"/>
<path d="M0 563.8 L69.28 563.8" class="st2"/>
<path d="M0 555.93 L69.28 555.93" class="st2"/>
<path d="M0 548.06 L69.28 548.06" class="st2"/>
<path d="M17.32 595.28 L17.32 587.41" class="st2"/>
<path d="M34.64 595.28 L34.64 587.41" class="st2"/>
<path d="M51.96 595.28 L51.96 587.41" class="st2"/>
<path d="M8.66 587.41 L8.66 579.54" class="st2"/>
<path d="M25.98 587.41 L25.98 579.54" class="st2"/>
<path d="M43.3 587.41 L43.3 579.54" class="st2"/>
<path d="M60.62 587.41 L60.62 579.54" class="st2"/>
<path d="M17.32 579.54 L17.32 571.67" class="st2"/>
<path d="M34.64 579.54 L34.64 571.67" class="st2"/>
<path d="M51.96 579.54 L51.96 571.67" class="st2"/>
<path d="M8.66 571.67 L8.66 563.8" class="st2"/>
<path d="M25.98 571.67 L25.98 563.8" class="st2"/>
<path d="M43.3 571.67 L43.3 563.8" class="st2"/>
<path d="M60.62 571.67 L60.62 563.8" class="st2"/>
<path d="M17.32 563.8 L17.32 555.93" class="st2"/>
<path d="M34.64 563.8 L34.64 555.93" class="st2"/>
<path d="M51.96 563.8 L51.96 555.93" class="st2"/>
<path d="M8.66 555.93 L8.66 548.06" class="st2"/>
<path d="M25.98 555.93 L25.98 548.06" class="st2"/>
<path d="M43.3 555.93 L43.3 548.06" class="st2"/>
<path d="M60.62 555.93 L60.62 548.06" class="st2"/>
<path d="M17.32 548.06 L17.32 540.19" class="st2"/>
<path d="M34.64 548.06 L34.64 540.19" class="st2"/>
<path d="M51.96 548.06 L51.96 540.19" class="st2"/>
</g>
<g id="shape1-36" v:mID="1" v:groupContext="groupContent">
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
<v:textRect cx="35.4331" cy="610.077" width="42.88" height="29.6036"/>
<text x="20.03" y="615.48" class="st3" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>NAT</text> </g>
</g>
<g id="group4-38" transform="translate(701.575,-311.811)" v:mID="4" v:groupContext="group">
<v:custProps>
<v:cp v:nameU="AssetNumber" v:lbl="资产号" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="SerialNumber" v:lbl="序列号" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Location" v:lbl="位置" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Building" v:lbl="构建" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Room" v:lbl="空间" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false" v:ask="false"
v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Manufacturer" v:lbl="制造商" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="ProductNumber" v:lbl="产品编号" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="PartNumber" v:lbl="部件号" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="ProductDescription" v:lbl="产品说明" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="NetworkName" v:lbl="网络名称" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="IPAddress" v:lbl="IP 地址" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="SubnetMask" v:lbl="子网掩码" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="AdminInterface" v:lbl="管理接口" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="NumberofPorts" v:lbl="端口数目" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="CommunityString" v:lbl="团体字符串" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="NetworkDescription" v:lbl="网络说明" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="MACAddress" v:lbl="MAC 地址" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="CPU" v:lbl="CPU" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Memory" v:lbl="内存" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="OperatingSystem" v:lbl="操作系统" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation"
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="HardDriveSize" v:lbl="硬盘容量" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation"
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Department" v:lbl="部门" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
v:langID="2052" v:cal="0"/>
<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(设备)"/>
<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(服务器)"/>
<v:cp v:nameU="BelongsTo" v:lbl="属于" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true" v:ask="false"
v:langID="2052" v:cal="0"/>
</v:custProps>
<v:userDefs>
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
</v:userDefs>
<title>服务器</title>
<desc>Application2 10.0.0.4:PORT</desc>
<g id="shape5-39" v:mID="5" v:groupContext="shape" transform="translate(12.8133,0)">
<title>工作表.5</title>
<rect x="0" y="524.409" width="45.2395" height="70.8661" class="st1"/>
</g>
<g id="shape6-41" v:mID="6" v:groupContext="shape" transform="translate(46.625,-30.2513)">
<title>工作表.6</title>
<ellipse cx="2.73472" cy="592.541" rx="2.73472" ry="2.73472" class="st4"/>
</g>
<g id="shape7-43" v:mID="7" v:groupContext="shape" transform="translate(30.0295,-11.6164)">
<title>工作表.7</title>
<v:userDefs>
<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(1)"/>
<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(#5b9bd5)"/>
</v:userDefs>
<path d="M-0 595.28 L22.06 595.28 L22.06 593.5 L-0 593.5 L-0 595.28 ZM-0 589.9 L22.06 589.9 L22.06 588.13 L-0 588.13
L-0 589.9 ZM-0 584.53 L22.06 584.53 L22.06 582.76 L-0 582.76 L-0 584.53 Z" class="st5"/>
</g>
<g id="shape4-46" v:mID="4" v:groupContext="groupContent">
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
<v:textRect cx="35.4331" cy="620.877" width="115.9" height="51.2036"/>
<text x="-10.6" y="615.48" class="st3" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>Application2<v:newlineChar/><tspan
x="-16.48" dy="1.2em" class="st6">10.0.0.4:PORT</tspan></text> </g>
</g>
<g id="group8-49" transform="translate(701.575,-496.063)" v:mID="8" v:groupContext="group">
<v:custProps>
<v:cp v:nameU="AssetNumber" v:lbl="资产号" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="SerialNumber" v:lbl="序列号" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Location" v:lbl="位置" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Building" v:lbl="构建" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Room" v:lbl="空间" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false" v:ask="false"
v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Manufacturer" v:lbl="制造商" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="ProductNumber" v:lbl="产品编号" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="PartNumber" v:lbl="部件号" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="ProductDescription" v:lbl="产品说明" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="NetworkName" v:lbl="网络名称" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="IPAddress" v:lbl="IP 地址" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="SubnetMask" v:lbl="子网掩码" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="AdminInterface" v:lbl="管理接口" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="NumberofPorts" v:lbl="端口数目" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="CommunityString" v:lbl="团体字符串" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="NetworkDescription" v:lbl="网络说明" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="MACAddress" v:lbl="MAC 地址" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="CPU" v:lbl="CPU" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Memory" v:lbl="内存" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="OperatingSystem" v:lbl="操作系统" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation"
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="HardDriveSize" v:lbl="硬盘容量" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation"
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Department" v:lbl="部门" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
v:langID="2052" v:cal="0"/>
<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(设备)"/>
<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(服务器)"/>
<v:cp v:nameU="BelongsTo" v:lbl="属于" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true" v:ask="false"
v:langID="2052" v:cal="0"/>
</v:custProps>
<v:userDefs>
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
</v:userDefs>
<title>服务器.8</title>
<desc>Application1 10.0.0.3:PORT</desc>
<g id="shape9-50" v:mID="9" v:groupContext="shape" transform="translate(12.8133,0)">
<title>工作表.9</title>
<rect x="0" y="524.409" width="45.2395" height="70.8661" class="st1"/>
</g>
<g id="shape10-52" v:mID="10" v:groupContext="shape" transform="translate(46.625,-30.2513)">
<title>工作表.10</title>
<ellipse cx="2.73472" cy="592.541" rx="2.73472" ry="2.73472" class="st4"/>
</g>
<g id="shape11-54" v:mID="11" v:groupContext="shape" transform="translate(30.0295,-11.6164)">
<title>工作表.11</title>
<v:userDefs>
<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(1)"/>
<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(#5b9bd5)"/>
</v:userDefs>
<path d="M-0 595.28 L22.06 595.28 L22.06 593.5 L-0 593.5 L-0 595.28 ZM-0 589.9 L22.06 589.9 L22.06 588.13 L-0 588.13
L-0 589.9 ZM-0 584.53 L22.06 584.53 L22.06 582.76 L-0 582.76 L-0 584.53 Z" class="st5"/>
</g>
<g id="shape8-57" v:mID="8" v:groupContext="groupContent">
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
<v:textRect cx="35.4331" cy="620.877" width="115.9" height="51.2036"/>
<text x="-10.6" y="615.48" class="st3" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>Application1<v:newlineChar/><tspan
x="-16.48" dy="1.2em" class="st6">10.0.0.3:PORT</tspan></text> </g>
</g>
<g id="group12-60" transform="translate(701.575,-127.559)" v:mID="12" v:groupContext="group">
<v:custProps>
<v:cp v:nameU="AssetNumber" v:lbl="资产号" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="SerialNumber" v:lbl="序列号" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Location" v:lbl="位置" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Building" v:lbl="构建" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Room" v:lbl="空间" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false" v:ask="false"
v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Manufacturer" v:lbl="制造商" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="ProductNumber" v:lbl="产品编号" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="PartNumber" v:lbl="部件号" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="ProductDescription" v:lbl="产品说明" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="NetworkName" v:lbl="网络名称" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="IPAddress" v:lbl="IP 地址" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="SubnetMask" v:lbl="子网掩码" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="AdminInterface" v:lbl="管理接口" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="NumberofPorts" v:lbl="端口数目" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="CommunityString" v:lbl="团体字符串" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="NetworkDescription" v:lbl="网络说明" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="MACAddress" v:lbl="MAC 地址" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="CPU" v:lbl="CPU" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Memory" v:lbl="内存" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="OperatingSystem" v:lbl="操作系统" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation"
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="HardDriveSize" v:lbl="硬盘容量" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation"
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Department" v:lbl="部门" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
v:langID="2052" v:cal="0"/>
<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(设备)"/>
<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(服务器)"/>
<v:cp v:nameU="BelongsTo" v:lbl="属于" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true" v:ask="false"
v:langID="2052" v:cal="0"/>
</v:custProps>
<v:userDefs>
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
</v:userDefs>
<title>服务器.12</title>
<desc>Application3 10.0.0.5:PORT</desc>
<g id="shape13-61" v:mID="13" v:groupContext="shape" transform="translate(12.8133,0)">
<title>工作表.13</title>
<rect x="0" y="524.409" width="45.2395" height="70.8661" class="st1"/>
</g>
<g id="shape14-63" v:mID="14" v:groupContext="shape" transform="translate(46.625,-30.2513)">
<title>工作表.14</title>
<ellipse cx="2.73472" cy="592.541" rx="2.73472" ry="2.73472" class="st4"/>
</g>
<g id="shape15-65" v:mID="15" v:groupContext="shape" transform="translate(30.0295,-11.6164)">
<title>工作表.15</title>
<v:userDefs>
<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(1)"/>
<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(#5b9bd5)"/>
</v:userDefs>
<path d="M-0 595.28 L22.06 595.28 L22.06 593.5 L-0 593.5 L-0 595.28 ZM-0 589.9 L22.06 589.9 L22.06 588.13 L-0 588.13
L-0 589.9 ZM-0 584.53 L22.06 584.53 L22.06 582.76 L-0 582.76 L-0 584.53 Z" class="st5"/>
</g>
<g id="shape12-68" v:mID="12" v:groupContext="groupContent">
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
<v:textRect cx="35.4331" cy="620.877" width="115.9" height="51.2036"/>
<text x="-10.6" y="615.48" class="st3" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>Application3<v:newlineChar/><tspan
x="-16.48" dy="1.2em" class="st6">10.0.0.5:PORT</tspan></text> </g>
</g>
<g id="group16-71" transform="translate(538.583,-311.811)" v:mID="16" v:groupContext="group">
<v:custProps>
<v:cp v:nameU="AssetNumber" v:lbl="资产号" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="SerialNumber" v:lbl="序列号" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Location" v:lbl="位置" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Building" v:lbl="建筑物" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Room" v:lbl="空间" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false" v:ask="false"
v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Manufacturer" v:lbl="制造商" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="ProductNumber" v:lbl="产品编号" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="PartNumber" v:lbl="部件号" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="ProductDescription" v:lbl="产品说明" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="NetworkName" v:lbl="网络名称" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="IPAddress" v:lbl="IP 地址" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="SubnetMask" v:lbl="子网掩码" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="AdminInterface" v:lbl="管理接口" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="NumberofPorts" v:lbl="端口数目" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="CommunityString" v:lbl="团体字符串" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="NetworkDescription" v:lbl="网络说明" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="MACAddress" v:lbl="MAC 地址" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(设备)"/>
<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(计算机)"/>
<v:cp v:nameU="SubShapeType" v:lbl="SubShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(大型机)"/>
</v:custProps>
<v:userDefs>
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
</v:userDefs>
<title>主机</title>
<desc>NPC Client 10.0.0.2 Dial To: -&#62;10.0.0.3:PORT -&#62;10.0.0.4:PORT ...</desc>
<g id="shape17-72" v:mID="17" v:groupContext="shape" transform="translate(5.68158,0)">
<title>工作表.17</title>
<path d="M0 595.28 L59.5 595.28 L59.5 524.41 L0 524.41 L0 595.28 Z" class="st7"/>
<path d="M0 595.28 L59.5 595.28 L59.5 524.41 L0 524.41 L0 595.28" class="st8"/>
<path d="M29.75 595.28 L29.75 524.41" class="st8"/>
</g>
<g id="shape18-76" v:mID="18" v:groupContext="shape" transform="translate(11.5726,-5.14536)">
<title>工作表.18</title>
<v:userDefs>
<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(1)"/>
<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(#5b9bd5)"/>
</v:userDefs>
<path d="M36.09 551.42 L49.23 551.42 L49.23 536.38 L36.09 536.38 L36.09 551.42 ZM14.89 542.47 L16.68 542.47 L16.68
536.06 L14.89 536.06 L14.89 542.47 ZM14.89 551.71 L16.68 551.71 L16.68 545.3 L14.89 545.3 L14.89 551.71
ZM10.63 542.47 L12.43 542.47 L12.43 536.06 L10.63 536.06 L10.63 542.47 ZM10.63 551.71 L12.43 551.71
L12.43 545.3 L10.63 545.3 L10.63 551.71 ZM4.25 542.47 L6.05 542.47 L6.05 536.06 L4.25 536.06 L4.25 542.47
ZM4.25 551.71 L6.05 551.71 L6.05 545.3 L4.25 545.3 L4.25 551.71 ZM0 542.47 L1.79 542.47 L1.79 536.06
L0 536.06 L0 542.47 ZM0 551.71 L1.79 551.71 L1.79 545.3 L0 545.3 L0 551.71 ZM33.82 586.45 L33.82 587.7
L49.39 587.69 L49.39 586.44 L33.82 586.45 ZM33.82 590.24 L33.82 591.49 L49.39 591.48 L49.39 590.24 L33.82
590.24 ZM33.82 594.03 L33.82 595.28 L49.39 595.27 L49.39 594.03 L33.82 594.03 ZM2.96 587.7 L18.52 587.7
L18.52 586.45 L2.95 586.45 L2.96 587.7 ZM2.96 591.49 L18.52 591.49 L18.52 590.24 L2.95 590.24 L2.96
591.49 ZM2.96 595.28 L18.52 595.28 L18.52 594.03 L2.95 594.03 L2.96 595.28 Z" class="st5"/>
</g>
<g id="shape19-79" v:mID="19" v:groupContext="shape" transform="translate(49.0815,-50.4059)">
<title>工作表.19</title>
<path d="M8.15 583.79 A1.11073 1.11073 -180 1 0 10.24 584.56 A1.11073 1.11073 -180 1 0 8.15 583.79 ZM8.17 587.08
A1.11073 1.11073 -180 1 0 10.22 587.93 A1.11073 1.11073 -180 1 0 8.17 587.08 ZM8.18 590.39 A1.11073
1.11073 -180 1 0 10.21 591.28 A1.11073 1.11073 -180 1 0 8.18 590.39 ZM8.18 593.71 A1.11073 1.11073 -180
1 0 10.21 594.6 A1.11073 1.11073 -180 1 0 8.18 593.71 ZM4.1 583.84 A1.11073 1.11073 -180 1 0 6.21 584.51
A1.11073 1.11073 -180 1 0 4.1 583.84 ZM4.11 587.14 A1.11073 1.11073 -180 1 0 6.2 587.87 A1.11073 1.11073
-180 1 0 4.11 587.14 ZM4.11 590.44 A1.11073 1.11073 -180 1 0 6.19 591.22 A1.11073 1.11073 -180 1 0 4.11
590.44 ZM4.11 593.77 A1.11073 1.11073 -180 1 0 6.19 594.55 A1.11073 1.11073 -180 1 0 4.11 593.77 ZM0.04
583.9 A1.11144 1.11144 -180 1 0 2.19 584.46 A1.11144 1.11144 -180 1 0 0.04 583.9 ZM0.05 587.19 A1.11144
1.11144 -180 1 0 2.18 587.82 A1.11144 1.11144 -180 1 0 0.05 587.19 ZM0.05 590.5 A1.11144 1.11144 -180
1 0 2.17 591.16 A1.11144 1.11144 -180 1 0 0.05 590.5 ZM0.05 593.83 A1.11144 1.11144 -180 1 0 2.17 594.49
A1.11144 1.11144 -180 1 0 0.05 593.83 Z" class="st9"/>
</g>
<g id="shape16-82" v:mID="16" v:groupContext="groupContent">
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
<v:textRect cx="35.4331" cy="674.877" width="130.38" height="159.204"/>
<text x="20.18" y="615.48" class="st3" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>NPC<v:newlineChar/><tspan
x="14.28" dy="1.2em" class="st6">Client<v:newlineChar/></tspan><tspan x="5.81" dy="1.2em" class="st6">10.0.0.2<v:newlineChar/></tspan><tspan
x="7.88" dy="1.2em" class="st6">Dial To:<v:newlineChar/></tspan><tspan x="-23.72" dy="1.2em"
class="st6">-</tspan>&#62;10.0.0.3:PORT<v:newlineChar/><tspan x="-23.72" dy="1.2em" class="st6">-</tspan>&#62;10.0.0.4:PORT<v:newlineChar/><tspan
x="-23.72" dy="1.2em" class="st6">-</tspan>&#62;10.0.0.5:PORT</text> </g>
</g>
<g id="group20-90" transform="translate(212.598,-311.811)" v:mID="20" v:groupContext="group">
<v:custProps>
<v:cp v:nameU="AssetNumber" v:lbl="资产号" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="SerialNumber" v:lbl="序列号" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Location" v:lbl="位置" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Building" v:lbl="建筑物" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Room" v:lbl="空间" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false" v:ask="false"
v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Manufacturer" v:lbl="制造商" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="ProductNumber" v:lbl="产品编号" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="PartNumber" v:lbl="部件号" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="ProductDescription" v:lbl="产品说明" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="NetworkName" v:lbl="网络名称" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="IPAddress" v:lbl="IP 地址" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="SubnetMask" v:lbl="子网掩码" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="AdminInterface" v:lbl="管理接口" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="NumberofPorts" v:lbl="端口数目" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="CommunityString" v:lbl="团体字符串" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="NetworkDescription" v:lbl="网络说明" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="MACAddress" v:lbl="MAC 地址" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
v:ask="false" v:langID="2052" v:cal="0"/>
<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(设备)"/>
<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(计算机)"/>
<v:cp v:nameU="SubShapeType" v:lbl="SubShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(大型机)"/>
</v:custProps>
<v:userDefs>
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
</v:userDefs>
<title>主机.20</title>
<desc>NPS Server 1.1.1.1 Listen On: 8003-&#62;10.0.0.3:PORT 8004-&#62;10.0....</desc>
<g id="shape21-91" v:mID="21" v:groupContext="shape" transform="translate(5.68158,0)">
<title>工作表.21</title>
<path d="M0 595.28 L59.5 595.28 L59.5 524.41 L0 524.41 L0 595.28 Z" class="st7"/>
<path d="M0 595.28 L59.5 595.28 L59.5 524.41 L0 524.41 L0 595.28" class="st8"/>
<path d="M29.75 595.28 L29.75 524.41" class="st8"/>
</g>
<g id="shape22-95" v:mID="22" v:groupContext="shape" transform="translate(11.5726,-5.14536)">
<title>工作表.22</title>
<v:userDefs>
<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(1)"/>
<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(#5b9bd5)"/>
</v:userDefs>
<path d="M36.09 551.42 L49.23 551.42 L49.23 536.38 L36.09 536.38 L36.09 551.42 ZM14.89 542.47 L16.68 542.47 L16.68
536.06 L14.89 536.06 L14.89 542.47 ZM14.89 551.71 L16.68 551.71 L16.68 545.3 L14.89 545.3 L14.89 551.71
ZM10.63 542.47 L12.43 542.47 L12.43 536.06 L10.63 536.06 L10.63 542.47 ZM10.63 551.71 L12.43 551.71
L12.43 545.3 L10.63 545.3 L10.63 551.71 ZM4.25 542.47 L6.05 542.47 L6.05 536.06 L4.25 536.06 L4.25 542.47
ZM4.25 551.71 L6.05 551.71 L6.05 545.3 L4.25 545.3 L4.25 551.71 ZM0 542.47 L1.79 542.47 L1.79 536.06
L0 536.06 L0 542.47 ZM0 551.71 L1.79 551.71 L1.79 545.3 L0 545.3 L0 551.71 ZM33.82 586.45 L33.82 587.7
L49.39 587.69 L49.39 586.44 L33.82 586.45 ZM33.82 590.24 L33.82 591.49 L49.39 591.48 L49.39 590.24 L33.82
590.24 ZM33.82 594.03 L33.82 595.28 L49.39 595.27 L49.39 594.03 L33.82 594.03 ZM2.96 587.7 L18.52 587.7
L18.52 586.45 L2.95 586.45 L2.96 587.7 ZM2.96 591.49 L18.52 591.49 L18.52 590.24 L2.95 590.24 L2.96
591.49 ZM2.96 595.28 L18.52 595.28 L18.52 594.03 L2.95 594.03 L2.96 595.28 Z" class="st5"/>
</g>
<g id="shape23-98" v:mID="23" v:groupContext="shape" transform="translate(49.0815,-50.4059)">
<title>工作表.23</title>
<path d="M8.15 583.79 A1.11073 1.11073 -180 1 0 10.24 584.56 A1.11073 1.11073 -180 1 0 8.15 583.79 ZM8.17 587.08
A1.11073 1.11073 -180 1 0 10.22 587.93 A1.11073 1.11073 -180 1 0 8.17 587.08 ZM8.18 590.39 A1.11073
1.11073 -180 1 0 10.21 591.28 A1.11073 1.11073 -180 1 0 8.18 590.39 ZM8.18 593.71 A1.11073 1.11073 -180
1 0 10.21 594.6 A1.11073 1.11073 -180 1 0 8.18 593.71 ZM4.1 583.84 A1.11073 1.11073 -180 1 0 6.21 584.51
A1.11073 1.11073 -180 1 0 4.1 583.84 ZM4.11 587.14 A1.11073 1.11073 -180 1 0 6.2 587.87 A1.11073 1.11073
-180 1 0 4.11 587.14 ZM4.11 590.44 A1.11073 1.11073 -180 1 0 6.19 591.22 A1.11073 1.11073 -180 1 0 4.11
590.44 ZM4.11 593.77 A1.11073 1.11073 -180 1 0 6.19 594.55 A1.11073 1.11073 -180 1 0 4.11 593.77 ZM0.04
583.9 A1.11144 1.11144 -180 1 0 2.19 584.46 A1.11144 1.11144 -180 1 0 0.04 583.9 ZM0.05 587.19 A1.11144
1.11144 -180 1 0 2.18 587.82 A1.11144 1.11144 -180 1 0 0.05 587.19 ZM0.05 590.5 A1.11144 1.11144 -180
1 0 2.17 591.16 A1.11144 1.11144 -180 1 0 0.05 590.5 ZM0.05 593.83 A1.11144 1.11144 -180 1 0 2.17 594.49
A1.11144 1.11144 -180 1 0 0.05 593.83 Z" class="st9"/>
</g>
<g id="shape20-101" v:mID="20" v:groupContext="groupContent">
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
<v:textRect cx="35.4331" cy="674.877" width="166.87" height="159.204"/>
<text x="20.84" y="615.48" class="st3" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>NPS<v:newlineChar/><tspan
x="12" dy="1.2em" class="st6">Server<v:newlineChar/></tspan><tspan x="10.37" dy="1.2em" class="st6">1.1.1.1<v:newlineChar/></tspan><tspan
x="-1.29" dy="1.2em" class="st6">Listen On:<v:newlineChar/></tspan><tspan x="-41.96" dy="1.2em"
class="st6">8003</tspan>-&#62;10.0.0.3:PORT<v:newlineChar/><tspan x="-41.96" dy="1.2em" class="st6">8004</tspan>-&#62;10.0.0.4:PORT<v:newlineChar/><tspan
x="-41.96" dy="1.2em" class="st6">8005</tspan>-&#62;10.0.0.5:PORT</text> </g>
</g>
<g id="group24-109" transform="translate(49.6063,-496.063)" v:mID="24" v:groupContext="group">
<v:custProps>
<v:cp v:nameU="Name" v:lbl="名称" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Location" v:lbl="位置" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Building" v:lbl="构建" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Room" v:lbl="空间" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Department" v:lbl="部门" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
v:langID="2052" v:cal="0"/>
<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(连接性)"/>
<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(用户)"/>
</v:custProps>
<v:userDefs>
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
</v:userDefs>
<title>用户</title>
<desc>User1 Wants:APP1</desc>
<g id="shape25-110" v:mID="25" v:groupContext="shape" transform="translate(18.0575,0)">
<title>工作表.25</title>
<path d="M26.29 533.22 A8.81 8.81 -180 1 0 8.67 533.22 A8.81 8.81 -180 1 0 26.29 533.22 ZM27.58 544.41 L7.17 544.41
C3.22 544.41 0 547.62 0 551.58 L0 576.58 L5.59 576.58 L5.59 562.03 L7.45 562.03 L7.45 595.28 L16.55
595.28 L16.55 580.42 C16.55 579.9 16.97 579.48 17.48 579.48 C18 579.48 18.42 579.9 18.42 580.42 L18.42
595.28 L28.04 595.28 L28.04 561.98 L29.91 561.98 L29.91 576.58 L34.75 576.58 L34.75 551.58 C34.75 547.62
31.54 544.41 27.58 544.41 Z" class="st1"/>
</g>
<g id="shape24-112" v:mID="24" v:groupContext="groupContent">
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
<v:textRect cx="35.4331" cy="620.877" width="102.19" height="51.2036"/>
<text x="13.96" y="615.48" class="st3" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>User1<v:newlineChar/><tspan
x="-9.62" dy="1.2em" class="st6">Wants:APP1</tspan></text> </g>
</g>
<g id="group26-115" transform="translate(49.6063,-311.811)" v:mID="26" v:groupContext="group">
<v:custProps>
<v:cp v:nameU="Name" v:lbl="名称" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Location" v:lbl="位置" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Building" v:lbl="构建" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Room" v:lbl="空间" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Department" v:lbl="部门" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
v:langID="2052" v:cal="0"/>
<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(连接性)"/>
<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(用户)"/>
</v:custProps>
<v:userDefs>
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
</v:userDefs>
<title>用户.26</title>
<desc>User2 Wants:APP2</desc>
<g id="shape27-116" v:mID="27" v:groupContext="shape" transform="translate(18.0575,0)">
<title>工作表.27</title>
<path d="M26.29 533.22 A8.81 8.81 -180 1 0 8.67 533.22 A8.81 8.81 -180 1 0 26.29 533.22 ZM27.58 544.41 L7.17 544.41
C3.22 544.41 0 547.62 0 551.58 L0 576.58 L5.59 576.58 L5.59 562.03 L7.45 562.03 L7.45 595.28 L16.55
595.28 L16.55 580.42 C16.55 579.9 16.97 579.48 17.48 579.48 C18 579.48 18.42 579.9 18.42 580.42 L18.42
595.28 L28.04 595.28 L28.04 561.98 L29.91 561.98 L29.91 576.58 L34.75 576.58 L34.75 551.58 C34.75 547.62
31.54 544.41 27.58 544.41 Z" class="st1"/>
</g>
<g id="shape26-118" v:mID="26" v:groupContext="groupContent">
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
<v:textRect cx="35.4331" cy="620.877" width="102.19" height="51.2036"/>
<text x="13.96" y="615.48" class="st3" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>User2<v:newlineChar/><tspan
x="-9.62" dy="1.2em" class="st6">Wants:APP2</tspan></text> </g>
</g>
<g id="group28-121" transform="translate(49.6063,-127.559)" v:mID="28" v:groupContext="group">
<v:custProps>
<v:cp v:nameU="Name" v:lbl="名称" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Location" v:lbl="位置" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Building" v:lbl="构建" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Room" v:lbl="空间" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
v:langID="2052" v:cal="0"/>
<v:cp v:nameU="Department" v:lbl="部门" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
v:langID="2052" v:cal="0"/>
<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(连接性)"/>
<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(用户)"/>
</v:custProps>
<v:userDefs>
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
</v:userDefs>
<title>用户.28</title>
<desc>User3 Wants:APP3</desc>
<g id="shape29-122" v:mID="29" v:groupContext="shape" transform="translate(18.0575,0)">
<title>工作表.29</title>
<path d="M26.29 533.22 A8.81 8.81 -180 1 0 8.67 533.22 A8.81 8.81 -180 1 0 26.29 533.22 ZM27.58 544.41 L7.17 544.41
C3.22 544.41 0 547.62 0 551.58 L0 576.58 L5.59 576.58 L5.59 562.03 L7.45 562.03 L7.45 595.28 L16.55
595.28 L16.55 580.42 C16.55 579.9 16.97 579.48 17.48 579.48 C18 579.48 18.42 579.9 18.42 580.42 L18.42
595.28 L28.04 595.28 L28.04 561.98 L29.91 561.98 L29.91 576.58 L34.75 576.58 L34.75 551.58 C34.75 547.62
31.54 544.41 27.58 544.41 Z" class="st1"/>
</g>
<g id="shape28-124" v:mID="28" v:groupContext="groupContent">
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
<v:textRect cx="35.4331" cy="620.877" width="102.19" height="51.2036"/>
<text x="13.96" y="615.48" class="st3" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>User3<v:newlineChar/><tspan
x="-9.62" dy="1.2em" class="st6">Wants:APP3</tspan></text> </g>
</g>
<g id="shape1003-127" v:mID="1003" v:groupContext="shape" v:layerMember="0" transform="translate(99.8466,-514.757)">
<title>动态连接线.1003</title>
<desc>-&#62;8003 Multi Conn</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
<v:textRect cx="56.059" cy="684.836" width="93.29" height="51.2036"/>
<path d="M5.09 601.03 L5.33 601.3 L113.11 723.13" class="st10"/>
<rect v:rectContext="textBkgnd" x="15.4535" y="663.236" width="81.2109" height="43.1999" class="st12"/>
<text x="30.58" y="679.44" class="st13" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>-&#62;8003<v:newlineChar/><tspan
x="15.45" dy="1.2em" class="st6">Multi Conn</tspan></text> </g>
<g id="shape1004-139" v:mID="1004" v:groupContext="shape" v:layerMember="0" transform="translate(102.415,-340.157)">
<title>动态连接线.1004</title>
<desc>-&#62;8004 Multi Conn</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
<v:textRect cx="57.9325" cy="588.189" width="93.29" height="51.2036"/>
<path d="M7.68 588.19 L8.04 588.19 L107.83 588.19" class="st10"/>
<rect v:rectContext="textBkgnd" x="17.327" y="566.589" width="81.2109" height="43.1999" class="st12"/>
<text x="32.45" y="582.79" class="st13" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>-&#62;8004<v:newlineChar/><tspan
x="17.33" dy="1.2em" class="st6">Multi Conn</tspan></text> </g>
<g id="shape1005-149" v:mID="1005" v:groupContext="shape" v:layerMember="0" transform="translate(98.1493,-177.812)">
<title>动态连接线.1005</title>
<desc>-&#62;8005 Multi Conn</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
<v:textRect cx="60.0654" cy="527.376" width="93.29" height="51.2036"/>
<path d="M5.09 589.52 L5.33 589.25 L114.8 465.5" class="st10"/>
<rect v:rectContext="textBkgnd" x="19.4599" y="505.776" width="81.2109" height="43.1999" class="st12"/>
<text x="34.58" y="521.98" class="st13" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>-&#62;8005<v:newlineChar/><tspan
x="19.46" dy="1.2em" class="st6">Multi Conn</tspan></text> </g>
<g id="shape1006-159" v:mID="1006" v:groupContext="shape" v:layerMember="0" transform="translate(277.783,-354.331)">
<title>动态连接线.1006</title>
<desc>NPS &#38; NPC Multiplexing Connection TCP or KCP Only One Conn Pe...</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
<v:textRect cx="70.4362" cy="602.362" width="103.62" height="159.204"/>
<path d="M7.68 602.36 L8.04 602.36 L132.83 602.36" class="st10"/>
<rect v:rectContext="textBkgnd" x="24.6671" y="526.762" width="91.5381" height="151.2" class="st12"/>
<text x="30.38" y="542.96" class="st13" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>NPS &#38; NPC<v:newlineChar/><tspan
x="24.67" dy="1.2em" class="st6">Multiplexing<v:newlineChar/></tspan><tspan x="28.6" dy="1.2em" class="st6">Connection<v:newlineChar/></tspan><tspan
x="30.53" dy="1.2em" class="st6">TCP or KCP<v:newlineChar/></tspan><tspan x="36.41" dy="1.2em" class="st6">Only One<v:newlineChar/></tspan><tspan
x="32.66" dy="1.2em" class="st6">Conn Peer<v:newlineChar/></tspan><tspan x="55.18" dy="1.2em" class="st6">NPC</tspan></text> </g>
<g id="shape1007-174" v:mID="1007" v:groupContext="shape" v:layerMember="0" transform="translate(603.767,-380.876)">
<title>动态连接线.1007</title>
<desc>-&#62;PORT Multi Conn</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
<v:textRect cx="55.0044" cy="550.955" width="93.29" height="51.2036"/>
<path d="M5.09 589.52 L5.33 589.25 L105.29 476.25" class="st10"/>
<rect v:rectContext="textBkgnd" x="14.3989" y="529.355" width="81.2109" height="43.1999" class="st12"/>
<text x="27.89" y="545.56" class="st13" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>-&#62;PORT<v:newlineChar/><tspan
x="14.4" dy="1.2em" class="st6">Multi Conn</tspan></text> </g>
<g id="shape1008-184" v:mID="1008" v:groupContext="shape" v:layerMember="0" transform="translate(603.767,-340.157)">
<title>动态连接线.1008</title>
<desc>-&#62;PORT Multi Conn</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
<v:textRect cx="55.3104" cy="588.189" width="93.29" height="51.2036"/>
<path d="M7.68 588.19 L8.04 588.19 L102.58 588.19" class="st10"/>
<rect v:rectContext="textBkgnd" x="14.7049" y="566.589" width="81.2109" height="43.1999" class="st12"/>
<text x="28.19" y="582.79" class="st13" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>-&#62;PORT<v:newlineChar/><tspan
x="14.7" dy="1.2em" class="st6">Multi Conn</tspan></text> </g>
<g id="shape1009-194" v:mID="1009" v:groupContext="shape" v:layerMember="0" transform="translate(603.767,-313.612)">
<title>动态连接线.1009</title>
<desc>-&#62;PORT Multi Conn</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
<v:textRect cx="68.0438" cy="667.943" width="93.29" height="51.2036"/>
<path d="M5.09 601.03 L5.33 601.3 L105.29 714.3" class="st10"/>
<rect v:rectContext="textBkgnd" x="27.4383" y="646.343" width="81.2109" height="43.1999" class="st12"/>
<text x="40.93" y="662.54" class="st13" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>-&#62;PORT<v:newlineChar/><tspan
x="27.44" dy="1.2em" class="st6">Multi Conn</tspan></text> </g>
<g id="shape1010-204" v:mID="1010" v:groupContext="shape" v:layerMember="0" transform="translate(488.431,-340.157)">
<title>动态连接线.1010</title>
<desc>NPS &#38; NPC</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
<v:textRect cx="27.9165" cy="588.189" width="90" height="72.8036"/>
<path d="M7.68 588.19 L8.04 588.19 L47.79 588.19" class="st10"/>
<rect v:rectContext="textBkgnd" x="12.6587" y="555.789" width="30.5156" height="64.7998" class="st12"/>
<text x="13.32" y="571.99" class="st13" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>NPS<v:newlineChar/><tspan
x="21.78" dy="1.2em" class="st6">&#38;<v:newlineChar/></tspan><tspan x="12.66" dy="1.2em" class="st6">NPC</tspan></text> </g>
<g id="shape1011-215" v:mID="1011" v:groupContext="shape" transform="translate(34.0157,-62.8844)">
<title>工作表.1011</title>
<path d="M0 595.28 L398.27 595.28 L398.27 85.04 L0 85.04 L0 595.28 Z" class="st14"/>
</g>
<g id="shape1012-217" v:mID="1012" v:groupContext="shape" transform="translate(473.386,-62.8844)">
<title>工作表.1012</title>
<path d="M0 595.28 L320.31 595.28 L320.31 85.04 L0 85.04 L0 595.28 Z" class="st14"/>
</g>
<g id="shape1013-219" v:mID="1013" v:groupContext="shape" transform="translate(255.118,-496.063)">
<title>工作表.1013</title>
<desc>Internet</desc>
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
<v:textRect cx="63.7795" cy="559.843" width="127.56" height="70.8661"/>
<rect x="0" y="524.409" width="127.559" height="70.8661" class="st15"/>
<text x="23.98" y="567.04" class="st16" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>Internet</text> </g>
<g id="shape1014-222" v:mID="1014" v:groupContext="shape" transform="translate(517.323,-515.866)">
<title>工作表.1014</title>
<desc>Intranet</desc>
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
<v:textRect cx="76" cy="579.646" width="152.01" height="31.2598"/>
<rect x="0" y="564.016" width="152" height="31.2598" class="st15"/>
<text x="36.43" y="586.85" class="st16" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>Intranet</text> </g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 58 KiB

View File

@ -49,6 +49,6 @@ const (
MUX_PING_RETURN MUX_PING_RETURN
MUX_PING int32 = -1 MUX_PING int32 = -1
MAXIMUM_SEGMENT_SIZE = PoolSizeWindow MAXIMUM_SEGMENT_SIZE = PoolSizeWindow
MAXIMUM_WINDOW_SIZE = 1 << 25 // 1<<31-1 TCP slide window size is very large, MAXIMUM_WINDOW_SIZE = 1 << 27 // 1<<31-1 TCP slide window size is very large,
// we use 32M, reduce memory usage // we use 128M, reduce memory usage
) )

View File

@ -162,10 +162,9 @@ func (Self *ConnPackager) UnPack(reader io.Reader) (n uint16, err error) {
} }
type MuxPackager struct { type MuxPackager struct {
Flag uint8 Flag uint8
Id int32 Id int32
Window uint32 Window uint64
ReadLength uint32
BasePackager BasePackager
} }
@ -178,19 +177,8 @@ func (Self *MuxPackager) NewPac(flag uint8, id int32, content ...interface{}) (e
err = Self.BasePackager.NewPac(content...) err = Self.BasePackager.NewPac(content...)
//logs.Warn(Self.Length, string(Self.Content)) //logs.Warn(Self.Length, string(Self.Content))
case MUX_MSG_SEND_OK: case MUX_MSG_SEND_OK:
// MUX_MSG_SEND_OK contains two data // MUX_MSG_SEND_OK contains one data
switch content[0].(type) { Self.Window = content[0].(uint64)
case int:
Self.Window = uint32(content[0].(int))
case uint32:
Self.Window = content[0].(uint32)
}
switch content[1].(type) {
case int:
Self.ReadLength = uint32(content[1].(int))
case uint32:
Self.ReadLength = content[1].(uint32)
}
} }
return return
} }
@ -210,10 +198,6 @@ func (Self *MuxPackager) Pack(writer io.Writer) (err error) {
WindowBuff.Put(Self.Content) WindowBuff.Put(Self.Content)
case MUX_MSG_SEND_OK: case MUX_MSG_SEND_OK:
err = binary.Write(writer, binary.LittleEndian, Self.Window) err = binary.Write(writer, binary.LittleEndian, Self.Window)
if err != nil {
return
}
err = binary.Write(writer, binary.LittleEndian, Self.ReadLength)
} }
return return
} }
@ -235,12 +219,7 @@ func (Self *MuxPackager) UnPack(reader io.Reader) (n uint16, err error) {
//logs.Warn("unpack", Self.Length, string(Self.Content)) //logs.Warn("unpack", Self.Length, string(Self.Content))
case MUX_MSG_SEND_OK: case MUX_MSG_SEND_OK:
err = binary.Read(reader, binary.LittleEndian, &Self.Window) err = binary.Read(reader, binary.LittleEndian, &Self.Window)
if err != nil { n += 8 // uint64
return
}
n += 4 // uint32
err = binary.Read(reader, binary.LittleEndian, &Self.ReadLength)
n += 4 // uint32
} }
n += 5 //uint8 int32 n += 5 //uint8 int32
return return
@ -251,7 +230,6 @@ func (Self *MuxPackager) reset() {
Self.Flag = 0 Self.Flag = 0
Self.Length = 0 Self.Length = 0
Self.Content = nil Self.Content = nil
Self.ReadLength = 0
Self.Window = 0 Self.Window = 0
} }

View File

@ -16,7 +16,7 @@ import (
"strings" "strings"
"sync" "sync"
"github.com/cnlh/nps/lib/crypt" "ehang.io/nps/lib/crypt"
) )
//Get the corresponding IP address through domain name //Get the corresponding IP address through domain name

View File

@ -6,8 +6,8 @@ import (
"regexp" "regexp"
"strings" "strings"
"github.com/cnlh/nps/lib/common" "ehang.io/nps/lib/common"
"github.com/cnlh/nps/lib/file" "ehang.io/nps/lib/file"
) )
type CommonConfig struct { type CommonConfig struct {
@ -241,7 +241,7 @@ func dealTunnel(s string) *file.Tunnel {
t.StripPre = item[1] t.StripPre = item[1]
case "multi_account": case "multi_account":
t.MultiAccount = &file.MultiAccount{} t.MultiAccount = &file.MultiAccount{}
if common.FileExists(item[1]){ if common.FileExists(item[1]) {
if b, err := common.ReadAllFromFile(item[1]); err != nil { if b, err := common.ReadAllFromFile(item[1]); err != nil {
panic(err) panic(err)
} else { } else {

View File

@ -3,11 +3,11 @@ package conn
import ( import (
"bufio" "bufio"
"bytes" "bytes"
"ehang.io/nps/lib/goroutine"
"encoding/binary" "encoding/binary"
"encoding/json" "encoding/json"
"errors" "errors"
"github.com/astaxie/beego/logs" "github.com/astaxie/beego/logs"
"github.com/cnlh/nps/lib/goroutine"
"io" "io"
"net" "net"
"net/http" "net/http"
@ -16,11 +16,11 @@ import (
"strings" "strings"
"time" "time"
"github.com/cnlh/nps/lib/common" "ehang.io/nps/lib/common"
"github.com/cnlh/nps/lib/crypt" "ehang.io/nps/lib/crypt"
"github.com/cnlh/nps/lib/file" "ehang.io/nps/lib/file"
"github.com/cnlh/nps/lib/mux" "ehang.io/nps/lib/mux"
"github.com/cnlh/nps/lib/rate" "ehang.io/nps/lib/rate"
"github.com/xtaci/kcp-go" "github.com/xtaci/kcp-go"
) )

View File

@ -9,7 +9,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/cnlh/nps/lib/common" "ehang.io/nps/lib/common"
) )
func InitDaemon(f string, runPath string, pidPath string) { func InitDaemon(f string, runPath string, pidPath string) {

View File

@ -8,8 +8,8 @@ import (
"path/filepath" "path/filepath"
"syscall" "syscall"
"ehang.io/nps/lib/common"
"github.com/astaxie/beego" "github.com/astaxie/beego"
"github.com/cnlh/nps/lib/common"
) )
func init() { func init() {

View File

@ -9,9 +9,9 @@ import (
"strings" "strings"
"sync" "sync"
"github.com/cnlh/nps/lib/common" "ehang.io/nps/lib/common"
"github.com/cnlh/nps/lib/crypt" "ehang.io/nps/lib/crypt"
"github.com/cnlh/nps/lib/rate" "ehang.io/nps/lib/rate"
) )
type DbUtils struct { type DbUtils struct {

View File

@ -9,8 +9,8 @@ import (
"sync" "sync"
"sync/atomic" "sync/atomic"
"github.com/cnlh/nps/lib/common" "ehang.io/nps/lib/common"
"github.com/cnlh/nps/lib/rate" "ehang.io/nps/lib/rate"
) )
func NewJsonDb(runPath string) *JsonDb { func NewJsonDb(runPath string) *JsonDb {

View File

@ -6,7 +6,7 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"github.com/cnlh/nps/lib/rate" "ehang.io/nps/lib/rate"
"github.com/pkg/errors" "github.com/pkg/errors"
) )

View File

@ -1,8 +1,8 @@
package goroutine package goroutine
import ( import (
"github.com/cnlh/nps/lib/common" "ehang.io/nps/lib/common"
"github.com/cnlh/nps/lib/file" "ehang.io/nps/lib/file"
"github.com/panjf2000/ants/v2" "github.com/panjf2000/ants/v2"
"io" "io"
"net" "net"

View File

@ -1,11 +1,11 @@
package install package install
import ( import (
"ehang.io/nps/lib/common"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"github.com/c4milo/unpackit" "github.com/c4milo/unpackit"
"github.com/cnlh/nps/lib/common"
"io" "io"
"io/ioutil" "io/ioutil"
"log" "log"
@ -50,7 +50,7 @@ func downloadLatest(bin string) string {
fmt.Println("the latest version is", version) fmt.Println("the latest version is", version)
filename := runtime.GOOS + "_" + runtime.GOARCH + "_" + bin + ".tar.gz" filename := runtime.GOOS + "_" + runtime.GOARCH + "_" + bin + ".tar.gz"
// download latest package // download latest package
downloadUrl := fmt.Sprintf("https://github.com/cnlh/nps/releases/download/%s/%s", version, filename) downloadUrl := fmt.Sprintf("https://ehang.io/nps/releases/download/%s/%s", version, filename)
fmt.Println("download package from ", downloadUrl) fmt.Println("download package from ", downloadUrl)
resp, err := http.Get(downloadUrl) resp, err := http.Get(downloadUrl)
if err != nil { if err != nil {

View File

@ -1,6 +1,7 @@
package mux package mux
import ( import (
"ehang.io/nps/lib/common"
"errors" "errors"
"github.com/astaxie/beego/logs" "github.com/astaxie/beego/logs"
"io" "io"
@ -10,8 +11,6 @@ import (
"sync" "sync"
"sync/atomic" "sync/atomic"
"time" "time"
"github.com/cnlh/nps/lib/common"
) )
type conn struct { type conn struct {
@ -146,25 +145,44 @@ func (s *conn) SetWriteDeadline(t time.Time) error {
} }
type window struct { type window struct {
remainingWait uint64 // 64bit alignment maxSizeDone uint64
off uint32 // 64bit alignment
maxSize uint32 // maxSizeDone contains 4 parts
closeOp bool // 1 31 1 31
closeOpCh chan struct{} // wait maxSize useless done
mux *Mux // wait zero means false, one means true
off uint32
closeOp bool
closeOpCh chan struct{}
mux *Mux
} }
func (Self *window) unpack(ptrs uint64) (remaining, wait uint32) { const windowBits = 31
const mask = 1<<dequeueBits - 1 const waitBits = dequeueBits + windowBits
remaining = uint32((ptrs >> dequeueBits) & mask) const mask1 = 1
wait = uint32(ptrs & mask) const mask31 = 1<<windowBits - 1
func (Self *window) unpack(ptrs uint64) (maxSize, done uint32, wait bool) {
maxSize = uint32((ptrs >> dequeueBits) & mask31)
done = uint32(ptrs & mask31)
//logs.Warn("unpack", maxSize, done)
if ((ptrs >> waitBits) & mask1) == 1 {
wait = true
return
}
return return
} }
func (Self *window) pack(remaining, wait uint32) uint64 { func (Self *window) pack(maxSize, done uint32, wait bool) uint64 {
const mask = 1<<dequeueBits - 1 //logs.Warn("pack", maxSize, done, wait)
return (uint64(remaining) << dequeueBits) | if wait {
uint64(wait&mask) return (uint64(1)<<waitBits |
uint64(maxSize&mask31)<<dequeueBits) |
uint64(done&mask31)
}
return (uint64(0)<<waitBits |
uint64(maxSize&mask31)<<dequeueBits) |
uint64(done&mask31)
} }
func (Self *window) New() { func (Self *window) New() {
@ -184,21 +202,25 @@ type ReceiveWindow struct {
bufQueue ReceiveWindowQueue bufQueue ReceiveWindowQueue
element *common.ListElement element *common.ListElement
count int8 count int8
bw *writeBandwidth
once sync.Once once sync.Once
// receive window send the current max size and read size to send window
// means done size actually store the size receive window has read
} }
func (Self *ReceiveWindow) New(mux *Mux) { func (Self *ReceiveWindow) New(mux *Mux) {
// initial a window for receive // initial a window for receive
Self.bufQueue.New() Self.bufQueue.New()
Self.element = common.ListElementPool.Get() Self.element = common.ListElementPool.Get()
Self.maxSize = common.MAXIMUM_SEGMENT_SIZE * 10 Self.maxSizeDone = Self.pack(common.MAXIMUM_SEGMENT_SIZE*30, 0, false)
Self.mux = mux Self.mux = mux
Self.window.New() Self.window.New()
Self.bw = NewWriteBandwidth()
} }
func (Self *ReceiveWindow) remainingSize(delta uint16) (n uint32) { func (Self *ReceiveWindow) remainingSize(maxSize uint32, delta uint16) (n uint32) {
// receive window remaining // receive window remaining
l := int64(atomic.LoadUint32(&Self.maxSize)) - int64(Self.bufQueue.Len()) l := int64(maxSize) - int64(Self.bufQueue.Len())
l -= int64(delta) l -= int64(delta)
if l > 0 { if l > 0 {
n = uint32(l) n = uint32(l)
@ -210,30 +232,46 @@ func (Self *ReceiveWindow) calcSize() {
// calculating maximum receive window size // calculating maximum receive window size
if Self.count == 0 { if Self.count == 0 {
//logs.Warn("ping, bw", Self.mux.latency, Self.bw.Get()) //logs.Warn("ping, bw", Self.mux.latency, Self.bw.Get())
conns := Self.mux.connMap.Size() //conns := Self.mux.connMap.Size()
n := uint32(math.Float64frombits(atomic.LoadUint64(&Self.mux.latency)) * muxBw := Self.mux.bw.Get()
Self.mux.bw.Get() / float64(conns)) connBw := Self.bw.Get()
if n < common.MAXIMUM_SEGMENT_SIZE*10 { //logs.Warn("muxbw connbw", muxBw, connBw)
n = common.MAXIMUM_SEGMENT_SIZE * 10 var n uint32
if connBw > 0 && muxBw > 0 {
n = uint32(math.Float64frombits(atomic.LoadUint64(&Self.mux.latency)) *
(muxBw + connBw))
} }
//bufLen := Self.bufQueue.Len() //logs.Warn(n)
//if n < bufLen { if n < common.MAXIMUM_SEGMENT_SIZE*30 {
// n = bufLen //logs.Warn("window small", n, Self.mux.bw.Get(), Self.bw.Get())
//} n = common.MAXIMUM_SEGMENT_SIZE * 30
if n < Self.maxSize/2 {
n = Self.maxSize / 2
} }
// set the minimal size for {
if n > 2*Self.maxSize { ptrs := atomic.LoadUint64(&Self.maxSizeDone)
n = 2 * Self.maxSize size, read, wait := Self.unpack(ptrs)
if n < size/2 {
n = size / 2
// half reduce
}
// set the minimal size
if n > 2*size {
n = 2 * size
// twice grow
}
if connBw > 0 && muxBw > 0 {
limit := uint32(common.MAXIMUM_WINDOW_SIZE * (connBw / (muxBw + connBw)))
if n > limit {
logs.Warn("window too large, calculated:", n, "limit:", limit, connBw, muxBw)
n = limit
}
}
// set the maximum size
//logs.Warn("n", n)
if atomic.CompareAndSwapUint64(&Self.maxSizeDone, ptrs, Self.pack(n, read, wait)) {
// only change the maxSize
break
}
} }
if n > (common.MAXIMUM_WINDOW_SIZE / uint32(conns)) {
logs.Warn("window too large", n)
n = common.MAXIMUM_WINDOW_SIZE / uint32(conns)
}
// set the maximum size
//logs.Warn("n", n)
atomic.StoreUint32(&Self.maxSize, n)
Self.count = -10 Self.count = -10
} }
Self.count += 1 Self.count += 1
@ -245,30 +283,40 @@ func (Self *ReceiveWindow) Write(buf []byte, l uint16, part bool, id int32) (err
return errors.New("conn.receiveWindow: write on closed window") return errors.New("conn.receiveWindow: write on closed window")
} }
element, err := NewListElement(buf, l, part) element, err := NewListElement(buf, l, part)
//logs.Warn("push the buf", len(buf), l, (&element).l) //logs.Warn("push the buf", len(buf), l, element.L)
if err != nil { if err != nil {
return return
} }
Self.calcSize() // calculate the max window size Self.calcSize() // calculate the max window size
var wait uint32 var wait bool
var maxSize, read uint32
start: start:
ptrs := atomic.LoadUint64(&Self.remainingWait) ptrs := atomic.LoadUint64(&Self.maxSizeDone)
_, wait = Self.unpack(ptrs) maxSize, read, wait = Self.unpack(ptrs)
newRemaining := Self.remainingSize(l) remain := Self.remainingSize(maxSize, l)
// calculate the remaining window size now, plus the element we will push // calculate the remaining window size now, plus the element we will push
if newRemaining == 0 { if remain == 0 && !wait {
//logs.Warn("window full true", remaining) //logs.Warn("window full true", remaining)
wait = 1 wait = true
} if !atomic.CompareAndSwapUint64(&Self.maxSizeDone, ptrs, Self.pack(maxSize, read, wait)) {
if !atomic.CompareAndSwapUint64(&Self.remainingWait, ptrs, Self.pack(0, wait)) { // only change the wait status, not send the read size
goto start goto start
// another goroutine change the status, make sure shall we need wait // another goroutine change the status, make sure shall we need wait
} }
//logs.Warn("receive window full")
} else if !wait {
if !atomic.CompareAndSwapUint64(&Self.maxSizeDone, ptrs, Self.pack(maxSize, 0, wait)) {
// reset read size here, and send the read size directly
goto start
// another goroutine change the status, make sure shall we need wait
}
} // maybe there are still some data received even if window is full, just keep the wait status
// and push into queue. when receive window read enough, send window will be acknowledged.
Self.bufQueue.Push(element) Self.bufQueue.Push(element)
// status check finish, now we can push the element into the queue // status check finish, now we can push the element into the queue
if wait == 0 { if !wait {
Self.mux.sendInfo(common.MUX_MSG_SEND_OK, id, Self.maxSize, newRemaining) Self.mux.sendInfo(common.MUX_MSG_SEND_OK, id, Self.pack(maxSize, read, false))
// send the remaining window size, not including zero size // send the current status to send window
} }
return nil return nil
} }
@ -277,9 +325,16 @@ func (Self *ReceiveWindow) Read(p []byte, id int32) (n int, err error) {
if Self.closeOp { if Self.closeOp {
return 0, io.EOF // receive close signal, returns eof return 0, io.EOF // receive close signal, returns eof
} }
Self.bw.StartRead()
n, err = Self.readFromQueue(p, id)
Self.bw.SetCopySize(uint16(n))
return
}
func (Self *ReceiveWindow) readFromQueue(p []byte, id int32) (n int, err error) {
pOff := 0 pOff := 0
l := 0 l := 0
//logs.Warn("receive window read off, element.l", Self.off, Self.element.l) //logs.Warn("receive window read off, element.l", Self.off, Self.element.L)
copyData: copyData:
if Self.off == uint32(Self.element.L) { if Self.off == uint32(Self.element.L) {
// on the first Read method invoked, Self.off and Self.element.l // on the first Read method invoked, Self.off and Self.element.l
@ -291,14 +346,13 @@ copyData:
Self.element, err = Self.bufQueue.Pop() Self.element, err = Self.bufQueue.Pop()
// if the queue is empty, Pop method will wait until one element push // if the queue is empty, Pop method will wait until one element push
// into the queue successful, or timeout. // into the queue successful, or timeout.
// timer start on timeout parameter is set up , // timer start on timeout parameter is set up
// reset to 60s if timeout and data still available
Self.off = 0 Self.off = 0
if err != nil { if err != nil {
Self.CloseWindow() // also close the window, to avoid read twice Self.CloseWindow() // also close the window, to avoid read twice
return // queue receive stop or time out, break the loop and return return // queue receive stop or time out, break the loop and return
} }
//logs.Warn("pop element", Self.element.l, Self.element.part) //logs.Warn("pop element", Self.element.L, Self.element.Part)
} }
l = copy(p[pOff:], Self.element.Buf[Self.off:Self.element.L]) l = copy(p[pOff:], Self.element.Buf[Self.off:Self.element.L])
pOff += l pOff += l
@ -320,22 +374,41 @@ copyData:
} }
func (Self *ReceiveWindow) sendStatus(id int32, l uint16) { func (Self *ReceiveWindow) sendStatus(id int32, l uint16) {
var remaining, wait uint32 var maxSize, read uint32
var wait bool
for { for {
ptrs := atomic.LoadUint64(&Self.remainingWait) ptrs := atomic.LoadUint64(&Self.maxSizeDone)
remaining, wait = Self.unpack(ptrs) maxSize, read, wait = Self.unpack(ptrs)
remaining += uint32(l) if read <= (read+uint32(l))&mask31 {
if atomic.CompareAndSwapUint64(&Self.remainingWait, ptrs, Self.pack(remaining, 0)) { read += uint32(l)
break remain := Self.remainingSize(maxSize, 0)
if wait && remain > 0 || read >= maxSize/2 || remain == maxSize {
if atomic.CompareAndSwapUint64(&Self.maxSizeDone, ptrs, Self.pack(maxSize, 0, false)) {
// now we get the current window status success
// receive window free up some space we need acknowledge send window, also reset the read size
// still having a condition that receive window is empty and not send the status to send window
// so send the status here
//logs.Warn("receive window free up some space", remain)
Self.mux.sendInfo(common.MUX_MSG_SEND_OK, id, Self.pack(maxSize, read, false))
break
}
} else {
if atomic.CompareAndSwapUint64(&Self.maxSizeDone, ptrs, Self.pack(maxSize, read, wait)) {
// receive window not into the wait status, or still not having any space now,
// just change the read size
break
}
}
} else {
//overflow
if atomic.CompareAndSwapUint64(&Self.maxSizeDone, ptrs, Self.pack(maxSize, uint32(l), wait)) {
// reset to l
Self.mux.sendInfo(common.MUX_MSG_SEND_OK, id, Self.pack(maxSize, read, false))
break
}
} }
runtime.Gosched() runtime.Gosched()
// another goroutine change remaining or wait status, make sure // another goroutine change remaining or wait status, make sure
// we need acknowledge other side
}
// now we get the current window status success
if wait == 1 {
//logs.Warn("send the wait status", remaining)
Self.mux.sendInfo(common.MUX_MSG_SEND_OK, id, atomic.LoadUint32(&Self.maxSize), remaining)
} }
return return
} }
@ -380,12 +453,14 @@ type SendWindow struct {
buf []byte buf []byte
setSizeCh chan struct{} setSizeCh chan struct{}
timeout time.Time timeout time.Time
// send window receive the receive window max size and read size
// done size store the size send window has send, send and read will be totally equal
// so send minus read, send window can get the current window size remaining
} }
func (Self *SendWindow) New(mux *Mux) { func (Self *SendWindow) New(mux *Mux) {
Self.setSizeCh = make(chan struct{}) Self.setSizeCh = make(chan struct{})
Self.maxSize = common.MAXIMUM_SEGMENT_SIZE * 10 Self.maxSizeDone = Self.pack(common.MAXIMUM_SEGMENT_SIZE*30, 0, false)
atomic.AddUint64(&Self.remainingWait, uint64(common.MAXIMUM_SEGMENT_SIZE*10)<<dequeueBits)
Self.mux = mux Self.mux = mux
Self.window.New() Self.window.New()
} }
@ -396,7 +471,15 @@ func (Self *SendWindow) SetSendBuf(buf []byte) {
Self.off = 0 Self.off = 0
} }
func (Self *SendWindow) SetSize(windowSize, newRemaining uint32) (closed bool) { func (Self *SendWindow) remainingSize(maxSize, send uint32) uint32 {
l := int64(maxSize&mask31) - int64(send&mask31)
if l > 0 {
return uint32(l)
}
return 0
}
func (Self *SendWindow) SetSize(currentMaxSizeDone uint64) (closed bool) {
// set the window size from receive window // set the window size from receive window
defer func() { defer func() {
if recover() != nil { if recover() != nil {
@ -408,26 +491,34 @@ func (Self *SendWindow) SetSize(windowSize, newRemaining uint32) (closed bool) {
return true return true
} }
//logs.Warn("set send window size to ", windowSize, newRemaining) //logs.Warn("set send window size to ", windowSize, newRemaining)
var remaining, wait, newWait uint32 var maxsize, send uint32
var wait, newWait bool
currentMaxSize, read, _ := Self.unpack(currentMaxSizeDone)
for { for {
ptrs := atomic.LoadUint64(&Self.remainingWait) ptrs := atomic.LoadUint64(&Self.maxSizeDone)
remaining, wait = Self.unpack(ptrs) maxsize, send, wait = Self.unpack(ptrs)
if remaining == newRemaining { if read > send {
//logs.Warn("waiting for another window size") logs.Error("window read > send: max size:", currentMaxSize, "read:", read, "send", send)
return false // waiting for receive another usable window size return
} }
if newRemaining == 0 && wait == 1 { if read == 0 && currentMaxSize == maxsize {
newWait = 1 // keep the wait status, return
// also if newRemaining is not zero, change wait to 0
} }
if atomic.CompareAndSwapUint64(&Self.remainingWait, ptrs, Self.pack(newRemaining, newWait)) { send -= read
remain := Self.remainingSize(currentMaxSize, send)
if remain == 0 && wait {
// just keep the wait status
newWait = true
}
// remain > 0, change wait to false. or remain == 0, wait is false, just keep it
if atomic.CompareAndSwapUint64(&Self.maxSizeDone, ptrs, Self.pack(currentMaxSize, send, newWait)) {
break break
} }
// anther goroutine change wait status or window size // anther goroutine change wait status or window size
} }
if wait == 1 { if wait && !newWait {
// send window into the wait status, need notice the channel // send window into the wait status, need notice the channel
//logs.Warn("send window remaining size is 0") //logs.Warn("send window allow")
Self.allow() Self.allow()
} }
// send window not into the wait status, so just do slide // send window not into the wait status, so just do slide
@ -446,18 +537,20 @@ func (Self *SendWindow) allow() {
} }
func (Self *SendWindow) sent(sentSize uint32) { func (Self *SendWindow) sent(sentSize uint32) {
var remaining, wait uint32 var maxSie, send uint32
var wait bool
for { for {
ptrs := atomic.LoadUint64(&Self.remainingWait) ptrs := atomic.LoadUint64(&Self.maxSizeDone)
remaining, wait = Self.unpack(ptrs) maxSie, send, wait = Self.unpack(ptrs)
if remaining >= sentSize { if (send+sentSize)&mask31 < send {
atomic.AddUint64(&Self.remainingWait, ^(uint64(sentSize)<<dequeueBits - 1)) // overflow
runtime.Gosched()
continue
}
if atomic.CompareAndSwapUint64(&Self.maxSizeDone, ptrs, Self.pack(maxSie, send+sentSize, wait)) {
// set the send size
//logs.Warn("sent", maxSie, send+sentSize, wait)
break break
} else {
if atomic.CompareAndSwapUint64(&Self.remainingWait, ptrs, Self.pack(0, wait)) {
// just keep the wait status, it will be wait in the next loop
break
}
} }
} }
} }
@ -472,12 +565,14 @@ func (Self *SendWindow) WriteTo() (p []byte, sendSize uint32, part bool, err err
return nil, 0, false, io.EOF return nil, 0, false, io.EOF
// send window buff is drain, return eof and get another one // send window buff is drain, return eof and get another one
} }
var remaining uint32 var maxSize, send uint32
start: start:
ptrs := atomic.LoadUint64(&Self.remainingWait) ptrs := atomic.LoadUint64(&Self.maxSizeDone)
remaining, _ = Self.unpack(ptrs) maxSize, send, _ = Self.unpack(ptrs)
if remaining == 0 { remain := Self.remainingSize(maxSize, send)
if !atomic.CompareAndSwapUint64(&Self.remainingWait, ptrs, Self.pack(0, 1)) { if remain == 0 {
if !atomic.CompareAndSwapUint64(&Self.maxSizeDone, ptrs, Self.pack(maxSize, send, true)) {
// just change the status wait status
goto start // another goroutine change the window, try again goto start // another goroutine change the window, try again
} }
// into the wait status // into the wait status
@ -490,17 +585,17 @@ start:
goto start goto start
} }
// there are still remaining window // there are still remaining window
//logs.Warn("rem", remaining) //logs.Warn("rem", remain, maxSize, send)
if len(Self.buf[Self.off:]) > common.MAXIMUM_SEGMENT_SIZE { if len(Self.buf[Self.off:]) > common.MAXIMUM_SEGMENT_SIZE {
sendSize = common.MAXIMUM_SEGMENT_SIZE sendSize = common.MAXIMUM_SEGMENT_SIZE
//logs.Warn("cut buf by mss") //logs.Warn("cut buf by mss")
} else { } else {
sendSize = uint32(len(Self.buf[Self.off:])) sendSize = uint32(len(Self.buf[Self.off:]))
} }
if remaining < sendSize { if remain < sendSize {
// usable window size is small than // usable window size is small than
// window MAXIMUM_SEGMENT_SIZE or send buf left // window MAXIMUM_SEGMENT_SIZE or send buf left
sendSize = remaining sendSize = remain
//logs.Warn("cut buf by remainingsize", sendSize, len(Self.buf[Self.off:])) //logs.Warn("cut buf by remainingsize", sendSize, len(Self.buf[Self.off:]))
} }
//logs.Warn("send size", sendSize) //logs.Warn("send size", sendSize)
@ -579,81 +674,49 @@ func (Self *SendWindow) SetTimeOut(t time.Time) {
Self.timeout = t Self.timeout = t
} }
//type bandwidth struct { type writeBandwidth struct {
// readStart time.Time writeBW uint64 // store in bits, but it's float64
// lastReadStart time.Time readEnd time.Time
// readEnd time.Time duration float64
// lastReadEnd time.Time bufLength uint32
// bufLength int }
// lastBufLength int
// count int8 const writeCalcThreshold uint32 = 5 * 1024 * 1024
// readBW float64
// writeBW float64 func NewWriteBandwidth() *writeBandwidth {
// readBandwidth float64 return &writeBandwidth{}
//} }
//
//func (Self *bandwidth) StartRead() { func (Self *writeBandwidth) StartRead() {
// Self.lastReadStart, Self.readStart = Self.readStart, time.Now() if Self.readEnd.IsZero() {
// if !Self.lastReadStart.IsZero() { Self.readEnd = time.Now()
// if Self.count == -5 { }
// Self.calcBandWidth() Self.duration += time.Now().Sub(Self.readEnd).Seconds()
// } if Self.bufLength >= writeCalcThreshold {
// } Self.calcBandWidth()
//} }
// }
//func (Self *bandwidth) EndRead() {
// Self.lastReadEnd, Self.readEnd = Self.readEnd, time.Now() func (Self *writeBandwidth) SetCopySize(n uint16) {
// if Self.count == -5 { Self.bufLength += uint32(n)
// Self.calcWriteBandwidth() Self.endRead()
// } }
// if Self.count == 0 {
// Self.calcReadBandwidth() func (Self *writeBandwidth) endRead() {
// Self.count = -6 Self.readEnd = time.Now()
// } }
// Self.count += 1
//} func (Self *writeBandwidth) calcBandWidth() {
// atomic.StoreUint64(&Self.writeBW, math.Float64bits(float64(Self.bufLength)/Self.duration))
//func (Self *bandwidth) SetCopySize(n int) { Self.bufLength = 0
// // must be invoke between StartRead and EndRead Self.duration = 0
// Self.lastBufLength, Self.bufLength = Self.bufLength, n }
//}
//// calculating func (Self *writeBandwidth) Get() (bw float64) {
//// start end start end // The zero value, 0 for numeric types
//// read read bw = math.Float64frombits(atomic.LoadUint64(&Self.writeBW))
//// write if bw <= 0 {
// bw = 0
//func (Self *bandwidth) calcBandWidth() { }
// t := Self.readStart.Sub(Self.lastReadStart) return
// if Self.lastBufLength >= 32768 { }
// Self.readBandwidth = float64(Self.lastBufLength) / t.Seconds()
// }
//}
//
//func (Self *bandwidth) calcReadBandwidth() {
// // Bandwidth between nps and npc
// readTime := Self.readEnd.Sub(Self.readStart)
// Self.readBW = float64(Self.bufLength) / readTime.Seconds()
// //logs.Warn("calc read bw", Self.readBW, Self.bufLength, readTime.Seconds())
//}
//
//func (Self *bandwidth) calcWriteBandwidth() {
// // Bandwidth between nps and user, npc and application
// writeTime := Self.readStart.Sub(Self.lastReadEnd)
// Self.writeBW = float64(Self.lastBufLength) / writeTime.Seconds()
// //logs.Warn("calc write bw", Self.writeBW, Self.bufLength, writeTime.Seconds())
//}
//
//func (Self *bandwidth) Get() (bw float64) {
// // The zero value, 0 for numeric types
// if Self.writeBW == 0 && Self.readBW == 0 {
// //logs.Warn("bw both 0")
// return 100
// }
// if Self.writeBW == 0 && Self.readBW != 0 {
// return Self.readBW
// }
// if Self.readBW == 0 && Self.writeBW != 0 {
// return Self.writeBW
// }
// return Self.readBandwidth
//}

View File

@ -9,8 +9,8 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"ehang.io/nps/lib/common"
"github.com/astaxie/beego/logs" "github.com/astaxie/beego/logs"
"github.com/cnlh/nps/lib/common"
) )
type Mux struct { type Mux struct {
@ -220,7 +220,7 @@ func (s *Mux) pingReturn() {
case data = <-s.pingCh: case data = <-s.pingCh:
atomic.StoreUint32(&s.pingCheckTime, 0) atomic.StoreUint32(&s.pingCheckTime, 0)
case <-s.closeChan: case <-s.closeChan:
break return
} }
_ = now.UnmarshalText(data) _ = now.UnmarshalText(data)
latency := time.Now().UTC().Sub(now).Seconds() / 2 latency := time.Now().UTC().Sub(now).Seconds() / 2
@ -303,7 +303,7 @@ func (s *Mux) readSession() {
if connection.isClose { if connection.isClose {
continue continue
} }
connection.sendWindow.SetSize(pack.Window, pack.ReadLength) connection.sendWindow.SetSize(pack.Window)
continue continue
case common.MUX_CONN_CLOSE: //close the connection case common.MUX_CONN_CLOSE: //close the connection
connection.closeFlag = true connection.closeFlag = true
@ -443,7 +443,7 @@ func (Self *bandwidth) Get() (bw float64) {
// The zero value, 0 for numeric types // The zero value, 0 for numeric types
bw = math.Float64frombits(atomic.LoadUint64(&Self.readBandwidth)) bw = math.Float64frombits(atomic.LoadUint64(&Self.readBandwidth))
if bw <= 0 { if bw <= 0 {
bw = 100 bw = 0
} }
//logs.Warn(bw) //logs.Warn(bw)
return return

View File

@ -2,10 +2,9 @@ package mux
import ( import (
"bufio" "bufio"
"ehang.io/nps/lib/common"
"ehang.io/nps/lib/goroutine"
"fmt" "fmt"
"github.com/cnlh/nps/lib/common"
"github.com/cnlh/nps/lib/goroutine"
"github.com/xtaci/kcp-go"
"io" "io"
"log" "log"
"net" "net"
@ -34,8 +33,8 @@ func TestNewMux(t *testing.T) {
//poolConnCopy, _ := ants.NewPoolWithFunc(200000, common.copyConn, ants.WithNonblocking(false)) //poolConnCopy, _ := ants.NewPoolWithFunc(200000, common.copyConn, ants.WithNonblocking(false))
time.Sleep(time.Second * 3) time.Sleep(time.Second * 3)
go func() { go func() {
//m2 := NewMux(conn2, "tcp") m2 := NewMux(conn2, "tcp")
m2 := NewMux(conn2, "kcp") //m2 := NewMux(conn2, "kcp")
for { for {
//logs.Warn("npc starting accept") //logs.Warn("npc starting accept")
c, err := m2.Accept() c, err := m2.Accept()
@ -84,8 +83,8 @@ func TestNewMux(t *testing.T) {
}() }()
go func() { go func() {
//m1 := NewMux(conn1, "tcp") m1 := NewMux(conn1, "tcp")
m1 := NewMux(conn1, "kcp") //m1 := NewMux(conn1, "kcp")
l, err := net.Listen("tcp", "127.0.0.1:7777") l, err := net.Listen("tcp", "127.0.0.1:7777")
if err != nil { if err != nil {
logs.Warn(err) logs.Warn(err)
@ -147,14 +146,14 @@ func TestNewMux(t *testing.T) {
func server() { func server() {
var err error var err error
//l, err := net.Listen("tcp", "127.0.0.1:9999") l, err := net.Listen("tcp", "127.0.0.1:9999")
l, err := kcp.Listen("127.0.0.1:9999") //l, err := kcp.Listen("127.0.0.1:9999")
if err != nil { if err != nil {
logs.Warn(err) logs.Warn(err)
} }
go func() { go func() {
conn1, err = l.Accept() conn1, err = l.Accept()
logs.Info("accept", conn1) //logs.Info("accept", conn1)
if err != nil { if err != nil {
logs.Warn(err) logs.Warn(err)
} }
@ -164,9 +163,9 @@ func server() {
func client() { func client() {
var err error var err error
//conn2, err = net.Dial("tcp", "127.0.0.1:9999") conn2, err = net.Dial("tcp", "127.0.0.1:9999")
logs.Warn("dial") //logs.Warn("dial")
conn2, err = kcp.Dial("127.0.0.1:9999") //conn2, err = kcp.Dial("127.0.0.1:9999")
if err != nil { if err != nil {
logs.Warn(err) logs.Warn(err)
} }

View File

@ -12,8 +12,8 @@ import (
"strings" "strings"
"time" "time"
"ehang.io/nps/lib/common"
"github.com/astaxie/beego/logs" "github.com/astaxie/beego/logs"
"github.com/cnlh/nps/lib/common"
"github.com/pkg/errors" "github.com/pkg/errors"
) )

View File

@ -1,8 +1,8 @@
package mux package mux
import ( import (
"ehang.io/nps/lib/common"
"errors" "errors"
"github.com/cnlh/nps/lib/common"
"io" "io"
"math" "math"
"runtime" "runtime"

View File

@ -14,7 +14,7 @@ func sysGetSock(fd *os.File) (bufferSize int, err error) {
if fd != nil { if fd != nil {
return syscall.GetsockoptInt(int(fd.Fd()), syscall.SOL_SOCKET, syscall.SO_RCVBUF) return syscall.GetsockoptInt(int(fd.Fd()), syscall.SOL_SOCKET, syscall.SO_RCVBUF)
} else { } else {
return 1400 * 320, nil return 5 * 1024 * 1024, nil
} }
} }

View File

@ -14,7 +14,7 @@ func sysGetSock(fd *os.File) (bufferSize int, err error) {
// not support, WTF??? // not support, WTF???
// Todo // Todo
// return syscall.GetsockoptInt((syscall.Handle)(unsafe.Pointer(fd.Fd())), syscall.SOL_SOCKET, syscall.SO_RCVBUF) // return syscall.GetsockoptInt((syscall.Handle)(unsafe.Pointer(fd.Fd())), syscall.SOL_SOCKET, syscall.SO_RCVBUF)
bufferSize = 10 * 1024 * 1024 bufferSize = 5 * 1024 * 1024
return return
} }

View File

@ -1,8 +1,8 @@
package version package version
const VERSION = "0.25.4" const VERSION = "0.26.0"
// Compulsory minimum version, Minimum downward compatibility to this version // Compulsory minimum version, Minimum downward compatibility to this version
func GetVersion() string { func GetVersion() string {
return "0.25.0" return "0.26.0"
} }

View File

@ -5,9 +5,9 @@ import (
"os" "os"
"strconv" "strconv"
"ehang.io/nps/lib/mux"
"github.com/astaxie/beego" "github.com/astaxie/beego"
"github.com/astaxie/beego/logs" "github.com/astaxie/beego/logs"
"github.com/cnlh/nps/lib/mux"
) )
var pMux *mux.PortMux var pMux *mux.PortMux

View File

@ -6,11 +6,11 @@ import (
"net/http" "net/http"
"sync" "sync"
"ehang.io/nps/bridge"
"ehang.io/nps/lib/common"
"ehang.io/nps/lib/conn"
"ehang.io/nps/lib/file"
"github.com/astaxie/beego/logs" "github.com/astaxie/beego/logs"
"github.com/cnlh/nps/bridge"
"github.com/cnlh/nps/lib/common"
"github.com/cnlh/nps/lib/conn"
"github.com/cnlh/nps/lib/file"
) )
type Service interface { type Service interface {

View File

@ -13,13 +13,13 @@ import (
"strings" "strings"
"sync" "sync"
"ehang.io/nps/bridge"
"ehang.io/nps/lib/cache"
"ehang.io/nps/lib/common"
"ehang.io/nps/lib/conn"
"ehang.io/nps/lib/file"
"ehang.io/nps/server/connection"
"github.com/astaxie/beego/logs" "github.com/astaxie/beego/logs"
"github.com/cnlh/nps/bridge"
"github.com/cnlh/nps/lib/cache"
"github.com/cnlh/nps/lib/common"
"github.com/cnlh/nps/lib/conn"
"github.com/cnlh/nps/lib/file"
"github.com/cnlh/nps/server/connection"
) )
type httpServer struct { type httpServer struct {

View File

@ -6,13 +6,13 @@ import (
"net/url" "net/url"
"sync" "sync"
"ehang.io/nps/lib/cache"
"ehang.io/nps/lib/common"
"ehang.io/nps/lib/conn"
"ehang.io/nps/lib/crypt"
"ehang.io/nps/lib/file"
"github.com/astaxie/beego" "github.com/astaxie/beego"
"github.com/astaxie/beego/logs" "github.com/astaxie/beego/logs"
"github.com/cnlh/nps/lib/cache"
"github.com/cnlh/nps/lib/common"
"github.com/cnlh/nps/lib/conn"
"github.com/cnlh/nps/lib/crypt"
"github.com/cnlh/nps/lib/file"
"github.com/pkg/errors" "github.com/pkg/errors"
) )

View File

@ -5,8 +5,8 @@ import (
"strings" "strings"
"time" "time"
"ehang.io/nps/lib/common"
"github.com/astaxie/beego/logs" "github.com/astaxie/beego/logs"
"github.com/cnlh/nps/lib/common"
) )
type P2PServer struct { type P2PServer struct {

View File

@ -7,10 +7,10 @@ import (
"net" "net"
"strconv" "strconv"
"ehang.io/nps/lib/common"
"ehang.io/nps/lib/conn"
"ehang.io/nps/lib/file"
"github.com/astaxie/beego/logs" "github.com/astaxie/beego/logs"
"github.com/cnlh/nps/lib/common"
"github.com/cnlh/nps/lib/conn"
"github.com/cnlh/nps/lib/file"
) )
const ( const (

View File

@ -7,13 +7,13 @@ import (
"path/filepath" "path/filepath"
"strconv" "strconv"
"ehang.io/nps/bridge"
"ehang.io/nps/lib/common"
"ehang.io/nps/lib/conn"
"ehang.io/nps/lib/file"
"ehang.io/nps/server/connection"
"github.com/astaxie/beego" "github.com/astaxie/beego"
"github.com/astaxie/beego/logs" "github.com/astaxie/beego/logs"
"github.com/cnlh/nps/bridge"
"github.com/cnlh/nps/lib/common"
"github.com/cnlh/nps/lib/conn"
"github.com/cnlh/nps/lib/file"
"github.com/cnlh/nps/server/connection"
) )
type TunnelModeServer struct { type TunnelModeServer struct {

View File

@ -7,8 +7,8 @@ import (
"strconv" "strconv"
"syscall" "syscall"
"github.com/cnlh/nps/lib/common" "ehang.io/nps/lib/common"
"github.com/cnlh/nps/lib/conn" "ehang.io/nps/lib/conn"
) )
func HandleTrans(c *conn.Conn, s *TunnelModeServer) error { func HandleTrans(c *conn.Conn, s *TunnelModeServer) error {

View File

@ -3,7 +3,7 @@
package proxy package proxy
import ( import (
"github.com/cnlh/nps/lib/conn" "ehang.io/nps/lib/conn"
) )
func HandleTrans(c *conn.Conn, s *TunnelModeServer) error { func HandleTrans(c *conn.Conn, s *TunnelModeServer) error {

View File

@ -4,11 +4,11 @@ import (
"net" "net"
"strings" "strings"
"ehang.io/nps/bridge"
"ehang.io/nps/lib/common"
"ehang.io/nps/lib/conn"
"ehang.io/nps/lib/file"
"github.com/astaxie/beego/logs" "github.com/astaxie/beego/logs"
"github.com/cnlh/nps/bridge"
"github.com/cnlh/nps/lib/common"
"github.com/cnlh/nps/lib/conn"
"github.com/cnlh/nps/lib/file"
) )
type UdpModeServer struct { type UdpModeServer struct {

View File

@ -1,21 +1,21 @@
package server package server
import ( import (
"ehang.io/nps/lib/version"
"errors" "errors"
"github.com/cnlh/nps/lib/version"
"math" "math"
"os" "os"
"strconv" "strconv"
"strings" "strings"
"time" "time"
"ehang.io/nps/bridge"
"ehang.io/nps/lib/common"
"ehang.io/nps/lib/file"
"ehang.io/nps/server/proxy"
"ehang.io/nps/server/tool"
"github.com/astaxie/beego" "github.com/astaxie/beego"
"github.com/astaxie/beego/logs" "github.com/astaxie/beego/logs"
"github.com/cnlh/nps/bridge"
"github.com/cnlh/nps/lib/common"
"github.com/cnlh/nps/lib/file"
"github.com/cnlh/nps/server/proxy"
"github.com/cnlh/nps/server/tool"
"github.com/shirou/gopsutil/cpu" "github.com/shirou/gopsutil/cpu"
"github.com/shirou/gopsutil/load" "github.com/shirou/gopsutil/load"
"github.com/shirou/gopsutil/mem" "github.com/shirou/gopsutil/mem"

View File

@ -5,9 +5,9 @@ import (
"path/filepath" "path/filepath"
"strconv" "strconv"
"ehang.io/nps/lib/common"
"ehang.io/nps/lib/file"
"github.com/astaxie/beego" "github.com/astaxie/beego"
"github.com/cnlh/nps/lib/common"
"github.com/cnlh/nps/lib/file"
) )
func TestServerConfig() { func TestServerConfig() {

View File

@ -5,8 +5,8 @@ import (
"strconv" "strconv"
"time" "time"
"ehang.io/nps/lib/common"
"github.com/astaxie/beego" "github.com/astaxie/beego"
"github.com/cnlh/nps/lib/common"
"github.com/shirou/gopsutil/cpu" "github.com/shirou/gopsutil/cpu"
"github.com/shirou/gopsutil/load" "github.com/shirou/gopsutil/load"
"github.com/shirou/gopsutil/mem" "github.com/shirou/gopsutil/mem"

View File

@ -4,8 +4,8 @@ import (
"encoding/hex" "encoding/hex"
"time" "time"
"ehang.io/nps/lib/crypt"
"github.com/astaxie/beego" "github.com/astaxie/beego"
"github.com/cnlh/nps/lib/crypt"
) )
type AuthController struct { type AuthController struct {

View File

@ -7,11 +7,11 @@ import (
"strings" "strings"
"time" "time"
"ehang.io/nps/lib/common"
"ehang.io/nps/lib/crypt"
"ehang.io/nps/lib/file"
"ehang.io/nps/server"
"github.com/astaxie/beego" "github.com/astaxie/beego"
"github.com/cnlh/nps/lib/common"
"github.com/cnlh/nps/lib/crypt"
"github.com/cnlh/nps/lib/file"
"github.com/cnlh/nps/server"
) )
type BaseController struct { type BaseController struct {

View File

@ -1,11 +1,11 @@
package controllers package controllers
import ( import (
"ehang.io/nps/lib/common"
"ehang.io/nps/lib/file"
"ehang.io/nps/lib/rate"
"ehang.io/nps/server"
"github.com/astaxie/beego" "github.com/astaxie/beego"
"github.com/cnlh/nps/lib/common"
"github.com/cnlh/nps/lib/file"
"github.com/cnlh/nps/lib/rate"
"github.com/cnlh/nps/server"
) )
type ClientController struct { type ClientController struct {

View File

@ -1,10 +1,10 @@
package controllers package controllers
import ( import (
"github.com/cnlh/nps/lib/file" "ehang.io/nps/lib/file"
"github.com/cnlh/nps/server" "ehang.io/nps/server"
"github.com/cnlh/nps/server/tool" "ehang.io/nps/server/tool"
"github.com/astaxie/beego" "github.com/astaxie/beego"
) )

View File

@ -6,10 +6,10 @@ import (
"sync" "sync"
"time" "time"
"ehang.io/nps/lib/common"
"ehang.io/nps/lib/file"
"ehang.io/nps/server"
"github.com/astaxie/beego" "github.com/astaxie/beego"
"github.com/cnlh/nps/lib/common"
"github.com/cnlh/nps/lib/file"
"github.com/cnlh/nps/server"
) )
type LoginController struct { type LoginController struct {

View File

@ -1,8 +1,8 @@
package routers package routers
import ( import (
"ehang.io/nps/web/controllers"
"github.com/astaxie/beego" "github.com/astaxie/beego"
"github.com/cnlh/nps/web/controllers"
) )
func Init() { func Init() {

View File

@ -5,6 +5,6 @@
<title>nps error</title> <title>nps error</title>
</head> </head>
<body> <body>
404 not found,power by <a href="//github.com/cnlh/nps">nps</a> 404 not found,power by <a href="//ehang.io/nps">nps</a>
</body> </body>
</html> </html>

View File

@ -37,7 +37,7 @@
</p> </p>
<p> <p>
goto <a href="//github.com/cnlh/nps">nps</a> goto <a href="//ehang.io/nps">nps</a>
</p> </p>
<div class="ibox-content"> <div class="ibox-content">
<form class="m-t" onsubmit="return false"> <form class="m-t" onsubmit="return false">

View File

@ -105,7 +105,7 @@
<ul class="nav navbar-top-links navbar-right"> <ul class="nav navbar-top-links navbar-right">
<li> <li>
<span class="m-r-sm text-muted welcome-message">Welcome to use <a <span class="m-r-sm text-muted welcome-message">Welcome to use <a
href="https://github.com/cnlh/nps">NPS</a></span> href="https://ehang.io/nps">NPS</a></span>
</li> </li>
<li> <li>
<a id="lang-en">English</a> <a id="lang-en">English</a>
@ -128,7 +128,7 @@
{{.LayoutContent}} {{.LayoutContent}}
<div class="footer"> <div class="footer">
<div class="pull-right"> <div class="pull-right">
read more <strong><a href="https://github.com/cnlh/nps">go</a></strong> read more <strong><a href="https://ehang.io/nps">go</a></strong>
</div> </div>
<div> <div>
<strong>Copyright</strong> nps &copy; 2018-2019 <strong>Copyright</strong> nps &copy; 2018-2019