ホームページ  >  記事  >  バックエンド開発  >  計測データをサーバーにアップロードする機能を実現する計測機器改造技術

計測データをサーバーにアップロードする機能を実現する計測機器改造技術

php是最好的语言
php是最好的语言オリジナル
2018-07-26 15:52:132504ブラウズ

C# を使用して機器の機器を変更するにはどうすればよいですか?機器制御プログラムはC#で開発されているため、クライアントはC#が最適ですが、トラフィックの節約(トラフィックに応じてサーバーに課金される)を考慮すると、ファイルは圧縮する必要があり、ファイル圧縮機能はC#で実装する必要があります。サーバーは、アップロード用の RESTful API を構築するために Java を選択します。

1. プロジェクトの要件と分析

  1. リーダーの要件に従って、機器を改造し、いくつかの機能を追加し、測定データをサーバーにアップロードする必要があります。本器の測定周期は約 20 秒であり、現時点ではデータ量は多くなく、1 回の測定あたり約 2M 未満で、すべて浮動小数点データと整数データです。

  2. 当初はTCPロング接続を使いたかったのですが、現場の環境を考慮して。一般的な製造現場では、電磁環境が複雑でネットワーク信号が不安定であるため、TCP 長時間接続の実装は考慮されていません。短い接続も考慮されておらず、将来的に機器の数が増えた場合、頻繁に接続を確立するコストも非常に高くなり、サーバーが耐えられなくなる可能性があります (Alibaba Cloud の乞食バージョン)。そこで、送信にはrestfulを使用することにしました。http通信はマルチスレッドでスケジュールできます。

  3. 機器制御プログラムは C# で開発されているため、クライアントは C# に最適です。非常に便利な SpringBoot をサーバー側で使用したいと考えています。

  4. 新しいアップロード機能が以前の測定ビートに影響を与えることができないことを考慮すると、これを実装するにはマルチスレッドが必要です。残念ながら、私は怠け者でスレッド調整の問題を考慮したくないため、最終的にメッセージ キューの実装を選択しました。

  5. トラフィックの節約を考慮すると (サーバーはトラフィックに基づいて課金されます)、ファイルは圧縮する必要があり、ファイル圧縮機能は C# で実装する必要があります。

  6. 測定ファイルからデータを読み取り、パラメータをデータベースに保存し、元の測定データをファイル サーバーにパッケージ化します。

2. 全体的なアーキテクチャと技術的ソリューション

最後の技術的解決策は、クライアントとして C# を使用し、Java を使用してサーバー側の RESTful API を構築することです。アップロード

全体的なアーキテクチャは次のとおりです:
計測データをサーバーにアップロードする機能を実現する計測機器改造技術

使用されるテクノロジは次のとおりです:

  1. C# の Restfulクライアント: RestSharp

  2. java の Restful サーバー: springboot

  3. C# 側のメッセージ キュー: NetMQ

  4. C#側zip操作部品:DotNetZip

  5. Java側zip操作部品:Apache Commons Compress

3.Server

サーバーは Springboot RESTful、非常にシンプルな POST メソッドを使用します。
クライアントの ResrSharp はこの方法でのみファイルを転送できるため、ファイルの転送には MultipartFile メソッドが使用されます

@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;
    }
}

4. Client

クライアントのアーキテクチャは次のとおりです。
計測データをサーバーにアップロードする機能を実現する計測機器改造技術

1 zeromq の概要

NetMQ は、ZeroMQ の C# 移植版です。

1.1: zeromqとは

NetMQ (ZeroMQ to .Net)、ZMQは史上最速のミドルウェアとして知られています。
ソケット通信をカプセル化するので、ソケット関数呼び出しを記述せずに複雑なネットワーク通信を完了できます。
それと Socket の違いは: 通常のソケットはエンドツーエンド (1:1 関係) ですが、ZMQ は N:M 関係を持つことができます。BSD ソケットについてはポイントツーポイントとしてよく知られています。接続、ポイントツーポイント接続では、接続の明示的な確立、接続の破棄、プロトコル (TCP/UDP) の選択、エラーの処理などが必要です。ZMQ はこれらの詳細を保護し、ネットワーク プログラミングを簡素化します。
これは、複数のスレッド、コア、ホスト ボックスにわたって柔軟に拡張するメッセージ処理キュー ライブラリです。一般的なメッセージ キュー製品とは異なり、メッセージ キュー サーバーを持たず、ネットワーク通信ライブラリに似ています。ネットワーク通信の観点から見ると、セッション層の上、アプリケーション層の下にあり、トランスポート層に属します。

1.2: zeromq のメッセージ モデル

zeromq は、メッセージ通信を 4 つのモデル、つまり 1 対 1 ペア モデル (Exclusive-Pair)、リクエスト応答モデル (Request-Reply)、Publish- に分割します。サブスクライブ モデル (Publish-Subscribe)、プッシュプル モデル (Push-Pull)。これら 4 つのモデルは一般的なネットワーク通信モデルを要約したもので、実際には、アプリケーションのニーズに応じて 2 つ以上を組み合わせて独自のソリューションを形成できます。

1.2.1 1 対 1 ペアリング モデル Exclusive-Pair

最も単純な 1:1 メッセージ通信モデル。従来の TCP ソケット モデルをサポートするために使用され、主にスレッド間通信に使用されます。プロセス内で。これは TCP 接続と見なすことができますが、TCP サーバーが受け入れることができる接続は 1 つだけです。ロックフリーを使用して実装されており、非常に高速です。データは両方向に流れることができます。これは、後の要求/応答モデルとは異なります。 (非推奨、例なし)

1.2.2 请求回应模型 Request-Reply

由请求端发起请求,然后等待回应端应答。一个请求必须对应一个回应,从请求端的角度来看是发-收配对,从回应端的角度是收-发对。跟一对一结对模型的区别在于请求端可以是1~N个。
请求端和回应端都可以是1:N的模型。通常把1认为是server,N认为是Client。ZeroMQ可以很好的支持路由功能(实现路由功能的组件叫作Device),把1:N扩展为N:M(只需要加入若干路由节点)。从这个模型看,更底层的端点地址是对上层隐藏的。每个请求都隐含有回应地址,而应用则不关心它。通常把该模型主要用于远程调用及任务分配等。
(NetMQ请求响应C#调用案例)

1.2.3 发布订阅模型 Publisher-Subscriber(本项目采用的模型)

发布端单向分发数据,且不关心是否把全部信息发送给订阅端。如果发布端开始发布信息时,订阅端尚未连接上来,则这些信息会被直接丢弃。订阅端未连接导致信息丢失的问题,可以通过与请求回应模型组合来解决。订阅端只负责接收,而不能反馈,且在订阅端消费速度慢于发布端的情况下,会在订阅端堆积数据。该模型主要用于数据分发。天气预报、微博明星粉丝可以应用这种经典模型。 (NetMQ发布订阅模式C#调用案例)

1.2.4 推拉模型 Push-Pull

Server端作为Push端,而Client端作为Pull端,如果有多个Client端同时连接到Server端,则Server端会在内部做一个负载均衡,采用平均分配的算法,将所有消息均衡发布到Client端上。与发布订阅模型相比,推拉模型在没有消费者的情况下,发布的消息不会被消耗掉;在消费者能力不够的情况下,能够提供多消费者并行消费解决方案。该模型主要用于多任务并行。
(NetMQ推拉模式C#调用案例)

1.3:zeromq的优势

  1. TCP:ZeroMQ基于消息,消息模式,而非字节流。

  2. XMPP:ZeroMQ更简单、快速、更底层。Jabber可建在ZeroMQ之上。

  3. AMQP:完成相同的工作,ZeroMQ要快100倍,而且不需要代理(规范更简洁——少278页)

  4. IPC:ZeroMQ可以跨多个主机盒,而非单台机器。

  5. CORBA:ZeroMQ不会将复杂到恐怖的消息格式强加于你。

  6. RPC:ZeroMQ完全是异步的,你可以随时增加/删除参与者。

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

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

  9. IBM低延迟:ZeroMQ是自由软件!

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

2.代码实现

2.1 Publisher(发布者)

一般都是发布者先启动,绑定监听端口。封装了一个发送函数,主要是发送原先软件生成测量文件的路径。

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

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="port">绑定的端口</param>
        public Publisher(int port)
        {
            Port = port;
        }

        /// <summary>
        /// 启动发布端
        /// </summary>
        public void Start()
        {
            NetMQContext context = NetMQContext.Create();
            this.socket = context.CreatePublisherSocket();
            this.socket.Bind("tcp://127.0.0.1:" + Port);
        }

        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="result"></param>
        public void Send(string result)
        {
            socket.SendFrame(result);
        }
    }

2.2 Subscriber(订阅者)

订阅者启动时候连接端口。防止线程阻塞,订阅者是新开一个线程运行的。

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 客户端压缩

压缩使用DotNetZip组件,非常简单好用。

 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 客户端上传

使用RestSharp组件,也是非常简单。异步回调,不影响性能。

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($"出错啦:{response.Content}");
                    }
                }
            );
        }
    }

五、总结

  1. 写代码之前一定要搞清楚需求,设计好架构

  2. 注意消息队列启动时候的线程问题

  3. 异步执行

相关文章:

企业数据备份技术

相关视频:

数据结构探险—队列篇

以上が計測データをサーバーにアップロードする機能を実現する計測機器改造技術の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。