Browse Source

Module 'sipc_conn' Done 2020-03-10 02:19

zry 4 years ago
parent
commit
a6dbdd1755

+ 2 - 0
.idea/.gitignore

@@ -0,0 +1,2 @@
+# Default ignored files
+/workspace.xml

+ 8 - 0
.idea/SatorIPC.iml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="WEB_MODULE" version="4">
+  <component name="NewModuleRootManager">
+    <content url="file://$MODULE_DIR$" />
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>

+ 5 - 0
.idea/inspectionProfiles/profiles_settings.xml

@@ -0,0 +1,5 @@
+<component name="InspectionProjectProfileManager">
+  <settings>
+    <option name="PROJECT_PROFILE" />
+  </settings>
+</component>

+ 6 - 0
.idea/misc.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="JavaScriptSettings">
+    <option name="languageLevel" value="ES6" />
+  </component>
+</project>

+ 8 - 0
.idea/modules.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/.idea/SatorIPC.iml" filepath="$PROJECT_DIR$/.idea/SatorIPC.iml" />
+    </modules>
+  </component>
+</project>

+ 6 - 0
.idea/vcs.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="$PROJECT_DIR$" vcs="Git" />
+  </component>
+</project>

+ 8 - 4
README.md

@@ -12,13 +12,17 @@ Working in progress...
 
 ### 平台
 
-Windows: 通过命名管道
-Unix: 通过AF_Unix
+* Windows: 通过命名管道
+* Unix: 通过AF_UNIX
 
 ## 语言
 
-Go: 支持
-Node.js: 计划支持
+* Go: 支持
+* Node.js: 计划支持
+
+## 结构
+
+* SIPC_Conn: 提供连接层,在Windows下使用命名管道,在Unix下使用AF_UNIX,提供流式Socket对象
 
 # English Docs
 

+ 57 - 0
docs/golang/sipc_conn/zh-CN.md

@@ -0,0 +1,57 @@
+# SIPC_Conn 中文文档
+
+## 安装
+
+```bash
+go get -u git.swzry.com/SatorIPC/golang/sipc_conn
+```
+
+## 开始使用
+
+在examples/golang/SIPC_Conn_BasicTest中有一个样例程序。
+
+使用 `go build` 编译样例程序后,使用方法如下:
+
+### 建立服务端
+
+使用 `-s` 参数建立服务端。
+
+```bash
+./SIPC_Conn_BasicTest -s
+```
+
+此时控制台会打印出随机生成的监听路径,之后连接就使用这个路径连接
+
+以下为Windows下输出的示例:
+```
+Listen Pipe Name: \\.\Pipe\satoripc-24d51fe8-3082-428f-a2ca-461ef2fb39b0
+```
+
+则监听路径为 `\\.\Pipe\satoripc-24d51fe8-3082-428f-a2ca-461ef2fb39b0` 。
+
+以下为Unix下输出的示例:
+
+```
+Listen Pipe Name: /var/run/satoripc-b9212b99-8897-4075-bb6b-fe475a751bef.sock
+```
+
+则监听路径为 `/var/run/satoripc-b9212b99-8897-4075-bb6b-fe475a751bef.sock` 。
+
+若想指定监听路径,使用 `-p` 参数指定:
+
+```bash
+./SIPC_Conn_BasicTest -s -p /var/run/test.sock
+```
+
+### 建立客户端
+
+不加 `-s` 参数则建立客户端。使用 `-p` 参数指定连接路径,即刚才服务器监听的路径。
+
+```bash
+.\SIPC_Conn_BasicTest -p /var/run/test.sock
+```
+
+### 实验
+
+在服务端或客户端通过标准输入向内输入内容,并按 `Enter` 键,则另一端会通过标准输出打印出这些内容。
+

+ 79 - 0
examples/golang/SIPC_Conn_BasicTest/main.go

@@ -0,0 +1,79 @@
+package main
+
+import (
+	"flag"
+	"fmt"
+	"git.swzry.com/zry/SatorIPC/golang/sipc_conn"
+	"io"
+	"net"
+	"os"
+	"os/signal"
+	"sync"
+	"time"
+)
+
+func main() {
+	var isServer bool
+	var pipename string
+	flag.BoolVar(&isServer, "s", false, "Server mode")
+	flag.StringVar(&pipename, "p", sipc_conn.GeneratePath(), "Pipe name")
+	flag.Parse()
+	if isServer {
+		fmt.Println("Listen Pipe Name:", pipename)
+		c := make(chan os.Signal, 1)
+		signal.Notify(c, os.Interrupt, os.Kill)
+		server, err := sipc_conn.NewServer(pipename, false)
+		if err != nil {
+			fmt.Println("CreateServerError:", err.Error())
+			return
+		}
+		server.SetConnErrorHandler(func(err error) {
+			fmt.Println("[Conn] Failed Handling Connection:", err.Error())
+		})
+		server.SetConnHandler(handleConnection)
+		err = server.Start()
+		if err != nil {
+			fmt.Println("StartServerError:", err.Error())
+			return
+		}
+		s := <-c
+		err = server.Stop()
+		if err != nil {
+			fmt.Println("StopServerError:", err.Error())
+		}
+		fmt.Println("Program Quit By Signal:", s)
+	} else {
+		fmt.Println("Dial Pipe Name:", pipename)
+		conn, err := sipc_conn.Dial(pipename, 1*time.Second)
+		if err != nil {
+			fmt.Println("DialError:", err.Error())
+			return
+		}
+		handleConnection(conn)
+		fmt.Println("Program End By Connection Lost.")
+	}
+}
+
+func handleConnection(netconn net.Conn) {
+	wg := sync.WaitGroup{}
+	wg.Add(2)
+	go func() {
+		outs := os.Stdout
+		n, err := io.Copy(outs, netconn)
+		if err != nil {
+			fmt.Println("Recv IO Error:", err.Error())
+		}
+		fmt.Printf("%d byte(s) recieved.\n", n)
+		wg.Done()
+	}()
+	go func() {
+		ins := os.Stdin
+		n, err := io.Copy(netconn, ins)
+		if err != nil {
+			fmt.Println("Transmit IO Error:", err.Error())
+		}
+		fmt.Printf("%d byte(s) transmitted.\n", n)
+		wg.Done()
+	}()
+	wg.Wait()
+}

+ 12 - 0
golang/sipc_conn/client_unix.go

@@ -0,0 +1,12 @@
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package sipc_conn
+
+import (
+	"net"
+	"time"
+)
+
+func Dial(path string, timeout time.Duration) (net.Conn, error) {
+	return net.DialTimeout("unix", path, timeout)
+}

+ 13 - 0
golang/sipc_conn/client_windows.go

@@ -0,0 +1,13 @@
+// +build windows
+
+package sipc_conn
+
+import (
+	"github.com/Microsoft/go-winio"
+	"net"
+	"time"
+)
+
+func Dial(path string, timeout time.Duration) (net.Conn, error) {
+	return winio.DialPipe(path, &timeout)
+}

+ 67 - 0
golang/sipc_conn/server.go

@@ -0,0 +1,67 @@
+package sipc_conn
+
+import (
+	"net"
+)
+
+type Server struct {
+	isUnix           bool
+	serverPath       string
+	ctx              ServerCtx
+	listener         net.Listener
+	connErrorHandler ConnErrorHandler
+	connHandler      ConnHandler
+	quitChan         chan int
+}
+
+func (s *Server) GetPath() string {
+	return s.serverPath
+}
+
+func (s *Server) IsUnix() bool {
+	return s.isUnix
+}
+
+func (s *Server) IsWindows() bool {
+	return !s.isUnix
+}
+
+func (s *Server) SetConnErrorHandler(handler ConnErrorHandler) {
+	s.connErrorHandler = handler
+}
+
+func (s *Server) SetConnHandler(handler ConnHandler) {
+	s.connHandler = handler
+}
+
+type ConnErrorHandler func(err error)
+type ConnHandler func(conn net.Conn)
+
+func defaultConnErrHandler(err error) {}
+func defaultConnHandler(conn net.Conn) {
+	conn.Close()
+}
+
+func (s *Server) doAccept() {
+	for {
+		conn, err := s.listener.Accept()
+		select {
+		default:
+		case <-s.quitChan:
+			return
+		}
+		if err != nil {
+			go s.connErrorHandler(err)
+		} else {
+			go s.connHandler(conn)
+		}
+	}
+}
+
+func (s *Server) Stop() error {
+	close(s.quitChan)
+	if s.listener != nil {
+		return s.listener.Close()
+	}
+	return nil
+}

+ 61 - 0
golang/sipc_conn/server_unix.go

@@ -0,0 +1,61 @@
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package sipc_conn
+
+import (
+	"fmt"
+	uuid "github.com/satori/go.uuid"
+	"net"
+	"os"
+)
+
+type ServerCtx struct {
+}
+
+func GenerateServerName() string {
+	return fmt.Sprintf("satoripc-%s.sock", uuid.NewV4().String())
+}
+
+func GeneratePath() string {
+	return fmt.Sprintf("/var/run/%s", GenerateServerName())
+}
+
+func NewDefaultServer(name string) (*Server, error) {
+	var sp string
+	if name == "" {
+		sp = GenerateServerName()
+	} else {
+		sp = name
+	}
+	return NewServer(sp, false)
+}
+
+func NewServer(path string, msgmode bool) (*Server, error) {
+	o := &Server{
+		serverPath:       path,
+		isUnix:           true,
+		connErrorHandler: defaultConnErrHandler,
+		connHandler:      defaultConnHandler,
+		ctx:              ServerCtx{},
+	}
+	return o, nil
+}
+
+func (s *Server) Win_UseSecurityDescrptor(sd string) {}
+func (s *Server) Win_SetBufferSize(in, out int32)    {}
+
+func (s *Server) Start() error {
+	var err error
+	os.Remove(s.serverPath)
+	uaddr, err := net.ResolveUnixAddr("unix", s.serverPath)
+	if err != nil {
+		return err
+	}
+	s.listener, err = net.ListenUnix("unix", uaddr)
+	if err != nil {
+		return err
+	}
+	s.quitChan = make(chan int)
+	go s.doAccept()
+	return nil
+}

+ 69 - 0
golang/sipc_conn/server_windows.go

@@ -0,0 +1,69 @@
+// +build windows
+
+package sipc_conn
+
+import (
+	"fmt"
+	"github.com/Microsoft/go-winio"
+	uuid "github.com/satori/go.uuid"
+)
+
+type ServerCtx struct {
+	pipeConfig *winio.PipeConfig
+}
+
+func GenerateServerName() string {
+	return fmt.Sprintf("satoripc-%s", uuid.NewV4().String())
+}
+
+func GeneratePath() string {
+	return fmt.Sprintf("\\\\.\\Pipe\\%s", GenerateServerName())
+}
+
+func NewDefaultServer(name string) (*Server, error) {
+	var sp string
+	if name == "" {
+		sp = GeneratePath()
+	} else {
+		sp = fmt.Sprintf("\\\\.\\Pipe\\%s", name)
+	}
+	return NewServer(sp, false)
+}
+
+func NewServer(path string, msgmode bool) (*Server, error) {
+	o := &Server{
+		serverPath:       path,
+		isUnix:           false,
+		connErrorHandler: defaultConnErrHandler,
+		connHandler:      defaultConnHandler,
+		ctx: ServerCtx{
+			pipeConfig: &winio.PipeConfig{
+				SecurityDescriptor: "",
+				MessageMode:        msgmode,
+				InputBufferSize:    0,
+				OutputBufferSize:   0,
+			},
+		},
+	}
+	return o, nil
+}
+
+func (s *Server) Win_UseSecurityDescrptor(sd string) {
+	s.ctx.pipeConfig.SecurityDescriptor = sd
+}
+
+func (s *Server) Win_SetBufferSize(in, out int32) {
+	s.ctx.pipeConfig.InputBufferSize = in
+	s.ctx.pipeConfig.OutputBufferSize = out
+}
+
+func (s *Server) Start() error {
+	var err error
+	s.listener, err = winio.ListenPipe(s.serverPath, s.ctx.pipeConfig)
+	if err != nil {
+		return err
+	}
+	s.quitChan = make(chan int)
+	go s.doAccept()
+	return nil
+}