微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Electron与工业CCD通过TCP Server协议连接通讯

Electron与工业CCD通过TCP Server协议连接通讯

CCD可以理解为是一个相机,在工业上可以通过CCD给物体拍照,然后识别出物体表面激光刻印的信息,大概如下图,下图是我公司研发的软件一张截图,软件是使用C#实现的,这个工业软件还是很厉害的,里面涉及到了许多与工业传感器的数据交互。现在我的工作主要就是使用前端知识重构这个软件,要与硬件打交道了,当然要选择ElectronNode技术栈了。

CCD底层是通过TCP Server协议进行通讯的,所以要想与CCD进行数据对接,就要在Electron中实现TCP Server服务了。

这个知识我是不会的,最先是读C#代码,看之前人家是怎么实现的,6000行的代码,看的我也是头晕脑胀的。再后来就是在网上找资料了,可是发现网上关于Electron连接TCP Server的资料真不多,但还是有的,下面就开始实现吧。

参考资料一:electron测试TCP通信,这篇文章写的估计也就只有博主自己能看懂吧!没办法参考着他的代码,我居然还悟出来点东西。

首先声明我的Electron是通过Vue CLI Plugin Electron Builder创建出来的。在主进程(background.js)中添加下面这段代码

 1 // TCP/IP通讯
 2 
 3 // 试了半天,才发现这是创建一个 TCP Server 的
 4 function createServer(port) {
 5   const HOST = '127.0.0.1';
 6   // const port = 7899;
 7   if (server) {
 8     server.close();
 9   }
10 
11   server = net.createServer();
12 
13   server.listen(port, HOST, function () {
14     console.log('Server listen on port:' + server.address().address);
15     console.log('--------------------------------------服务正在监听中---------------------------------------');
16     sendServerData('start-server', '服务正在监听中,server is listening...');
17   });
18 
19 
20   server.on('connection', socket => {
21     sendServerData('connect-server', 'Get conneciton from:' + socket.remoteAddress);
22 
23     socket.on('data', data => {
24       sendServerData('data-server', 'Get data from socket:' + socket.remoteAddress + '. The data:' + data);
25       socket.write('you said:' + data);
26     });
27 
28     socket.on('close', () => {
29       sendServerData('close-server', 'Socket:' + socket.remoteAddress + " closed");
30     })
31   });
32 
33 }
34 
35 let server;
36 let client;
37 let serverEvent, clientEvent;
38 // 通过这个方法就可以建立一个TCP服务器,当收到前端发送的event,就可以创建了,这里前端发送的消息是 start-server
39 ipcMain.on('start-server', (event, arg) => {
40   serverEvent = event;
41   // event.sender.send()
42   console.log('+++++++++++++++++++++++++++ event ++++++++++++++++++++++++++++++++++++++++++++++')
43   console.log(event)
44   console.log('=================================== arg =============================================')
45   console.log(arg)
46   createServer(arg);
47 })
48 
49 // 将消息返回给前端
50 function sendServerData(channel, msg) {
51   try {
52     console.log(`server send event ${channel}, ${msg}`);
53     if (serverEvent) {
54       serverEvent.sender.send(channel, msg);
55     }
56   } catch (error) {
57     console.error('gt error:' + error);
58   }
59 }

然后在前端页面上新增两个输入框和一个按钮,如下图:

Home.vue 代码

 1 <template>
 2   <div class="home">
 3     <img alt="Vue logo" src="../assets/logo.png" />
 4     <div>
 5       发送的消息:<input type="text" v-model="msg" />
 6     </div>
 7     <div>
 8       接收的消息:<input type="text" v-model="msg2">
 9     </div>
10     <div>
11       <button @click="tcpserver">TCP通信</button>
12     </div>
13     <!-- <HelloWorld msg="Welcome to Your Vue.js App" /> -->
14   </div>
15 </template>
16 
17 <script>
18 const ipc = window.require("electron").ipcRenderer;
19 ipc.on("start-server", (evnet, args) => {
20   console.log(evnet,args)
21 });
22 ipc.on("data-server", (evnet, args) => {
23   console.log(evnet,args)
24 });
25 
26 ipc.on("close-server", (evnet, args) => {
27   console.log(evnet,args)
28 });
29 
30 // @ is an alias to /src
31 import HelloWorld from "@/components/HelloWorld.vue";
32 
33 export default {
34   name: "Home",
35   components: {
36     HelloWorld,
37   },
38   data() {
39     return {
40       msg: "",
41       msg2: "",
42     };
43   },
44   methods: {
45     tcpserver() {
46       console.log(this.msg);
47       ipc.send("start-server", this.msg);
48     },
49     addText(msg) {
50       this.msg2 += msg + "\n";
51     },
52   },
53 };
54 </script>
55 
56 <style lang="css" scoped>
57 img {
58   -webkit-app-region: drag;
59 }
60 </style>

下面这张图是主进程在控制台输出的信息,从中可以看出event参数是这么一大坨东西,arg参数就是我们输入框输入的111。

如果我们先通过网络调试助手,创建一个ip为 127.0.0.1 端口号为 7899 的 TCP Server,然后再回到页面上在输入框内也输入7899,然后点击按钮,就发现报错了,报错说127.0.0.1:7899已经被创建了。

可以看出在主进程里面加的这段代码其实是通过渲染进程来创建一个TCP Server的,可这并不是我的需求,我的需求是将Electron作为一个客户端,可以向CCDTCP服务器发送消息,并且可以接收CCD返回给我的信息,下面实现一下。

参考资料二、electron 使用tcp套接字(一)

参考资料三、Node.js Net 模块

在主进程(background.js)中添加下面这段代码

 1 // 作为客户端
 2 var net = require('net');
 3 var HOST = '127.0.0.1';
 4 var PORT = 7899;
 5 
 6 var client = new net.socket();
 7 client.connect(PORT, HOST, function() {
 8     console.log('CONNECTED TO: ' + HOST + ':' + PORT);
 9     // 建立连接后立即向服务器发送数据,服务器将收到这些数据
10     client.write('Hello TCP/IP! 老子终于通过 Electron 实现和你通信了!!!');
11 
12 });
13 
14 // 为客户端添加“data”事件处理函数
15 // data是服务器发回的数据
16 client.on('data', function(data) {
17     console.log('DATA: ' + data);
18     // 完全关闭连接
19     client.destroy();
20 });
21 
22 // 为客户端添加“close”事件处理函数
23 client.on('close', function() {
24     console.log('Connection closed');
25 });

然后通过网络调试助手打开一个127.0.0.1:7899的TCP Server服务,我们通过Electron向网络调试助手发送一条消息。

再次启动我们的Electron项目,项目一启动就会自动向网络调试助手发送一条信息,在网络调试助手中我们就可以看到这条消息了

然后再通过网络调试助手给我们的客户端Electron发送一条数据:

然后我们的Electron也就可以收到来自TCP Server服务端的消息了,至此,大功告成。

最后贴出我主进程background.js的完整代码

  1 'use strict'
  2 
  3 import {
  4   app,
  5   protocol,
  6   browserWindow,
  7   ipcMain,
  8 } from 'electron'
  9 import {
 10   createProtocol
 11 } from 'vue-cli-plugin-electron-builder/lib'
 12 import installExtension, {
 13   VUEJS_DEVTOOLS
 14 } from 'electron-devtools-installer'
 15 const isDevelopment = process.env.NODE_ENV !== 'production'
 16 
 17 const net = require('net');
 18 // Keep a global reference of the window object, if you don't, the window will
 19 // be closed automatically when the JavaScript object is garbage collected.
 20 let win
 21 
 22 // Scheme must be registered before the app is ready
 23 protocol.registerSchemesAsPrivileged([{
 24   scheme: 'app',
 25   privileges: {
 26     secure: true,
 27     standard: true
 28   }
 29 }])
 30 
 31 function createWindow() {
 32   // Create the browser window.
 33   win = new browserWindow({
 34     width: 800,
 35     height: 700,
 36     // 设置窗口的透明属性为true
 37     // transparent:true,
 38     // 禁用认边框,无法拖拽移动窗口,也无法最大化、最小化、关闭窗口
 39     frame: false,
 40     // 透明的窗口不可调整大小,所以将resizable属性也设置为false
 41     // resizable:false,
 42     // 为了防止双击窗口可拖拽区域触发最大化事件,将maximizable属性也设置为false
 43     // maximizable:false,
 44     webPreferences: {
 45       // nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
 46       // 注意devTools可能会影响到transparent
 47       // devTools: false,
 48       nodeIntegration: true,
 49       // enableRemoteModule:true
 50     }
 51   })
 52 
 53   if (process.env.WEBPACK_DEV_SERVER_URL) {
 54     // Load the url of the dev server if in development mode
 55     win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
 56     if (!process.env.IS_TEST) win.webContents.openDevTools()
 57   } else {
 58     createProtocol('app')
 59     // Load the index.html when not in development
 60     win.loadURL('app://./index.html')
 61   }
 62 
 63   win.on('closed', () => {
 64     win = null
 65   })
 66 }
 67 
 68 // Quit when all windows are closed.
 69 app.on('window-all-closed', () => {
 70   // On macOS it is common for applications and their menu bar
 71   // to stay active until the user quits explicitly with Cmd + Q
 72   if (process.platform !== 'darwin') {
 73     app.quit()
 74   }
 75 })
 76 
 77 app.on('activate', () => {
 78   // On macOS it's common to re-create a window in the app when the
 79   // dock icon is clicked and there are no other windows open.
 80   if (win === null) {
 81     createWindow()
 82   }
 83 })
 84 
 85 // This method will be called when Electron has finished
 86 // initialization and is ready to create browser windows.
 87 // Some APIs can only be used after this event occurs.
 88 app.on('ready', async () => {
 89   if (isDevelopment && !process.env.IS_TEST) {
 90     // Install Vue Devtools
 91     try {
 92       await installExtension(VUEJS_DEVTOOLS)
 93     } catch (e) {
 94       console.error('Vue Devtools Failed to install:', e.toString())
 95     }
 96   }
 97 
 98   // 最小化窗体
 99   ipcMain.on('minWindow', () => {
100     win.minimize()
101   })
102 
103   // 关闭窗体
104   ipcMain.on('closeWindow', () => {
105     win.close()
106   })
107 
108   // 最大化窗体
109   ipcMain.on('maxWindow', () => {
110     win.isMaximized() ? win.unmaximize() : win.maximize()
111   })
112 
113   createWindow()
114 })
115 
116 // Exit cleanly on request from parent process in development mode.
117 if (isDevelopment) {
118   if (process.platform === 'win32') {
119     process.on('message', (data) => {
120       if (data === 'graceful-exit') {
121         app.quit()
122       }
123     })
124   } else {
125     process.on('SIGTERM', () => {
126       app.quit()
127     })
128   }
129 }
130 
131 
132 // TCP/IP通讯
133 
134 // 试了半天,才发现这是创建一个 TCP Server 的
135 // function createServer(port) {
136 //   const HOST = '127.0.0.1';
137 //   // const port = 7899;
138 //   if (server) {
139 //     server.close();
140 //   }
141 
142 //   server = net.createServer();
143 
144 //   server.listen(port, HOST, function () {
145 //     console.log('Server listen on port:' + server.address().address);
146 //     console.log('--------------------------------------服务正在监听中---------------------------------------');
147 //     sendServerData('start-server', '服务正在监听中,server is listening...');
148 //   });
149 
150 
151 //   server.on('connection', socket => {
152 //     sendServerData('connect-server', 'Get conneciton from:' + socket.remoteAddress);
153 
154 //     socket.on('data', data => {
155 //       sendServerData('data-server', 'Get data from socket:' + socket.remoteAddress + '. The data:' + data);
156 //       socket.write('you said:' + data);
157 //     });
158 
159 //     socket.on('close', () => {
160 //       sendServerData('close-server', 'Socket:' + socket.remoteAddress + " closed");
161 //     })
162 //   });
163 
164 // }
165 
166 // let server;
167 // let client;
168 // let serverEvent, clientEvent;
169 // // 通过这个方法就可以建立一个TCP服务器,当收到前端发送的event,就可以创建了,这里前端发送的消息是 start-server
170 // ipcMain.on('start-server', (event, arg) => {
171 //   serverEvent = event;
172 //   // event.sender.send()
173 //   console.log('+++++++++++++++++++++++++++ event ++++++++++++++++++++++++++++++++++++++++++++++')
174 //   console.log(event)
175 //   console.log('=================================== arg =============================================')
176 //   console.log(arg)
177 //   createServer(arg);
178 // })
179 
180 // 将消息返回给前端
181 // function sendServerData(channel, msg) {
182 //   try {
183 //     console.log(`server send event ${channel}, ${msg}`);
184 //     if (serverEvent) {
185 //       serverEvent.sender.send(channel, msg);
186 //     }
187 //   } catch (error) {
188 //     console.error('gt error:' + error);
189 //   }
190 // }
191 
192 
193 // 作为客户端
194 var HOST = '127.0.0.1';
195 var PORT = 7899;
196 
197 var client = new net.socket();
198 client.connect(PORT, HOST, function() {
199     console.log('CONNECTED TO: ' + HOST + ':' + PORT);
200     // 建立连接后立即向服务器发送数据,服务器将收到这些数据
201     client.write('Hello TCP/IP! 老子终于通过 Electron 实现和你通信了!!!');
202 });
203 
204 // 为客户端添加“data”事件处理函数
205 // data是服务器发回的数据
206 client.on('data', function(data) {
207     console.log('DATA: ' + data);
208     // 完全关闭连接
209     client.destroy();
210 });
211 
212 // 为客户端添加“close”事件处理函数
213 client.on('close', function() {
214     console.log('Connection closed');
215 });

文章会首发于我的微信公众号:小笑残虹,大家可以关注我,一起交流进步。

 

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐