標籤:讀取資料 添加 發送 star 機器 內容 這一 string ddr
隨著倒計時的響聲,自覺無心工作,只想為祖國慶生。
最近有遇到過這樣一個問題,將網路攝影機識別的行人,車輛即時顯示在用戶端中。有提供介面,會以Json的資料的形式將即時將識別的對象進行Post提交。所以我們這邊先寫一個web服務來持續接收資料,再將資料進行解析存入資料庫。到這裡為止,資料沒有問題,都全部存入資料庫中,這樣還剩下一個即時重新整理識別圖片的問題。之前的處理方法是每隔5秒左右去讀取資料庫最新訊息,用Timer計時器來解決,這樣的話確實能解決問題,但是感覺不是最好的方法,因為網路攝影機識別的對象有時效性,比如半夜幾乎沒人通過,這個時候後台還在去撈取最新資料進行判斷就比較消耗資源。所以我先想到的是用 TCP方法來處理, web在解析圖片的時候, 進行發送,winform用戶端進行接收。貌似可以解決問題,先上代碼
private void button1_Click(object sender, EventArgs e) { //建立TCP用戶端對象 TcpClient tcpClient = new TcpClient(); //添加目標(伺服器)主機的IP、連接埠號碼 tcpClient.Connect(IPAddress.Parse("172.16.0.217"), 8056); //網路流 資料的形式 NetworkStream networkStream = tcpClient.GetStream(); if (networkStream.CanWrite) { //待發送資料轉Byte[] Byte[] bytSend = Encoding.UTF8.GetBytes(textBox1.Text); networkStream.Write(bytSend, 0, bytSend.Length); } else { MessageBox.Show("無法寫入資料流"); networkStream.Close(); tcpClient.Close(); return; } //流建立完需要及時關閉 networkStream.Close(); tcpClient.Close(); }
這裡是TCP的用戶端,指定了接收端的IP和連接埠號碼,以及發送的資料流,同樣在服務端選擇接受這些流資料。服務端要持續接收資料,就必須開啟一個線程進行監聽
private void Form1_Load(object sender, EventArgs e) { //初始化載入資料 Thread thread = new Thread(new ThreadStart(Listen)); thread.Start(); } //線程內向文字框txtRecvMssg中添加字串及委託 private delegate void serverRecDeg(string s); private void ReceiveMsg(string mes) { textBox1.Text = "Time:" + DateTime.Now.ToLongTimeString() + "Data:" + mes; } //監聽資料 private void Listen() { //socket 對象 Socket sock = new Socket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp); sock.Bind(new IPEndPoint(IPAddress.Any, 8056)); //不斷監聽連接埠 while (true) { sock.Listen(0); Socket socket = sock.Accept(); NetworkStream ntwStream = new NetworkStream(socket); StreamReader strmReader = new StreamReader(ntwStream); //winform UI控制項賦值,如果有線程,則需要用Invoke 來賦值,則否報錯 Invoke(new serverRecDeg(ReceiveMsg),new object[] { strmReader.ReadToEnd() }); socket.Close(); } }
以上是TCP用戶端發送資料,服務端持續接收。剛開始自認沒問題,但是後來一想確實不可行。我web服務端是發送資料的,用戶端是用來接收資料。TCP是用戶端指定服務端唯一的IP 和連接埠號碼進行資料的傳輸,這裡明顯就衝突了,如果在Web服務端用TCP發送資料,
就只能有一個用戶端進行接收,需求是winform最後要部署到不同機器上,這種思路肯定不行。思來想去,最後在同事的指點下,想到了廣播這一思路。在web服務端每次解析到圖片的時候,發一個廣播,然後隱藏在區域網路內的各個用戶端就可以進行收聽,解析後將圖片
//定義對象 private static Socket sock; private static IPEndPoint ipendPoint; private static byte[] data; //發送廣播 public static void UdpSend(byte[] bytes1) { //sock 對象,指定UDP協議 sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); ipendPoint = new IPEndPoint(IPAddress.Broadcast, 9050); //賦值 data = bytes1; sock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1); //發送 sock.SendTo(data, ipendPoint); }
這裡使用的是UDP廣播,代碼量很少,發送端已經完成,剩下的就是用戶端持續接收廣播
public void Receive() { try { //Scok 對象,設定UDP協議 Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); //逾時時間 sock.ReceiveTimeout = 4000; //廣播的連接埠號碼指定 IPEndPoint iep = new IPEndPoint(IPAddress.Any, 9050); sock.Bind(iep); EndPoint ep = (EndPoint)iep; //資料接收(指定非同步接收的方法) sock.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveMessage), sock); } catch (Exception ex) { MessageBox.Show(ex.Message); } } //指定單次接收圖片流緩衝區的大小 static byte[] buffer = new byte[102400]; //非同步接收 public void ReceiveMessage(IAsyncResult ar) { try { var socket = ar.AsyncState as Socket; var length = socket.EndReceive(ar); //讀取出來訊息內容 //var message = Encoding.UTF8.GetString(buffer, 0, length); //前三個長度為物件類型 車輛/行人 ,後面識別圖片 //解析圖片類型 string objType = System.Text.Encoding.Default.GetString(buffer.Skip(0).Take(3).ToArray()); //解析圖片 Image img = convertImg(buffer.Skip(3).ToArray()); //顯示訊息 this.Invoke(new Action(() => { SetPicBoxImg(objType, img); })); //接收下一個訊息(遞迴) socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveMessage), socket); } catch (Exception ex) { MessageBox.Show(ex.Message); } }
這些做完,剩下的就是將接收廣播的方法寫入到後台線程中,在表單啟動並執行時候啟動即可
Thread td = new Thread(new ThreadStart(Receive)); td.IsBackground = true; td.Start();
好了,事情到這裡基本就結束了,可以看出來,代碼量很少,卻能解決即時重新整理的需求。以後遇到事情一定要思路明確,不然一開始鑽進TCP的死胡同裡,怎麼都出不來,白白浪費時間不說,把人也搞得很疲憊。這裡多謝同事的指點,以後多像技術高手學習,畢竟閱曆有時候真的就是硬實力。
UDP廣播 與 TCP用戶端 --服務端