집 >백엔드 개발 >C#.Net 튜토리얼 >측정 데이터를 서버에 업로드하는 기능을 구현하는 기기 및 장비 개조 기술
C#을 사용하여 악기 장비를 수정하는 방법은 무엇입니까? 계측기 제어 프로그램은 C#으로 개발되었기 때문에 클라이언트는 C#이 가장 좋습니다. 트래픽 절약(서버는 트래픽에 따라 과금됨)을 고려하면 파일을 압축해야 하며, 파일 압축 기능은 C#에서 구현해야 합니다. 서버는 업로드를 위한 안정적인 API를 구축하기 위해 Java를 선택합니다.
리더의 요구 사항에 따라 기기 수정, 일부 기능 추가, 측정 데이터를 서버에 업로드해야 합니다. 계측기의 측정주기는 약 20초이며, 현재 데이터의 양은 많지 않습니다. 각 측정값은 약 2M 미만이며 모두 부동 소수점 데이터와 정수 데이터입니다.
처음에는 TCP Long Connection을 사용하고 싶었으나 현장 환경을 고려하여.. 일반적인 제조 작업장에서는 전자기 환경이 복잡하고 네트워크 신호가 불안정하므로 TCP 긴 연결 구현은 고려되지 않습니다. 짧은 연결도 고려되지 않습니다. 향후 기기 수가 증가하면 자주 연결을 설정하는 데 드는 비용도 매우 높아 서버가 이를 감당하지 못할 수도 있습니다(Alibaba Cloud의 거지 버전). 그래서 나는 제출을 위해 Restful을 사용하기로 선택했고, http 통신은 멀티 스레드로 예약될 수 있습니다.
기기 제어 프로그램은 C#으로 개발되었기 때문에 클라이언트는 C#이 가장 좋습니다. 서버 측에서 springboot를 사용하고 싶습니다. 이는 매우 편리합니다.
새로운 업로드 기능이 이전 측정 비트에 영향을 미칠 수 없다는 점을 고려하여 이를 구현하려면 멀티스레딩이 필요합니다. 불행하게도 나는 게으르고 스레드 조정 문제를 고려하고 싶지 않기 때문에 마침내 메시지 대기열 구현을 선택했습니다.
트래픽 절약을 고려하여(서버는 트래픽에 따라 요금이 부과됨) 파일을 압축해야 하며, 파일 압축 기능은 C#에서 구현해야 합니다.
측정 파일에서 데이터를 읽고, 매개변수를 데이터베이스에 저장하고, 원본 측정 데이터를 파일 서버에 패키징합니다.
최종 기술 솔루션은 C#을 클라이언트로 사용하고 Java를 사용하여 업로드를 위한 서버측 Restful API를 구축하는 것입니다
전체 아키텍처는 다음과 같습니다.
사용된 기술은 다음과 같습니다.
C# Restful 클라이언트: RestSharp
java Restful 서버: springboot
C# 사이드 메시지 큐: NetMQ
C# 사이드 zip 작업 구성 요소: DotNetZ ip
java 측면 zip 작업 구성 요소: Apache Commons Compress
서버는 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; } }
클라이언트 아키텍처는 다음과 같습니다.
NetMQ ZeroMQ 포팅 버전의 C#입니다.
NetMQ(ZeroMQ to .Net), ZMQ는 역사상 가장 빠른 미들웨어로 알려져 있습니다.
소켓 함수 호출을 작성하지 않고도 복잡한 네트워크 통신을 완료할 수 있도록 소켓 통신을 캡슐화합니다.
소켓과의 차이점은 일반 소켓은 엔드투엔드(1:1 관계)이지만 ZMQ는 지점간 연결을 위한 BSD 소켓에 대해 더 많이 알고 있습니다. -포인트 연결에는 명시적인 연결 설정, 연결 파괴, 프로토콜 선택(TCP/UDP), 오류 처리 등이 필요합니다. ZMQ는 이러한 세부 사항을 보호하여 네트워크 프로그래밍을 더 간단하게 만듭니다.
여러 스레드, 코어 및 호스트 상자에 걸쳐 탄력적으로 확장되는 메시지 처리 대기열 라이브러리입니다. 일반 메시지 대기열 제품과 달리 메시지 대기열 서버가 없지만 네트워크 통신 라이브러리에 가깝습니다. 네트워크 통신의 관점에서 보면 세션 계층 위와 애플리케이션 계층 아래에 있으며 전송 계층에 속합니다.
zeromq는 메시지 통신을 일대일 쌍 모델(Exclusive-Pair), 요청-응답 모델(Request-Reply), 게시-구독 모델(Publish-Subscribe)의 네 가지 모델로 나눕니다. ) , 푸시풀 모델(Push-Pull). 이 네 가지 모델은 일반적인 네트워크 통신 모델을 요약합니다. 실제로는 이러한 모델 중 두 개 이상을 결합하여 애플리케이션 요구 사항에 따라 고유한 솔루션을 구성할 수 있습니다.
기존 TCP 소켓 모델을 지원하는 가장 간단한 1:1 메시지 통신 모델로, 주로 프로세스 내 스레드 간 통신에 사용됩니다. 이는 TCP 연결로 간주될 수 있지만 TCP 서버는 하나의 연결만 허용할 수 있습니다. lock free를 사용하여 구현되었으며 매우 빠릅니다. 데이터는 양방향으로 흐를 수 있으며 이는 이후의 요청-응답 모델과 다릅니다. (권장하지 않음, 예시 없음)
由请求端发起请求,然后等待回应端应答。一个请求必须对应一个回应,从请求端的角度来看是发-收配对,从回应端的角度是收-发对。跟一对一结对模型的区别在于请求端可以是1~N个。
请求端和回应端都可以是1:N的模型。通常把1认为是server,N认为是Client。ZeroMQ可以很好的支持路由功能(实现路由功能的组件叫作Device),把1:N扩展为N:M(只需要加入若干路由节点)。从这个模型看,更底层的端点地址是对上层隐藏的。每个请求都隐含有回应地址,而应用则不关心它。通常把该模型主要用于远程调用及任务分配等。
(NetMQ请求响应C#调用案例)
发布端单向分发数据,且不关心是否把全部信息发送给订阅端。如果发布端开始发布信息时,订阅端尚未连接上来,则这些信息会被直接丢弃。订阅端未连接导致信息丢失的问题,可以通过与请求回应模型组合来解决。订阅端只负责接收,而不能反馈,且在订阅端消费速度慢于发布端的情况下,会在订阅端堆积数据。该模型主要用于数据分发。天气预报、微博明星粉丝可以应用这种经典模型。 (NetMQ发布订阅模式C#调用案例)
Server端作为Push端,而Client端作为Pull端,如果有多个Client端同时连接到Server端,则Server端会在内部做一个负载均衡,采用平均分配的算法,将所有消息均衡发布到Client端上。与发布订阅模型相比,推拉模型在没有消费者的情况下,发布的消息不会被消耗掉;在消费者能力不够的情况下,能够提供多消费者并行消费解决方案。该模型主要用于多任务并行。
(NetMQ推拉模式C#调用案例)
TCP:ZeroMQ基于消息,消息模式,而非字节流。
XMPP:ZeroMQ更简单、快速、更底层。Jabber可建在ZeroMQ之上。
AMQP:完成相同的工作,ZeroMQ要快100倍,而且不需要代理(规范更简洁——少278页)
IPC:ZeroMQ可以跨多个主机盒,而非单台机器。
CORBA:ZeroMQ不会将复杂到恐怖的消息格式强加于你。
RPC:ZeroMQ完全是异步的,你可以随时增加/删除参与者。
RFC 1149:ZeroMQ比它快多了!
29west LBM:ZeroMQ是自由软件!
IBM低延迟:ZeroMQ是自由软件!
Tibco:仍然是自由软件!
一般都是发布者先启动,绑定监听端口。封装了一个发送函数,主要是发送原先软件生成测量文件的路径。
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); } }
订阅者启动时候连接端口。防止线程阻塞,订阅者是新开一个线程运行的。
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); }
压缩使用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; } }
使用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}"); } } ); } }
写代码之前一定要搞清楚需求,设计好架构
注意消息队列启动时候的线程问题
异步执行
相关文章:
相关视频:
위 내용은 측정 데이터를 서버에 업로드하는 기능을 구현하는 기기 및 장비 개조 기술의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!