您好,登錄后才能下訂單哦!
這篇文章主要介紹C#中儀器設備改造技術如何實現測量數據上傳到服務器的功能,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!
怎樣用C#進行儀器的設備改造?因為儀器控制程序是C#開發的,所以客戶端最好是c#,考慮到節省流量(服務器是按流量收費的),文件要壓縮,C#下要實現文件壓縮功能。而服務端選擇java構建restful API進行上傳的的方案。
按照領導的要求,要改造一臺儀器,添加點功能,將測量數據上傳到服務器。儀器測量節拍大概是20s,數據量目前不大,每次測量大概不到2M左右,且都是浮點數據和整形數據。
起初想用TCP長連接實現的,但考慮到現場環境。典型的制造業車間,電磁環境復雜,網絡信號不穩,所以不考慮TCP長連接實現。短連接也不在考慮范圍內,以后儀器數量多了之后頻繁的建立連接開銷也很大,服務器有可能受不了(阿里云的乞丐版)。所以選擇用restful提交,http的通信可以多線程調度。
儀器控制程序是C#開發的,所以客戶端最好是c#。服務端我想用springboot,很方便。
考慮到新增的上傳功能不能影響之前的測量節拍,所以要多線程實現。可惜我又很懶,不想考慮線程協調問題,最后選擇消息隊列實現。
考慮到節省流量(服務器是按流量收費的),文件要壓縮,C#下要實現文件壓縮功能。
從測量文件中讀取數據,將參數存入數據庫,測量原始數據打包放在文件服務器上。
最后的技術方案就是C#做客戶端,java構建服務端restful API進行上傳
整體架構如下圖:
使用的技術如下:
C#的Restful客戶端:RestSharp
java的Restful服務端:springboot
C#端消息隊列:NetMQ
C#端zip操作組件:DotNetZip
java端zip操作組件:Apache Commons Compress
服務端采用springboot的restful,POST方式,非常簡單。
傳輸文件采用MultipartFile方式,因為客戶端的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; } }
客戶端架構如下圖:
NetMQ 是 ZeroMQ的C#移植版本。
NetMQ (ZeroMQ to .Net),ZMQ號稱史上最快中間件。
它對socket通信進行了封裝,使得我們不需要寫socket函數調用就能完成復雜的網絡通信。
它跟Socket的區別是:普通的socket是端到端的(1:1的關系),而ZMQ卻是可以N:M的關系,人們對BSD套接字的了解較多的是點對點的連接,點對點連接需要顯式地建立連接、銷毀連接、選擇協議(TCP/UDP)和處理錯誤等,而ZMQ屏蔽了這些細節,讓你的網絡編程更為簡單。
它是一個消息處理隊列庫,可在多個線程、內核和主機盒之間彈性伸縮。和一般意義上的消息隊列產品不同的是,它沒有消息隊列服務器,而更像是一個網絡通信庫。從網絡通信的角度看,它處于會話層之上,應用層之下,屬于傳輸層。
zeromq將消息通信分為4種模型,分別是一對一結對模型(Exclusive-Pair)、請求回應模型(Request-Reply)、發布訂閱模型(Publish-Subscribe)、推拉模型(Push-Pull)。這4種模型總結出了通用的網絡通信模型,在實際中可以根據應用需要,組合其中的2種或多種模型來形成自己的解決方案。
最簡單的1:1消息通信模型,用來支持傳統的 TCP socket模型,主要用于進程內部線程間通信。可以認為是一個TCP Connection,但是TCP Server只能接受一個連接。采用了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}"); } } ); } }
以上是C#中儀器設備改造技術如何實現測量數據上傳到服務器的功能的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。