客户端程序传送图片到服务器
转载:http://www.cnblogs.com/networkcomms/p/4314898.html
源码 (因为空间大小限制,不包含通信框架源码,通信框架源码请另行下载)
以前帮朋友做了一个图片采集系统,客户端采集相片后,通过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>
/// 把Image对象存储为私有的字节数组
/// </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;
}
}
}
工作到此完成,很少的代码量,就帮我们实现了传递客户端图片保存在服务器的功能。
注意:此种方式并不适合传递比较大的图片,如果图片比较大,比如10M以上,最好以传送文件的形式,分段发送.
作者:阿笨
【官方QQ一群:跟着阿笨一起玩NET(已满)】:422315558
【官方QQ二群:跟着阿笨一起玩C#(已满)】:574187616
【官方QQ三群:跟着阿笨一起玩ASP.NET(已满)】:967920586
【官方QQ四群:Asp.Net Core跨平台技术开发(可加入)】:829227829
【官方QQ五群:.NET Core跨平台开发技术(可加入)】:647639415
【网易云课堂】:https://study.163.com/provider/2544628/index.htm?share=2&shareId=2544628
【腾讯课堂】:https://abennet.ke.qq.com
【51CTO学院】:https://edu.51cto.com/sd/66c64
【微信公众号】:微信搜索:跟着阿笨一起玩NET