您的位置:首页 > 理论基础 > 计算机网络

[c#源码]微风IM V3.1 支持TCP通信发送图片

2015-03-03 00:00 393 查看
更新后的源码

数据库 (数据库和以前一样 没有变动) 数据库用的是sql2005,不方便用sql2005的朋友可以下载sql脚本文件 下载地址

前面有好几位朋友说希望微风IM能够支持图片的发送,于是学习了图片发送的一些相关知识,在微风IMV3.1中实现了图片的发送。

如果客户端之间P2P通道已经打通,则直接在客户端之间发送,不经过服务器。

如果P2P通道没有打通,则通过服务器转发。

效果图:







下面简单的介绍一下相关知识

在TCP 通信中,Image类本身不支持序列化。

我们想要发送的话,需要做一些变通。简单的讲,就是在序列化之前把Image类转化为二进制数据,序列化完成后,解析的时候再把二进制数据解析成Image类。

我们使用的是开源的 protobuf.net序列化器。

对IMage图片类进行包装

using System; using System.Collections.Generic; using System.Text; using ProtoBuf; using System.Drawing; using System.IO; using ProtoBuf; namespace SimpleIM.Business { [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; } } }


修改一下用于传输聊天信息的契约类,使之包含相关的图片

using System; using System.Collections.Generic; using System.Text; using ProtoBuf; using System.IO; using System.Runtime.Serialization.Formatters.Binary; using System.ComponentModel; namespace SimpleIM.Business { /// <summary>
/// 此契约类存放聊天对话消息 /// </summary>
[ProtoContract] public class NewChatContract { //用户ID
[ProtoMember(1)] public string UserID { get; set; } //用户名
[ProtoMember(2)] public string UserName { get; set; } //目标用户ID
[ProtoMember(3)] public string DestUserID { get; set; } //目标用户名
[ProtoMember(4)] public string DestUserName { get; set; } //聊天的内容,主要是文本消息
[ProtoMember(5)] public string Content { get; set; } //发送的时间
[ProtoMember(6)] public DateTime SendTime { get; set; } [ProtoMember(7)] public IList<ImageWrapper> ImageList { get; set; } //下面这段代码主要是为了防止列表为空,如果列表为空,不加入下面这段代码,序列化会有问题
[DefaultValue(false), ProtoMember(8)] private bool IsEmptyList { get { return ImageList != null && ImageList.Count == 0; } set { if (value) { ImageList = new List<ImageWrapper>(); } } } public NewChatContract() { } public NewChatContract(string userID, string userName, string destUserID, string destUserName, string content, IList<ImageWrapper> imageList, DateTime sendTime) { this.UserID = userID; this.UserName = userName; this.DestUserID = destUserID; this.DestUserName = destUserName; this.Content = content; this.ImageList = imageList; this.SendTime = sendTime; } } }


修改ChatControl控件,添加2个按钮



并添加相关代码,具体大家可以看一下源码

需要说明的是,聊天控件使用的是RichTextBox的扩展控件,本来想是否能够提取出RichTextBox中的内容,即包含所有的文字信息和图片信息,然后以发送二进制数据的形式发送,

但是对这方面不太了解,查了好些文章,也没有完后,对这方面比较了解的朋友请指点一下。

后来使用了一个变通的方法,即把文本内容,和图片文件分开发送。

在ChatControl控件中增加了一个字典类变量

public Dictionary<string, Image> imageDict = new Dictionary<string, Image>();


当用户插入图片时,会把图片添加到此字典中。

当用户发送聊天信息时,会提取字典中的图片列表进行发送,并清空图片字典。

点击发送聊天信息时的相关代码:

/ /控件中的图片字典
public Dictionary<string, Image> imageDict = null; //图片包装类的列表
IList<ImageWrapper> imageWrapperList = new List<ImageWrapper>(); private void chatControl1_BeginToSend(string content) { this.chatControl1.ShowMessage(Common.UserName, DateTime.Now, content, true); imageDict = this.chatControl1.imageDict; //把控件中的图片字典,添加到图片包装类列表中
foreach (KeyValuePair<string, Image> kv in imageDict) { ImageWrapper newWrapper = new ImageWrapper(kv.Key, kv.Value); imageWrapperList.Add(newWrapper); } //清除控件中图片字典的内容
this.chatControl1.ClearImageDic(); //从客户端 Common中获取相应连接
Connection p2pConnection = Common.GetUserConn(this.friendID); if (p2pConnection != null) { NewChatContract chatContract = new NewChatContract(); chatContract.UserID = Common.UserID; chatContract.UserName = Common.UserName; chatContract.DestUserID = this.friendID; chatContract.DestUserName = this.friendID; chatContract.Content = content; chatContract.SendTime = DateTime.Now; chatContract.ImageList = imageWrapperList; p2pConnection.SendObject("ClientChatMessage", chatContract); this.chatControl1.Focus(); LogInfo.LogMessage("通过p2p通道发送消息,当前用户ID为"+Common.UserID+"当前Tcp连接端口号"+p2pConnection.ConnectionInfo.LocalEndPoint.Port.ToString (), "P2PINFO"); } else { NewChatContract chatContract = new NewChatContract(); chatContract.UserID = Common.UserID; chatContract.UserName = Common.UserName; chatContract.DestUserID = this.friendID; chatContract.DestUserName = this.friendID; chatContract.Content = content; chatContract.SendTime = DateTime.Now; chatContract.ImageList = imageWrapperList; Common.TcpConn.SendObject("ChatMessage", chatContract); this.chatControl1.Focus(); LogInfo.LogMessage("服务器转发消息", "P2PINFO"); } }


图片的传送是经常用的功能,在其他的程序中也经常用到,稍微改动一下,可以实现客户端拍照片,然后传送到服务器上保存等类似功能。

感谢您的光临

有朋友需要数据库的sql文件,制作了一下:



数据SQL文件下载地址 生成sql数据表的内容用的是CodeSmith的模板(4.0以上应该都能用) CodeSmith 模板 下载地址

"陌路夕颜念有你的单纯"朋友提到的“ 多次发图片,对方会收到多张图片的”问题已经修正,用来存储图片的 imageWrapperList列表每次发送消息后 清空一下即可 感谢关注

IList<ImageWrapper> imageWrapperList = new List<ImageWrapper>();


加入这一句

imageWrapperList.Clear();


更新后的源码

微风IM3.2已发布 请见 [源码分享]微风IM 3.2 实现新用户注册 含详细过程

有朋友问性能的问题,可参见下面这篇文章

NetworkComms通信框架 性能测试
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐