一文學(xué)會(huì)搭建HTTP服務(wù)器調(diào)用DLL庫
如何搭建HTTP服務(wù)器調(diào)用DLL庫
之前在幫朋友救急時(shí),忽然想到了這個(gè)方法,就是通過HTTP服務(wù)器調(diào)用DLL庫。在某些情況下,我們可能需要遠(yuǎn)程調(diào)用本地的 DLL 庫。為了實(shí)現(xiàn)這個(gè)目標(biāo),我們可以搭建一個(gè) HTTP 服務(wù)器,通過發(fā)送 HTTP 請(qǐng)求來調(diào)用 DLL 庫的函數(shù)。這種方法可以讓我們?cè)诓粚?DLL 庫放到遠(yuǎn)程機(jī)器上的情況下,實(shí)現(xiàn)對(duì) DLL 函數(shù)的遠(yuǎn)程調(diào)用。
環(huán)境:MacOS + Node 18.0.0
目的:酒店的房卡系統(tǒng),通過HTTP服務(wù)器調(diào)用DLL庫,實(shí)現(xiàn)對(duì)房卡的讀取、寫入、刪除等操作。
準(zhǔn)備階段
- 安裝 Node.js:首先,我們需要安裝 Node.js。Node.js 是一個(gè)基于 Chrome V8 引擎的 JavaScript 運(yùn)行時(shí),它可以幫助我們構(gòu)建高效的網(wǎng)絡(luò)應(yīng)用程序。
- 創(chuàng)建 HTTP 服務(wù)器:使用 Node.js 的內(nèi)置模塊,我們可以輕松地創(chuàng)建一個(gè)簡單的 HTTP 服務(wù)器。我們將展示如何編寫一個(gè)簡單的 Node.js 腳本,以創(chuàng)建一個(gè)監(jiān)聽特定端口的 HTTP 服務(wù)器。這里我們使用express框架。
- 調(diào)用 DLL 庫:為了調(diào)用 DLL 庫,我們將使用 Node.js 的 "ffi" 模塊。該模塊允許我們加載和調(diào)用動(dòng)態(tài)鏈接庫(DLL)中的函數(shù)。我們將演示如何使用 "ffi" 模塊加載 DLL 庫,并調(diào)用其中的函數(shù)。
搭建基礎(chǔ)讀取DLL庫
首先創(chuàng)建一個(gè)文件夾:mkdir http-dll
,然后進(jìn)入該文件夾:cd http-dll
。
1.1 創(chuàng)建 package.json 文件
在該文件夾下創(chuàng)建 package.json 文件:pnpm init -y
。
1.2 安裝依賴
安裝依賴:pnpm i ffi ref-struct ref-array ref
。
1.3 讀取
搭建的過程不重要,為什么用的原因更重要,其次是思考怎么處理,最后是設(shè)計(jì)使用的方法。
假如這里我們使用的是LockSDK.dll
,這里只是為了演示,提供了基礎(chǔ)的4個(gè)方法,因此以這4個(gè)方法為例子。
- TP_Configuration:動(dòng)態(tài)庫初始化配置,完成門鎖類型選擇/發(fā)卡器連接等
- TP_MakeGuestCardEx: 制作賓客卡
- TP_ReadGuestCardEx: 讀賓客卡信息
- TP_CancelCard: 注銷卡片/卡片回收
此處不展示具體的C代碼,而直接以DLL庫的形式提供給我們使用。
首先要考慮一個(gè)問題,單純從文檔里拿去使用和調(diào)用的話,會(huì)出現(xiàn)什么問題?
- 每次使用都需要讀文檔
- 每次使用都需要重新編寫代碼
- 沒有統(tǒng)一的調(diào)用方法,很容易出現(xiàn)凌亂的管理
那我們需要在此設(shè)置一個(gè)目標(biāo),就是將這些方法封裝起來,統(tǒng)一調(diào)用,方便管理。而我們創(chuàng)建一個(gè)conf目錄,用于存放配置文件,創(chuàng)建dll.conf.js
文件,用于存放dll配置信息。
/** 函數(shù)名:TP_Configuration 功能:動(dòng)態(tài)庫初始化配置,完成門鎖類型選擇/發(fā)卡器連接等 @param {number} lock_type - 門鎖類型(也就是使用的卡片類型): 4-RF57門鎖; 5-RF50門鎖 @returns {number} - 錯(cuò)誤類型 注意:此函數(shù)為 __stdcall 調(diào)用約定,如果您的函數(shù)庫采用的是 __cdecl 調(diào)用約定,需要將其修改為 __stdcall 調(diào)用約定。 */ export const TP_Configuration = { "TP_Configuration": [ "int", // return // parameters ["int"], ], };
- 這種配置方法是為了方便ffi調(diào)用,暫且不表。
如果只是這種方式配置,那么我們還是需要每次都去讀文件,然后重新編寫,這樣就沒有意義了。因此我們需要考慮一個(gè)更方便的方式,也就是放置在一個(gè)統(tǒng)一的文件內(nèi),通過調(diào)用這個(gè)文件,來獲取我們需要的所有方法。
因此創(chuàng)建conf.js文件,用于存放所有的方法。
const { TP_Configuration, TP_MakeGuestCardEx, TP_ReadGuestCardEx, TP_CancelCard } = require('./dll.conf.js') export const LIB_NAME = "../dll/mylib.dll" export const lib_func = { TP_Configuration, TP_MakeGuestCardEx, TP_ReadGuestCardEx, TP_CancelCard } module.exports = { LIB_NAME, lib_func }
此時(shí)我們已經(jīng)配置好了conf的配置文件,那么下一步,我們就需要實(shí)現(xiàn)讀取和調(diào)用的方法。
我們創(chuàng)建一個(gè)core目錄,用于存放核心方法,創(chuàng)建load.js文件,用于存放核心方法。
const { lib_func, LIB_NAME } = require('../conf/conf.js') const ffi = require('ffi'); const ref = require('ref'); const { TP_Configuration, TP_MakeGuestCardEx, TP_ReadGuestCardEx, TP_CancelCard } = ffi.Library(LIB_NAME, lib_func); module.exports = { TP_Configuration, TP_MakeGuestCardEx, TP_ReadGuestCardEx, TP_CancelCard }
ffi
模塊,用于加載和調(diào)用動(dòng)態(tài)鏈接庫(DLL)中的函數(shù)。ref
模塊,用于處理C語言中的指針問題。- 這里我們將Library從DLL里讀取出來的函數(shù),放置在一個(gè)對(duì)象里,方便外部調(diào)用。此處我們讓HTTP服務(wù)器來調(diào)用
1.4 創(chuàng)建HTTP服務(wù)器
安裝express
框架,然后在創(chuàng)建server
目錄,用于存放HTTP服務(wù)器。
在server
目錄下創(chuàng)建app.js
文件,用于存放HTTP服務(wù)器。
const express = require('express'); class App { routes; app = express(); constructor(routes) { this.routes = routes; this.requestEntry() } requestEntry() { this.routes.forEach(route => { this.app[route.method](route.path, route.handler) }) } listen(port) { app.listen(port, () => { console.log(`Example app listening at http://localhost:${port}`) }) } } module.exports = { App }
- 此處我們將HTTP服務(wù)器的創(chuàng)建和路由的配置分離,方便管理。
下面我們創(chuàng)建目錄文件routes.js
,用于存放路由配置。
const CancelController = require('./controller/cancel.controller.js') const ConfigurationController = require('./controller/configuration.controller.js') const MakeGuestCardEx = require('./controller/MakeGuestCardEx.controller') const ReadGuestCardExController = require('./controller/ReadGuestCardExController.controller') const routes = [ { path: '/cancel', method: 'post', handler: new CancelController(), }, { path: '/configuration', method: 'post', handler: new ConfigurationController(), }, { path: '/make-guest-card-ex', method: 'post', handler: new MakeGuestCardEx(), }, { path: '/read-guest-card-ex', method: 'post', handler: new ReadGuestCardExController(), } ] module.exports = { routes }
在邏輯上,我們需要把每個(gè)路由的處理邏輯分離出來,因此我們創(chuàng)建controller
目錄,用于存放路由處理邏輯。
在controller
目錄下創(chuàng)建cancel.controller.js
文件,用于存放路由處理邏輯。
const ref = require("ref"); const { TP_CancelCard } = require("../../core/load"); class CancelController { constructor() {} async handler(_req, res) { try { const card_snr = _req.body.card_snr || ref.allocCString("", 20); const result = await TP_CancelCard(card_snr); const card_snr_str = ref.readCString(card_snr); return res.status(201).send({ data: { result, card_snr_str, }, }); } catch (error) { res.status(500).json(error); } } } module.exports = CancelController
- 到這個(gè)時(shí)候,我們已經(jīng)完成了對(duì)DLL的函數(shù)的一個(gè)完整的調(diào)用,并且把這個(gè)調(diào)用封裝成了一個(gè)HTTP服務(wù)器,方便我們通過網(wǎng)頁端來進(jìn)行處理。
此外,我們還需要一個(gè)main.js
文件,用于啟動(dòng)HTTP服務(wù)器。
const App = require('./server/app.js') const { routes } = require('./server/routes.js') const app = new App(routes); app.listen(3000)
到這一步,整體流程就走完了。我們只需要在終端中輸入node main.js
,就可以啟動(dòng)HTTP服務(wù)器了。
最終結(jié)果
目錄結(jié)構(gòu)如下:
. ├── conf │ ├── conf.js │ └── dll.conf.js ├── core │ └── load.js ├── dll │ └── LockSDK.dll ├── main.js ├── mock │ └── mockUse.js ├── package.json ├── pnpm-lock.yaml └── server ├── app.js ├── controller │ ├── cancel.controller.js │ ├── configuration.controller.js │ ├── makeGuestCardEx.js │ └── readGuestCardEx.controller.js └── routes.js
Reference Node-DLL
以上就是一文學(xué)會(huì)搭建HTTP服務(wù)器調(diào)用DLL庫的詳細(xì)內(nèi)容,更多關(guān)于HTTP服務(wù)器調(diào)用DLL庫搭建的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
如何設(shè)置process.env.NODE_ENV生產(chǎn)環(huán)境模式
process.env.NODE_ENV默認(rèn)只有兩種狀態(tài)即development和production,本文主要介紹了process.env.NODE_ENV設(shè)置生產(chǎn)環(huán)境模式,感興趣的可以了解一下2021-09-09Nodejs + Websocket 指定發(fā)送及群聊的實(shí)現(xiàn)
這篇文章主要介紹了Nodejs + Websocket 指定發(fā)送及群聊的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01淺談Express.js解析Post數(shù)據(jù)類型的正確姿勢(shì)
這篇文章主要介紹了Express.js解析Post數(shù)據(jù)類型的正確姿勢(shì),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-05-05nodeJs爬蟲的技術(shù)點(diǎn)總結(jié)
本篇文章給大家總結(jié)了關(guān)于nodeJs爬蟲的技術(shù)點(diǎn)的相關(guān)知識(shí),對(duì)爬蟲有興趣的朋友可以跟著學(xué)習(xí)參考下。2018-05-05利用Node轉(zhuǎn)換Excel成JSON的詳細(xì)步驟
最近工作中遇到一個(gè)需求,大致需求就是將Excel文件在導(dǎo)入時(shí)解析為json格式轉(zhuǎn)換數(shù)據(jù)結(jié)構(gòu)再傳輸給后臺(tái),下面這篇文章主要給大家介紹了關(guān)于如何利用Node轉(zhuǎn)換Excel成JSON的詳細(xì)步驟,需要的朋友可以參考下2022-11-11node.js學(xué)習(xí)總結(jié)之調(diào)式代碼的方法
調(diào)式代碼很多時(shí)候類似于查案一樣,只是結(jié)果的重要程度不同,警察查案為的是人民安穩(wěn),而我們調(diào)式則是為了系統(tǒng)的安穩(wěn)。既然這樣我們就不要冤枉任何一段代碼和程序,以免他們受到不合理的懲罰。2014-06-06