Maison  >  Article  >  développement back-end  >  Technologie de modification des instruments et des équipements pour réaliser la fonction de téléchargement des données de mesure sur le serveur

Technologie de modification des instruments et des équipements pour réaliser la fonction de téléchargement des données de mesure sur le serveur

php是最好的语言
php是最好的语言original
2018-07-26 15:52:132443parcourir

Comment utiliser C# pour modifier l'équipement de l'instrument ? Le programme de contrôle des instruments étant développé en C#, il est préférable que le client soit en C#. Compte tenu de l'économie de trafic (le serveur est facturé en fonction du trafic), les fichiers doivent être compressés et la fonction de compression de fichiers doit être implémentée sous C#. Le serveur choisit Java pour créer une API reposante pour le téléchargement.

1. Exigences et analyse du projet

  1. Selon les exigences du leader, un instrument doit être modifié, ajouter quelques fonctions et télécharger les données de mesure sur le serveur. Le cycle de mesure de l'instrument est d'environ 20 secondes et la quantité de données n'est actuellement pas importante. Chaque mesure est d'environ moins de 2 millions, et ce sont toutes des données à virgule flottante et des données entières.

  2. Au début, je voulais utiliser une connexion longue TCP, mais en tenant compte de l'environnement sur site. Dans un atelier de fabrication typique, l'environnement électromagnétique est complexe et le signal réseau est instable, la mise en œuvre d'une connexion TCP longue n'est donc pas prise en compte. Les connexions courtes ne sont pas non plus prises en compte.À l'avenir, lorsque le nombre d'instruments augmentera, le coût de l'établissement fréquent de connexions sera également très élevé et le serveur pourrait ne pas être en mesure de le supporter (version mendiante d'Alibaba Cloud). J'ai donc choisi d'utiliser restful pour la soumission, et la communication http peut être programmée par multi-threads.

  3. Le programme de contrôle des instruments est développé en C#, le client est donc meilleur en C#. Je souhaite utiliser Springboot côté serveur, ce qui est très pratique.

  4. Étant donné que la nouvelle fonction de téléchargement ne peut pas affecter le battement de mesure précédent, le multi-threading est nécessaire pour la mettre en œuvre. Malheureusement, je suis paresseux et je ne veux pas prendre en compte les problèmes de coordination des threads, j'ai donc finalement choisi l'implémentation de la file d'attente de messages.

  5. Considérant que pour économiser du trafic (le serveur est facturé en fonction du trafic), les fichiers doivent être compressés et la fonction de compression de fichiers doit être implémentée en C#.

  6. Lisez les données du fichier de mesure, stockez les paramètres dans la base de données et regroupez les données de mesure originales sur le serveur de fichiers.

2. Architecture globale et solution technique

La solution technique finale consiste à utiliser C# comme client et Java pour créer l'API restful côté serveur pour mise en ligne

L'architecture globale est la suivante :
Technologie de modification des instruments et des équipements pour réaliser la fonction de téléchargement des données de mesure sur le serveur

La technologie utilisée est la suivante :

  1. Restful de C# client : RestSharp

  2. java Serveur Restful : springboot

  3. File d'attente de messages côté C# : NetMQ

  4. C# Composant d'opération zip latéral :DotNetZip

  5. java Composant d'opération zip latéral: Apache Commons Compress

3. Serveur

Le le serveur utilise Springboot Restful, méthode POST, très simple.
MultipartFile est utilisé pour transférer des fichiers, car le ResrSharp du client ne peut transférer des fichiers que de cette manière

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

Client

L'architecture du client est la suivante. suit l'image :
Technologie de modification des instruments et des équipements pour réaliser la fonction de téléchargement des données de mesure sur le serveur

1 Introduction à Zeromq

NetMQ est la version portée en C# de ZeroMQ.

1.1 : Qu'est-ce que Zeromq

NetMQ (ZeroMQ vers .Net), ZMQ est connu comme le middleware le plus rapide de l'histoire.
Il encapsule la communication socket afin que nous puissions effectuer une communication réseau complexe sans écrire d'appels de fonction socket.
La différence entre celui-ci et Socket est la suivante : le socket ordinaire est de bout en bout (relation 1:1), mais ZMQ peut avoir une relation N:M. Les gens en savent plus sur les sockets BSD en tant que connexion point à point. la connexion point à point nécessite l'établissement explicite de la connexion, la destruction de la connexion, la sélection du protocole (TCP/UDP) et la gestion des erreurs, etc. ZMQ protège ces détails, simplifiant ainsi la programmation de votre réseau.
Il s'agit d'une bibliothèque de files d'attente de traitement de messages qui évolue de manière élastique sur plusieurs threads, cœurs et boîtes hôtes. Différent des produits de file d'attente de messages généraux, il ne dispose pas de serveur de file d'attente de messages, mais ressemble davantage à une bibliothèque de communication réseau. Du point de vue de la communication réseau, elle se situe au-dessus de la couche session et en dessous de la couche application, et appartient à la couche transport.

1.2 : le modèle de message de Zeromq

Zeromq divise la communication par message en quatre modèles, à savoir le modèle de paire un-à-un (Exclusive-Pair), le modèle de demande-réponse (Demande-Réponse), Publier -Modèle d'abonnement (Publish-Subscribe), modèle push-pull (Push-Pull). Ces quatre modèles résument le modèle général de communication réseau. En pratique, vous pouvez combiner deux ou plusieurs de ces modèles pour former votre propre solution en fonction des besoins de l'application.

1.2.1 Modèle d'appariement un-à-un Paire exclusive

Le modèle de communication de message 1:1 le plus simple, utilisé pour prendre en charge le modèle de socket TCP traditionnel, principalement utilisé pour l'inter-processus -fil de communication. Cela peut être considéré comme une connexion TCP, mais le serveur TCP ne peut accepter qu'une seule connexion. Il est implémenté sans verrouillage et est très rapide. Les données peuvent circuler dans les deux sens, ce qui est différent du modèle requête-réponse ultérieur. (Non recommandé, pas d'exemples)

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. 异步执行

相关文章:

企业数据备份技术

相关视频:

数据结构探险—队列篇

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn