当前位置: 代码迷 >> C# >> [c#源码]轻风IM V3.1 支持TCP通信发送图片
  详细解决方案

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

热度:113   发布时间:2016-05-05 04:46:38.0
[c#源码]微风IM V3.1 支持TCP通信发送图片

 更新后的源码

 

 数据库 (数据库和以前一样 没有变动) 数据库用的是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通信框架 性能测试

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,您好,图片是可以传送的
  相关解决方案