WCF全双工数据传输

项目结构:


客户端:

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System.Runtime.Serialization;
using System.Collections;


using Cn100.Wcf.Duplex.Contract;
using Cn100.Wcf.Duplex.Service;
using Cn100.Wcf.Duplex.Common;
using System.ServiceModel.Description;


namespace Cn100.Wcf.Duplex.Client
{
   public delegate void DuplexCallBack(object reust,int count);

    public class ClientHandler : ICallback,IDisposable
    {
        /// <summary>
        /// 处理回调事件的类
        /// </summary>
        public static event DuplexCallBack callback;

        public Hashtable hashResult = new Hashtable();
        public StringBuilder builder = new StringBuilder();

        private static DuplexChannelFactory<ICallbackService> channelFactory = null;

        /// <summary>
        /// 接收回传数据
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="isComplete"></param>
        public void ReceiveData(object result, int count, int index, bool isComplete)
        {
            if (isComplete)
            {
                //ArrayList array = new ArrayList(hashResult.Keys);
                //array.Sort();
                //StringBuilder builder = new StringBuilder();
                //foreach (int key in array)
                //{
                //    builder.Append(hashResult[key].ToString());
                //}
                object obj = new object();
                if (builder.Length > 0)
                {
                     obj = SerializeHelper.DeserializeObject(builder.ToString());
                    builder = new StringBuilder();
                }
                else
                {
                    obj = result;
                }

                if (callback != null)
                {
                    callback(obj, count);
                    //callback = null;
                }

                
                HideProcess();
            }
            else
            {
                builder.Append(result.ToString());
                //hashResult.Add(index, result);
            }
        }

        /// <summary>
        /// 显示进度条
        /// </summary>
        public void ShowProcess()
        { 
        
        }

        /// <summary>
        /// 隐藏进度条
        /// </summary>
        public void HideProcess()
        { 
        
        }

        public static object @Lock = new object();

        /// <summary>
        /// 发送数据到服务器端
        /// </summary>
        /// <param name="Assemply">服务端程序集名称,如:Cn100.Wcf.Duplex.Service.CallbackService,Cn100.Wcf.Duplex.Service</param>
        /// <param name="method">调用方法名称,如:SendData</param>
        /// <param name="parameters">调用方法参数</param>
        public void SendData(string assembly, string method, params object[] parameters)
        {
            object[] paras=new object[parameters.Length];
            for (int i = 0; i < parameters.Length; i++)
            {
                paras[i] = SerializeHelper.SerializeObject(parameters[i]);
            }
            lock (@Lock)
            {
                try
                {
                    if (channelFactory == null || channelFactory.State != CommunicationState.Opened)
                    {
                        channelFactory = CreateChannel<ICallbackService>("CallBackService", new ClientHandler());
                    }
                    ICallbackService proxy = channelFactory.CreateChannel();
                    proxy.SendData(assembly, method, paras);
                    Console.Read();
                }
                catch (Exception ex)
                {
                    channelFactory = null;
                    //throw ex;
                }
            }
        
       
            //using (DuplexChannelFactory<ICallbackService> channelFactory = new DuplexChannelFactory<ICallbackService>(instanceContext, "CallBackService"))
            //{
            //    ICallbackService proxy = channelFactory.CreateChannel();
            //    using (proxy as IDisposable)
            //    {
            //        ShowProcess();
            //        proxy.SendData(assembly, method, paras);
            //        Console.Read();
            //    }
                
            //}
        }

        /// <summary>
        /// 异步调用发送数据
        /// </summary>
        /// <param name="assembly"></param>
        /// <param name="method"></param>
        /// <param name="parameters"></param>
        public void AsySendData(string assembly, string method, params object[] parameters)
        {
            Action<string, string,object[]> action = (ass, m, p) => SendData(ass, m, p);
            action.BeginInvoke(assembly, method, parameters, ar => action.EndInvoke(ar), null);
        }


        public DuplexChannelFactory<T> CreateChannel<T>(string name,object handler)
        {
            InstanceContext instanceContext = new InstanceContext(handler);
            DuplexChannelFactory<T> factory = new DuplexChannelFactory<T>(instanceContext, name);

            //EndpointAddress address = new EndpointAddress("net.tcp://127.0.0.1:9998/CallbackService");
            //NetTcpBinding binding = new NetTcpBinding();
           
            //ContractDescription description=new ContractDescription(name);
            //ServiceEndpoint potion=new ServiceEndpoint (description,binding,address);
            //DuplexChannelFactory<T> factory = new DuplexChannelFactory<T>(instanceContext, potion);
            
            return factory;
        }

        public void Dispose()
        {
            if (channelFactory != null)
            {
                channelFactory.Close();
                channelFactory = null;
            }
        }

    }
}

 

 

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Cn100.Wcf.Duplex.Client
{
    interface IClientHandler
    {
        /// <summary>
        /// 显示进度条
        /// </summary>
        void ShowProcess();

        /// <summary>
        /// 隐藏进度条
        /// </summary>
        void HideProcess();

        /// <summary>
        /// 发送数据到服务器端
        /// </summary>
        /// <param name="Assemply">服务端程序集名称,如:Cn100.Wcf.Duplex.Service.CallbackService,Cn100.Wcf.Duplex.Service</param>
        /// <param name="method">调用方法名称,如:SendData</param>
        /// <param name="parameters">调用方法参数</param>
        void SendData(string assembly, string method, params object[] parameters);


    }
}


协议:

 

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;

namespace Cn100.Wcf.Duplex.Contract
{

    [ServiceContract(Namespace = "http://www.cn100.com", CallbackContract = typeof(ICallback),SessionMode=SessionMode.Required)]
    public interface ICallbackService
    {

        /// <summary>
        /// 发送数据到服务器端
        /// </summary>
        /// <param name="Assemply">服务端程序集名称,如:Cn100.Wcf.Duplex.Service.CallbackService,Cn100.Wcf.Duplex.Service</param>
        /// <param name="method">调用方法名称,如:SendData</param>
        /// <param name="parameters">调用方法参数</param>
        [OperationContract(IsOneWay = true)]
        void SendData(string Assemply, string method, params object[] parameters);
    }
}

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;

namespace Cn100.Wcf.Duplex.Contract
{
   [ServiceContract]
   public interface ICallback
    {
       /// <summary>
       /// 客户端接收数据
       /// </summary>
       /// <param name="result"></param>
       /// <param name="count"></param>
       /// <param name="isComplete"></param>
       [OperationContract(IsOneWay = true)]
       void ReceiveData(object result, int count, int index, bool isComplete);

    }
}

 

 

服务端

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Reflection;
using System.Diagnostics;
using System.Runtime.Serialization;
using System.IO;
using System.Text.RegularExpressions;

using Cn100.Wcf.Duplex.Contract;
using Cn100.Wcf.Duplex.Module;
using System.Runtime.Serialization.Formatters.Binary;
using Cn100.Wcf.Duplex.Common;



namespace Cn100.Wcf.Duplex.Service
{
    [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)]
    public class CallbackService:ICallbackService
    {

        public void SendData(string assembly, string method, params object[] parameters)
        {
            try
            {
                string strPath = System.Environment.CurrentDirectory;

                string[] assemplys = assembly.Split(',');

                string strClass = assemplys[0];
                string strDLL = strPath + "/" + assemplys[1] + ".dll";


                Assembly ass = Assembly.LoadFile(strDLL);
                Type type = ass.GetType(strClass);
                MethodInfo mi = type.GetMethod(method);
                object obj = ass.CreateInstance(strClass);

                object[] paras = new object[parameters.Length];
                for (int i = 0; i < parameters.Length; i++)
                {
                    paras[i] = SerializeHelper.DeserializeObject(parameters[i]);
                }

                object result = mi.Invoke(obj, paras);

                ICallback callback = OperationContext.Current.GetCallbackChannel<ICallback>();
                if (result != null)
                {
                    int intOut = 0;
                    if (paras.Length > 0)
                    {
                        string strOut = paras[paras.Length - 1].ToString();
                        int.TryParse(strOut, out intOut);
                    }

                    //序列化
                    string strResult = SerializeHelper.SerializeObject(result);

                    
                    string[] source = StingSplit.SplitData(strResult, Size);
                    for (int i = 0; i < source.Length; i++)
                    {
                        callback.ReceiveData(source[i], i, i, false);
                    }
                    callback.ReceiveData("", intOut, source.Length, true);
                }
                else
                {
                    callback.ReceiveData(null, 0, 0, true);
                }
                
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                if (ex.InnerException != null)
                {
                    Console.WriteLine(ex.InnerException.Message);
                }
                throw ex;
            }
        }

       

        const string TransferSizeConfigName = "transferSize";
        public static int Size = GetTransferSize();

        public static int GetTransferSize()
        {
            
            if (System.Configuration.ConfigurationManager.AppSettings[TransferSizeConfigName] != null)
            {
                string strSize = System.Configuration.ConfigurationManager.AppSettings[TransferSizeConfigName].ToString();
                int intSize = 0;
                if (int.TryParse(strSize, out intSize))
                {
                    return intSize;
                }
            }
            return 20;
        }
    }
}


服务载体配置:

 

 

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
	<system.serviceModel>
		<bindings>
			<netTcpBinding>
				<binding  name="DuplexBindingConfiguration"  openTimeout="00:30:00" receiveTimeout="01:30:00"  sendTimeout="01:30:00"  maxBufferSize="2147483647" maxReceivedMessageSize="2147483647">
					<security mode="None" />
					<readerQuotas  maxStringContentLength="6553600" maxArrayLength="6553600" />
				</binding>
			</netTcpBinding>
		</bindings>
		<behaviors>
			<serviceBehaviors>
				<behavior name="mybehavior">
					<serviceDebug includeExceptionDetailInFaults="true"/>
				</behavior>
			</serviceBehaviors>
		</behaviors>
		<services>
			<service name="Cn100.Wcf.Duplex.Service.CallbackService">
				<endpoint address="net.tcp://127.0.0.1:9998/CallbackService" bindingConfiguration="DuplexBindingConfiguration"
						  binding="netTcpBinding" contract="Cn100.Wcf.Duplex.Contract.ICallbackService" />
			</service>
		</services>
	</system.serviceModel>
	<!--传输大小配置,不通超过最大配置:8192-->
	<appSettings>
		<add key="transferSize" value="500"/>
	</appSettings>
</configuration>


客户端配置:

 

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
	<system.serviceModel>
		<bindings>
			<netTcpBinding>
				<binding  name="TicketBindingConfiguration"  openTimeout="00:30:00" receiveTimeout="01:30:00"  sendTimeout="01:30:00"  maxBufferSize="2147483647" maxReceivedMessageSize="2147483647">
					<security mode="None" />
					<readerQuotas  maxStringContentLength="6553600" maxArrayLength="6553600" />
				</binding>
			</netTcpBinding>
		</bindings>
		<client>
			<endpoint name="CallBackService" bindingConfiguration="TicketBindingConfiguration"
					   address="net.tcp://127.0.0.1:9998/CallbackService"
					   binding="netTcpBinding"
					   contract="Cn100.Wcf.Duplex.Contract.ICallbackService"/>
		</client>
		<!--address="net.tcp://192.168.0.8:5687/CallbackService"-->
		<!--address="net.tcp://127.0.0.1:9998/CallbackService"-->
	</system.serviceModel>
</configuration>

 

工具类:

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

using Newtonsoft.Json;
using System.Diagnostics;

namespace Cn100.Wcf.Duplex.Common
{
    public class SerializeHelper
    {

        /// <summary>
        /// 反序列化对象
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static object DeserializeObject(object source)
        {
            //Stopwatch watch = new Stopwatch();
            //watch.Start();
            IFormatter formatter = new BinaryFormatter();
            byte[] buffer = Convert.FromBase64String(source.ToString());
            MemoryStream stream = new MemoryStream(buffer);

            object obj = formatter.Deserialize(stream);
            stream.Flush();
            stream.Close();

            //long time = watch.ElapsedMilliseconds;
            //watch.Stop();
            //Console.WriteLine(time);

            return obj;

        }

        /// <summary>
        /// 序列化对象
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static string SerializeObject(object source)
        {
            //Stopwatch watch = new Stopwatch();
            //watch.Start();

            IFormatter formatter = new BinaryFormatter();
            MemoryStream stream = new MemoryStream();
            formatter.Serialize(stream, source);
            stream.Position = 0;
            byte[] buffer = new byte[stream.Length];
            stream.Read(buffer, 0, buffer.Length);
            stream.Flush();
            stream.Close();

            string strResult = Convert.ToBase64String(buffer);

            //long time = watch.ElapsedMilliseconds;
            //watch.Stop();
            //Console.WriteLine(time);
            return strResult;

        }

        public static string SerializeObjectToJson(object source)
        {
            return JsonConvert.SerializeObject(source);
        }

        public static object DeserializeJsonToObject(string source)
        {
            return JsonConvert.DeserializeObject(source);
        }

        public static List<T> DeserializeJsonToObject<T>(string source)
        {
            return JsonConvert.DeserializeObject<List<T>>(source);
        }
    }
}


 

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace Cn100.Wcf.Duplex.Common
{
    public class StingSplit
    {
        public static string[] SplitData(string source, int length)
        {
            List<string> lists = new List<string>();

            if (source.Length > length)
            {
                Regex reg = new Regex(".{" + length.ToString() + "}", RegexOptions.Multiline | RegexOptions.IgnoreCase);
                if (reg.IsMatch(source))
                {
                    int i = 0;
                    foreach (var m in reg.Matches(source))
                    {
                        i++;
                        lists.Add(m.ToString());
                    }
                    if (i * length < source.Length)
                    {
                        lists.Add(source.Substring(i * length));
                    }
                }
            }
            else
            {
                lists.Add(source);
            }
            return lists.ToArray();
        }
    }
}


 

 

posted @ 2013-07-05 21:33  坚固66  阅读(377)  评论(0编辑  收藏  举报