標籤:
源碼 (因為空白間大小限制,不包含通訊架構源碼,通訊架構源碼請另行下載)
以前幫朋友做了一個圖片採集系統,用戶端採集相片後,通過TCP通訊傳送到伺服器,本文把用戶端傳送圖片到伺服器的這部分提取出來。
由於每張圖片的大小都不大,所以我們在傳輸圖片時,沒有採用傳送檔案的方式,而是採用了直接序列化圖片的方式來進行。
當前支援的圖片類型: jpg,png,gif 您可以自己添加擴充支援的圖片類型
通訊架構採用英國的開源的networkcomms2.3.1 通訊架構 序列化器採用開源的protobuf.net
我們先開看一下實現的效果
伺服器端:
用戶端:
在伺服器端,我們把收到的圖片儲存在D盤根目錄下(您可以另外指定路徑),開啟D盤看到收到的圖片如下:
下面看一下具體的過程
第一步,首先進行伺服器端的設定
(1)監聽連接埠:
IPEndPoint thePoint = new IPEndPoint(IPAddress.Parse(txtIP.Text), int.Parse(txtPort.Text)); TCPConnection.StartListening(thePoint, false); button1.Text = "監聽中"; button1.Enabled = false;
(2) 針對圖片上傳寫對應的處理方法:
NetworkComms.AppendGlobalIncomingPacketHandler<ImageWrapper>("UploadImage", IncomingUploadImage);
//處理用戶端發來的圖片 private void IncomingUploadImage(PacketHeader header, Connection connection, ImageWrapper wrapper) { try { //具體的解析工作由通訊架構完成 //從圖片封裝器中擷取到圖片檔案和圖片名稱 Image image = wrapper.Image; string fileName = wrapper.ImageName; //擷取副檔名 int index = fileName.LastIndexOf(‘.‘); string extion = fileName.Substring( index + 1, fileName.Length - index - 1); extion = extion.ToLower(); //設定檔案格式 ImageFormat imageFormat = ImageFormat.Bmp; switch (extion) { case "jpg": case "jpeg": imageFormat = ImageFormat.Jpeg; break; case "png": imageFormat = ImageFormat.Png; break; case "gif": imageFormat = ImageFormat.Gif; break; }
//此處,我們手工指定了一個儲存路徑,您可以自訂 image.Save(@"D:\" + fileName, imageFormat); ResMsgContract contract = new ResMsgContract(); contract.Message = "上傳成功"; //發送回複資訊給用戶端 connection.SendObject("ResUploadImage", contract); } catch (Exception ex) { } }
第二步:用戶端的設定
(1)串連伺服器:
//給串連資訊對象賦值 connInfo = new ConnectionInfo(txtIP.Text, int.Parse(txtPort.Text)); //如果不成功,會彈出異常資訊 newTcpConnection = TCPConnection.GetConnection(connInfo); TCPConnection.StartListening(connInfo.LocalEndPoint); button1.Enabled = false; button1.Text = "串連成功";
(2)從本地選擇圖片並上傳
openFileDialog1.Filter = "圖片檔案|*.jpg|所有檔案|*.*"; if (openFileDialog1.ShowDialog() == DialogResult.OK) { string shortFileName = System.IO.Path.GetFileName(openFileDialog1.FileName); //圖片封裝類 ImageWrapper wrapper = new ImageWrapper(shortFileName, Image.FromFile(openFileDialog1.FileName)); //發送圖片封裝類到伺服器,並擷取返回資訊 ResMsgContract resMessage = newTcpConnection.SendReceiveObject<ResMsgContract>("UploadImage", "ResUploadImage", 8000, wrapper); if (resMessage.Message == "上傳成功") { MessageBox.Show("圖片已經上傳到伺服器"); } else { MessageBox.Show("圖片沒有發送成功"); } }
(三)關於 ImageWrapper類
在用戶端與伺服器端通訊的過程中,我們注意到上面的程式中使用了一個ImageWrapper類,用來傳遞圖片(Image)對象。
ImageWrapper類,存放在MessageContract類庫中,此類用來序列化圖片
我們知道Image類並不直接支援序列化,所以我們採用的方式是序列化之前把Image轉化為二級制資料,還原序列化之前再把二級制資料轉化為Image類。
我們只負責定義ImageWrapper類,其他工作通訊架構幫我們做好了。
using System;using System.Collections.Generic;using System.Text;using ProtoBuf;using System.Drawing;using System.IO;using ProtoBuf;namespace MessageContract{ [ProtoContract] public class ImageWrapper { /// <summary> /// 把ImageObject Storage Service為私人的位元組數組 /// </summary> [ProtoMember(1)] private byte[] _imageData; /// <summary> /// 圖片名稱 /// </summary> [ProtoMember(2)] public string ImageName { get; set; } /// <summary> /// 圖片對象 /// </summary> public Image Image { get; set; } /// <summary> /// 私人的無參數建構函式 還原序列化時需要使用 /// </summary> private ImageWrapper() { } /// <summary> /// 建立一個新的 ImageWrapper類 /// </summary> /// <param name="imageName"></param> /// <param name="image"></param> public ImageWrapper(string imageName, Image image) { this.ImageName = imageName; this.Image = image; } /// <summary> ///序列化之前,把圖片轉化為位元據 /// </summary> [ProtoBeforeSerialization] private void Serialize() { if (Image != null) { //We need to decide how to convert our image to its raw binary form here using (MemoryStream inputStream = new MemoryStream()) { //For basic image types the features are part of the .net framework Image.Save(inputStream, Image.RawFormat); //If we wanted to include additional data processing here //such as compression, encryption etc we can still use the features provided by NetworkComms.Net //e.g. see DPSManager.GetDataProcessor<LZMACompressor>() //Store the binary image data as bytes[] _imageData = inputStream.ToArray(); } } } /// <summary> /// 還原序列化時,把位元據轉化為圖片對象 /// </summary> [ProtoAfterDeserialization] private void Deserialize() { MemoryStream ms = new MemoryStream(_imageData); //If we added custom data processes we have the perform the reverse operations here before //trying to recreate the image object //e.g. DPSManager.GetDataProcessor<LZMACompressor>() Image = Image.FromStream(ms); _imageData = null; } }} ImageWrapper
工作到此完成,很少的代碼量,就幫我們實現了傳遞用戶端圖片儲存在伺服器的功能。
注意:此種方式並不適合傳遞比較大的圖片,如果圖片比較大,比如10M以上,最好以傳送檔案的形式,分段發送.
[c#源碼分享]用戶端程式傳送圖片到伺服器