数据库 (数据库和以前一样 没有变动) 数据库用的是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 实现新用户注册 含详细过程
有朋友问性能的问题,可参见下面这篇文章
- 6楼GreySky
- 有WEB 版么?或者计划出WEB 前端版么?
- Re: networkcomms通信框架
- @GreySky,您好 没有Web版 对Web的开发也不了解。倒是对安卓版比较有兴趣,数据通信没有问题,但是xamarin.android相关的UI还不熟悉
- 5楼新手涂
- 感觉很好,改天试用看看
- 4楼陌路夕颜念有你的单纯
- ,多次发图片,对方会收到多张图片的,,发完图片再发文字,对方依然收到的是多张图片
- Re: networkcomms通信框架
- @陌路夕颜念有你的单纯,感谢关注 您所说的问题确实存在 源码中已经修正
- 3楼networkcomms通信框架
- 微风IM 采用networkcomms2.3.1c#开源通信框架
- 2楼fatcat916
- 真的不错。,我在win7下用的SQL Server 2000绿色版,附加数据库会提示如下错误:
- Re: networkcomms通信框架
- @fatcat916,您好,数据库用的是sql2005,用sql2000附件可能会出错
- 1楼fatcat916
- 图片呢?
- Re: networkcomms通信框架
- @fatcat916,您好,图片是可以传送的