命名管道通信

管道通信(Communication Pipeline)即发送进程以字符流形式将大量数据送入管道,接收进程可从管道接收数据,二者利用管道进行通信。无论是SQL Server用户,还是PB用户,作为C/S结构开发环境,他们在网络通信的实现上,都有一种共同的方法——命名管道。(来源百度百科)

起因

因为一些特殊的原因,开发工程中不能使用http这种开服务端口的形式进行数据交互,而且当时的项目也是类似的C/S架构,所以刚好学习并应用到工作开发中。。。

开整

废话不多说
数据交互以命名管道通信为主。
上代码(只有一部分,主要架构的代码,前端node.js)

后端
import gw "github.com/Microsoft/go-winio"
var ServerSocket net.Conn
var lockSend sync.Mutex
var pipeFile = "\\\\.\\pipe\\wtreelee_pipe"
//注册函数,一个函数对应一个口令
func register() map[string]returnFunc {return map[string]returnFunc{"entry":            		pipeEntry,	 			// 获取入口数据"main":						startMain,	 			// 进入"load":						load,		 			// 加载}
}/**开启管道通信监听通过一个命名管道文件 wtreelee_pipe 进行管道通信进行数据交互通过封装数据交互:方法&&&参数*/
func OpenPipeServer() {log.Println("开启管道通信")l, err := gw.ListenPipe(pipeFile, &config)if err != nil {log.Println("管道通信,开启管道错误")log.Println(err)return}for {conn, err := l.Accept()if err != nil {log.Println("管道通信,开启监听错误")log.Println(err)continue}go doServer(conn)}
}func doServer(conn net.Conn) {ServerSocket = connvar cmdChan = make(chan string)  //接收请求数据var stopChan = make(chan string) //发送、接收一起停止var methods = register()go func() {for{cmd := <-cmdChanvar message []byteif len(cmd) > 0 {log.Println("管道通信,接收到数据")// 口令格式和数据格式: cmd&&&jsondata := map[string]interface{}{}if strings.Contains(cmd, "&&&") {params := strings.Split(cmd, "&&&")cmd = params[0]log.Println("read ", cmd+" ", params[1])err := json.Unmarshal([]byte(params[1]), &data)if err != nil {log.Println("read2:", err)stopChan <- err.Error()break}}cmdFunc, ok := methods[cmd]if !ok {log.Println("socket", "没有这个函数", cmd)stopChan <- fmt.Errorf("没有这个函数" + cmd).Error()break}message, _ = json.Marshal(cmdFunc(data))//log.Println(string(message))err := sendMessage(fmt.Sprintf("%s&&&%s", cmd, string(message)))if err != nil {log.Println("write2:", err)stopChan <- err.Error()break}stopChan <- ""}}}()for{r := bufio.NewReader(conn)msg, err := r.ReadString('\n')if err != nil {log.Println("readErr",err)return}log.Println("msg:",msg)cmdChan<-msg}
}/**管道通信:发送数据*/
func sendMessage(message string) error {lockSend.Lock()defer lockSend.Unlock()if ServerSocket != nil {_,err := fmt.Fprintln(ServerSocket,message)if err != nil {log.Println("sendMessage:", err)return err}}return nil
}
前端Js
/* eslint-disable no-undef */
/** 用pipe连接 */import setting from '../../setting';
import Utils from './Utils';const openTips = true;
const net = window.$nw.require('net');/** 建立* @param PIPE_NAME: [String] 管道名*/
export default class Pipe {constructor(PIPE_NAME = "wtreelee_pipe") {this.path = "\\\\.\\pipe\\" + PIPE_NAME;this.channel = Pipe.getChannel();this.server = Pipe.newPipe(this);this.readyState = 0;}// /** 重置失败次数, 重置之后将会重新连接*/resetPipe() {if (openTips) {let tips = `[pipe ${this.path}] : 失败次数重置, 将重新连接...`;tips = Utils.formatTips(tips);console.log(...tips);}this.failTime = 0;this.socket = Pipe.newPipe(this);}/** 生成事件实例 */static getChannel() {const events = require('events');return new events.EventEmitter();}/** 开始连接* @param that : [Object] 实例对象* @return socket: 返回一个socket*/static newPipe(that) {let server = net.connect(that.path, function () {let tips = `[pipe ${that.path}]: 建立`;tips = Utils.formatTips(tips);console.log(...tips);});// server.setTimeout(3000);// server.on('timeout', () => {//   console.log('socket 超时');//   that.resetPipe();// });server.on('connect',function(){console.log("连接成功");});server.on('data', function (c) {let order = '';let data = c.toString();let tips = '';// 如果是[命令]&&&[数据的格式]if (~data.indexOf('&&&')) {data = c.toString().split('&&&'); // 约定格式, &&&是命令跟数据的分割符order = data[0]; // 命令(一个标记, send的命令它就是什么)data = data[1] ? JSON.parse(data[1]) : 'have no data'; // 数据tips = `[pipe ${that.path}]: 接收到 ${order} 的数据\n`;}// 不是这种格式的话就直接解析else {data = JSON.parse(data);tips = `[pipe ${that.path}]: 接收到数据\n`;}if (openTips) {tips = Utils.formatTips(tips);console.log(...tips, data);}that.channel.emit(order, JSON.parse(JSON.stringify(data)));});server.on('end', function () {console.log("关闭");});return server;}/** 发送数据* @param order: [String] 命令* @param data: [Object] 数据*/send(order, data = {}) {Utils.isintance(order, 'String');Utils.isintance(data, 'Object');if (this.server.readyState === "open") {this.server.write(`${order}&&&${JSON.stringify(data)}\n`); // 数据发送if (openTips) {const o = `${order}&&&${JSON.stringify(data)}`;let tips = `[pipe ${this.path}]: 发送数据, 命令: ${o}`;tips = Utils.formatTips(tips);const tips_data = Object.keys(data).length ? data : '';console.log(...tips, tips_data); // 打印状态}}// 当连接未完成的时候, 递归本身直到连接完成else {setTimeout(() => this.send(order, data), 500);}}/** 监听数据* @param order: [String] 事件名* @param cb: [Function] 回调函数*/listen(order, cb) {Utils.isintance(order, 'String');Utils.isintance(cb, 'Function');if (openTips) {let tips = `[pipe ${this.path}]: 正在监听 ${order} 的数据...`;tips = Utils.formatTips(tips);console.log(...tips);}this.channel.on(order, cb);}/** 移除某个监听* @param order: [String] 事件名*/removeListen(order) {Utils.isintance(order, 'String');if (openTips) {let tips = `[pipe ${this.path}]: 取消 ${order} 的监听`;tips = Utils.formatTips(tips);console.log(...tips);}this.channel.removeAllListeners(order);}
}

实现接口的功能就自己定义数据的格式 怎么好搞怎么来

(^-^)V