溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

C#中儀器設(shè)備改造技術(shù)如何實(shí)現(xiàn)測(cè)量數(shù)據(jù)上傳到服務(wù)器的功能

發(fā)布時(shí)間:2020-10-23 17:03:40 來(lái)源:億速云 閱讀:229 作者:小新 欄目:編程語(yǔ)言

這篇文章主要介紹C#中儀器設(shè)備改造技術(shù)如何實(shí)現(xiàn)測(cè)量數(shù)據(jù)上傳到服務(wù)器的功能,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!

                                                           怎樣用C#進(jìn)行儀器的設(shè)備改造?因?yàn)閮x器控制程序是C#開(kāi)發(fā)的,所以客戶(hù)端最好是c#,考慮到節(jié)省流量(服務(wù)器是按流量收費(fèi)的),文件要壓縮,C#下要實(shí)現(xiàn)文件壓縮功能。而服務(wù)端選擇java構(gòu)建restful API進(jìn)行上傳的的方案。

一、項(xiàng)目需求及分析

  1. 按照領(lǐng)導(dǎo)的要求,要改造一臺(tái)儀器,添加點(diǎn)功能,將測(cè)量數(shù)據(jù)上傳到服務(wù)器。儀器測(cè)量節(jié)拍大概是20s,數(shù)據(jù)量目前不大,每次測(cè)量大概不到2M左右,且都是浮點(diǎn)數(shù)據(jù)和整形數(shù)據(jù)。

  2. 起初想用TCP長(zhǎng)連接實(shí)現(xiàn)的,但考慮到現(xiàn)場(chǎng)環(huán)境。典型的制造業(yè)車(chē)間,電磁環(huán)境復(fù)雜,網(wǎng)絡(luò)信號(hào)不穩(wěn),所以不考慮TCP長(zhǎng)連接實(shí)現(xiàn)。短連接也不在考慮范圍內(nèi),以后儀器數(shù)量多了之后頻繁的建立連接開(kāi)銷(xiāo)也很大,服務(wù)器有可能受不了(阿里云的乞丐版)。所以選擇用restful提交,http的通信可以多線(xiàn)程調(diào)度。

  3. 儀器控制程序是C#開(kāi)發(fā)的,所以客戶(hù)端最好是c#。服務(wù)端我想用springboot,很方便。

  4. 考慮到新增的上傳功能不能影響之前的測(cè)量節(jié)拍,所以要多線(xiàn)程實(shí)現(xiàn)??上矣趾軕?,不想考慮線(xiàn)程協(xié)調(diào)問(wèn)題,最后選擇消息隊(duì)列實(shí)現(xiàn)。

  5. 考慮到節(jié)省流量(服務(wù)器是按流量收費(fèi)的),文件要壓縮,C#下要實(shí)現(xiàn)文件壓縮功能。

  6. 從測(cè)量文件中讀取數(shù)據(jù),將參數(shù)存入數(shù)據(jù)庫(kù),測(cè)量原始數(shù)據(jù)打包放在文件服務(wù)器上。

二、整體架構(gòu)和技術(shù)方案

最后的技術(shù)方案就是C#做客戶(hù)端,java構(gòu)建服務(wù)端restful API進(jìn)行上傳

整體架構(gòu)如下圖:
C#中儀器設(shè)備改造技術(shù)如何實(shí)現(xiàn)測(cè)量數(shù)據(jù)上傳到服務(wù)器的功能

使用的技術(shù)如下:

  1. C#的Restful客戶(hù)端:RestSharp

  2. java的Restful服務(wù)端:springboot

  3. C#端消息隊(duì)列:NetMQ

  4. C#端zip操作組件:DotNetZip

  5. java端zip操作組件:Apache Commons Compress

三、服務(wù)端

服務(wù)端采用springboot的restful,POST方式,非常簡(jiǎn)單。
傳輸文件采用MultipartFile方式,因?yàn)榭蛻?hù)端的ResrSharp只能采用這種方式傳遞文件

@RestController
@RequestMapping(value = "upload")
public class FileRestController {
    Logger logger = LogManager.getLogger(FileRestController.class);

    @RequestMapping(value = "file", method = RequestMethod.POST)
    public
    @ResponseBody
    RestResult getZipFile(@RequestParam("file") MultipartFile file) throws IOException, URISyntaxException {
        RestResult result = new RestResult();
        if (!file.getName().isEmpty()) {
            InputStream stream = file.getInputStream();
//            String directory = FileRestController.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath();
            String directory = "/usr/local/haliang/files/";
            try {
                directory = URLDecoder.decode(directory, "utf-8");
            } catch (java.io.UnsupportedEncodingException e) {
                return null;
            }
            FileOutputStream fs = new FileOutputStream(directory + file.getOriginalFilename());
            logger.info("文件所在的目錄:   " + directory + "/files/" + file.getOriginalFilename());
            byte[] buffer = new byte[1024 * 1024];
            int bytesum = 0;
            int byteread = 0;
            while ((byteread = stream.read(buffer)) != -1) {
                bytesum += byteread;
                fs.write(buffer, 0, byteread);
                fs.flush();
            }
            fs.close();
            stream.close();
            logger.info("成功接收文件:   " + directory + file.getOriginalFilename());
        }

        return result;
    }
}

四、客戶(hù)端

客戶(hù)端架構(gòu)如下圖:
C#中儀器設(shè)備改造技術(shù)如何實(shí)現(xiàn)測(cè)量數(shù)據(jù)上傳到服務(wù)器的功能

1 zeromq簡(jiǎn)介

NetMQ 是 ZeroMQ的C#移植版本。

1.1:zeromq是什么

NetMQ (ZeroMQ to .Net),ZMQ號(hào)稱(chēng)史上最快中間件。
它對(duì)socket通信進(jìn)行了封裝,使得我們不需要寫(xiě)socket函數(shù)調(diào)用就能完成復(fù)雜的網(wǎng)絡(luò)通信。
它跟Socket的區(qū)別是:普通的socket是端到端的(1:1的關(guān)系),而ZMQ卻是可以N:M的關(guān)系,人們對(duì)BSD套接字的了解較多的是點(diǎn)對(duì)點(diǎn)的連接,點(diǎn)對(duì)點(diǎn)連接需要顯式地建立連接、銷(xiāo)毀連接、選擇協(xié)議(TCP/UDP)和處理錯(cuò)誤等,而ZMQ屏蔽了這些細(xì)節(jié),讓你的網(wǎng)絡(luò)編程更為簡(jiǎn)單。
它是一個(gè)消息處理隊(duì)列庫(kù),可在多個(gè)線(xiàn)程、內(nèi)核和主機(jī)盒之間彈性伸縮。和一般意義上的消息隊(duì)列產(chǎn)品不同的是,它沒(méi)有消息隊(duì)列服務(wù)器,而更像是一個(gè)網(wǎng)絡(luò)通信庫(kù)。從網(wǎng)絡(luò)通信的角度看,它處于會(huì)話(huà)層之上,應(yīng)用層之下,屬于傳輸層。

1.2:zeromq的消息模型

zeromq將消息通信分為4種模型,分別是一對(duì)一結(jié)對(duì)模型(Exclusive-Pair)、請(qǐng)求回應(yīng)模型(Request-Reply)、發(fā)布訂閱模型(Publish-Subscribe)、推拉模型(Push-Pull)。這4種模型總結(jié)出了通用的網(wǎng)絡(luò)通信模型,在實(shí)際中可以根據(jù)應(yīng)用需要,組合其中的2種或多種模型來(lái)形成自己的解決方案。

1.2.1 一對(duì)一結(jié)對(duì)模型 Exclusive-Pair

最簡(jiǎn)單的1:1消息通信模型,用來(lái)支持傳統(tǒng)的 TCP socket模型,主要用于進(jìn)程內(nèi)部線(xiàn)程間通信??梢哉J(rèn)為是一個(gè)TCP Connection,但是TCP Server只能接受一個(gè)連接。采用了lock free實(shí)現(xiàn),速度很快。數(shù)據(jù)可以雙向流動(dòng),這點(diǎn)不同于后面的請(qǐng)求響應(yīng)模型。(不推薦使用,沒(méi)有例子)

1.2.2 請(qǐng)求回應(yīng)模型 Request-Reply

由請(qǐng)求端發(fā)起請(qǐng)求,然后等待回應(yīng)端應(yīng)答。一個(gè)請(qǐng)求必須對(duì)應(yīng)一個(gè)回應(yīng),從請(qǐng)求端的角度來(lái)看是發(fā)-收配對(duì),從回應(yīng)端的角度是收-發(fā)對(duì)。跟一對(duì)一結(jié)對(duì)模型的區(qū)別在于請(qǐng)求端可以是1~N個(gè)。
請(qǐng)求端和回應(yīng)端都可以是1:N的模型。通常把1認(rèn)為是server,N認(rèn)為是Client。ZeroMQ可以很好的支持路由功能(實(shí)現(xiàn)路由功能的組件叫作Device),把1:N擴(kuò)展為N:M(只需要加入若干路由節(jié)點(diǎn))。從這個(gè)模型看,更底層的端點(diǎn)地址是對(duì)上層隱藏的。每個(gè)請(qǐng)求都隱含有回應(yīng)地址,而應(yīng)用則不關(guān)心它。通常把該模型主要用于遠(yuǎn)程調(diào)用及任務(wù)分配等。
(NetMQ請(qǐng)求響應(yīng)C#調(diào)用案例)

1.2.3 發(fā)布訂閱模型 Publisher-Subscriber(本項(xiàng)目采用的模型)

發(fā)布端單向分發(fā)數(shù)據(jù),且不關(guān)心是否把全部信息發(fā)送給訂閱端。如果發(fā)布端開(kāi)始發(fā)布信息時(shí),訂閱端尚未連接上來(lái),則這些信息會(huì)被直接丟棄。訂閱端未連接導(dǎo)致信息丟失的問(wèn)題,可以通過(guò)與請(qǐng)求回應(yīng)模型組合來(lái)解決。訂閱端只負(fù)責(zé)接收,而不能反饋,且在訂閱端消費(fèi)速度慢于發(fā)布端的情況下,會(huì)在訂閱端堆積數(shù)據(jù)。該模型主要用于數(shù)據(jù)分發(fā)。天氣預(yù)報(bào)、微博明星粉絲可以應(yīng)用這種經(jīng)典模型。 (NetMQ發(fā)布訂閱模式C#調(diào)用案例)

1.2.4 推拉模型 Push-Pull

Server端作為Push端,而Client端作為Pull端,如果有多個(gè)Client端同時(shí)連接到Server端,則Server端會(huì)在內(nèi)部做一個(gè)負(fù)載均衡,采用平均分配的算法,將所有消息均衡發(fā)布到Client端上。與發(fā)布訂閱模型相比,推拉模型在沒(méi)有消費(fèi)者的情況下,發(fā)布的消息不會(huì)被消耗掉;在消費(fèi)者能力不夠的情況下,能夠提供多消費(fèi)者并行消費(fèi)解決方案。該模型主要用于多任務(wù)并行。
(NetMQ推拉模式C#調(diào)用案例)

1.3:zeromq的優(yōu)勢(shì)
  1. TCP:ZeroMQ基于消息,消息模式,而非字節(jié)流。

  2. XMPP:ZeroMQ更簡(jiǎn)單、快速、更底層。Jabber可建在ZeroMQ之上。

  3. AMQP:完成相同的工作,ZeroMQ要快100倍,而且不需要代理(規(guī)范更簡(jiǎn)潔——少278頁(yè))

  4. IPC:ZeroMQ可以跨多個(gè)主機(jī)盒,而非單臺(tái)機(jī)器。

  5. CORBA:ZeroMQ不會(huì)將復(fù)雜到恐怖的消息格式強(qiáng)加于你。

  6. RPC:ZeroMQ完全是異步的,你可以隨時(shí)增加/刪除參與者。

  7. RFC 1149:ZeroMQ比它快多了!

  8. 29west LBM:ZeroMQ是自由軟件!

  9. IBM低延遲:ZeroMQ是自由軟件!

  10. Tibco:仍然是自由軟件!

2.代碼實(shí)現(xiàn)

2.1 Publisher(發(fā)布者)

一般都是發(fā)布者先啟動(dòng),綁定監(jiān)聽(tīng)端口。封裝了一個(gè)發(fā)送函數(shù),主要是發(fā)送原先軟件生成測(cè)量文件的路徑。

public class Publisher
    {
        public int Port { get; set; }
        private PublisherSocket socket;

        /// <summary>
        /// 構(gòu)造函數(shù)
        /// </summary>
        /// <param name="port">綁定的端口</param>
        public Publisher(int port)
        {
            Port = port;
        }

        /// <summary>
        /// 啟動(dòng)發(fā)布端
        /// </summary>
        public void Start()
        {
            NetMQContext context = NetMQContext.Create();
            this.socket = context.CreatePublisherSocket();
            this.socket.Bind("tcp://127.0.0.1:" + Port);
        }

        /// <summary>
        /// 發(fā)送數(shù)據(jù)
        /// </summary>
        /// <param name="result"></param>
        public void Send(string result)
        {
            socket.SendFrame(result);
        }
    }
2.2 Subscriber(訂閱者)

訂閱者啟動(dòng)時(shí)候連接端口。防止線(xiàn)程阻塞,訂閱者是新開(kāi)一個(gè)線(xiàn)程運(yùn)行的。

public class Subscribe
    {
        private delegate void GetDataHandler(string message);

        private event GetDataHandler onGetData;
        public int Port { get; set; }
        public string TempDirectory { get; set; }
        public bool isRunning { get; set; }
        public string domain { get; set; }

        public Subscribe(int port, string domain)
        {
            Port = port;
            this.domain = domain;
            onGetData += ProcessData;
        }

        private SubscriberSocket socket;

        public void Start()
        {
            this.isRunning = true;
            NetMQContext context = NetMQContext.Create();
            socket = context.CreateSubscriberSocket();
            socket.Connect("tcp://127.0.0.1:" + Port);
            socket.Subscribe("");
            Thread t = new Thread(new ThreadStart(StartSub));
            t.Start();
        }

        private void StartSub()
        {
            while (isRunning)
            {
                Thread.Sleep(10000);
                string result = socket.ReceiveFrameString(Encoding.UTF8);
                onGetData(result);
            }
        }

        private void ProcessData(string path)
        {
            Console.WriteLine("收到文件:" + path);
            string compressedFile = Compress.CompressFile(TempDirectory, path);
            new RestPost(domain).Post(compressedFile);
        }

3 客戶(hù)端壓縮

壓縮使用DotNetZip組件,非常簡(jiǎn)單好用。

 public class Compress
    {
        public static string CompressFile(string temp,string txtPath)
        {
            string txtFileName = System.IO.Path.GetFileNameWithoutExtension(txtPath);
            string compressedFileName = temp+"/"+txtFileName + ".zip";
            ZipFile file=new ZipFile();
            file.AddFile(txtPath,"");
            file.Save(compressedFileName);
            return compressedFileName;
        }
    }

4 客戶(hù)端上傳

使用RestSharp組件,也是非常簡(jiǎn)單。異步回調(diào),不影響性能。

public class RestPost
    {
        public string Domain { get; set; }

        public RestPost(string domain)
        {
            Domain = domain;
        }

        public void Post(string path)
        {
            RestRequest request = new RestRequest(Method.POST);
            request.AddFile("file", path);
            RestClient client = new RestClient {BaseUrl = new Uri("http://" + Domain + "/upload/file")};
            client.ExecuteAsync(request, (response) =>
                {
                    if (response.StatusCode == HttpStatusCode.OK)
                    {
                        Console.WriteLine("上傳成功...\n" + response.Content);
                    }
                    else
                    {
                        Console.WriteLine($"出錯(cuò)啦:{response.Content}");
                    }
                }
            );
        }
    }

以上是C#中儀器設(shè)備改造技術(shù)如何實(shí)現(xiàn)測(cè)量數(shù)據(jù)上傳到服務(wù)器的功能的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI