none
wcf中双工问题 RRS feed

  • 问题

  • 你好,我要实现双向多次交互过程。当我再客户端输入数据后传给服务器端,服务器端执行后返回给客户端,如果客户端选择继续,服务器端继续处理,就这样循环,当我退出的时候,要销毁代理对象(我为了保证在程序询问执行的过程中使用的是同一线程,我用单例模式写了这个代理对象),当我销毁后,第二次就没法启动了。按道理说第二次,系统会再次运行单例中的代理生成方法,但是系统没有。请问这是如何造成的?
    附代码:

    服务器端:
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    namespace WCF
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    {
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
        // 注意: 如果更改此处的接口名称 "IHostService",也必须更新 App.config 中对 "IHostService" 的引用。
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
        [ServiceContract(CallbackContract=typeof(IHostServiceReturn),SessionMode=SessionMode.Required)]
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
        public interface IHostService
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
        {
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
            [OperationContract]
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
            string ShowMessage(string message);
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
            [OperationContract(IsOneWay=true)]
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
            void dobuleRoad(string message);
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
        }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
        public interface IHostServiceReturn
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
        {
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
            [OperationContract(IsOneWay=true)]
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
            void ReturnMessage(string message);
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
        }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    namespace WCF
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    {
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
        // 注意: 如果更改此处的类名 "HostService",也必须更新 App.config 中对 "HostService" 的引用。
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
        [ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Multiple)]
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
        public class HostService : IHostService
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
        {
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
            public string  ShowMessage(string message)
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
            {
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
                return message;
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
            }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
            public void dobuleRoad(string message)
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
            {
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
                Console.WriteLine(string.Format("服务器已经接收到客户端传过来的数据:{0}", message));
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
                IHostServiceReturn returnMessage = OperationContext.Current.GetCallbackChannel<IHostServiceReturn>();
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
                returnMessage.ReturnMessage("服务器端传给客户端处理");
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
            }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
        }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    客户端被调用方法:
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
     public class Ansuwer:ServiceReference.IHostServiceCallback
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
        {
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
            public void ReturnMessage(string message)
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
            {
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
                DialogResult result = MessageBox.Show("是否继续吗?", "提问", MessageBoxButtons.YesNo);
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
                if (result == DialogResult.Yes)
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
                {
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
                    //Ansuwer an = new Ansuwer();
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
                    //InstanceContext context = new InstanceContext(an);
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
                    //ServiceReference.HostServiceClient cline = new Show.ServiceReference.HostServiceClient(context);
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
                    ServiceReference.HostServiceClient cline = SingleHostServiceClient.getInsertance;
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
                    cline.dobuleRoad("客户端要继续,循环传值继续:");
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
                }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
                else
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
                {
    cline.Close(); MessageBox.Show("一切已经结束了"); } } } 单例: public sealed class SingleHostServiceClient { static readonly Show.ServiceReference.HostServiceClient cline = new Show.ServiceReference.HostServiceClient(new InstanceContext(new Ansuwer())); SingleHostServiceClient() { } static SingleHostServiceClient(){} public static Show.ServiceReference.HostServiceClient getInsertance { get { return cline; } } }


    您好,我按照您的意思,做了一个回调,然后在客户端用了一个委托,滚动条的运行情况是完全正确的,但是到第11次的时候,程序就好像死了一样。你能帮我看看这个是怎么回事吗?代码如下:
     
    namespace Host
    {
        // 注意: 如果更改此处的接口名称 "IServiceExample",也必须更新 App.config 中对 "IServiceExample" 的引用。
        [ServiceContract(SessionMode = SessionMode.Required,CallbackContract = typeof(IServiceReturn))]
        public interface IServiceExample
        {
            [OperationContract(IsOneWay=true,IsInitiating=true,IsTerminating=false)]
            void DoWork();
        }
        public interface IServiceReturn
        {
            [OperationContract(IsOneWay = true, IsInitiating = false, IsTerminating =false)]
            void CallBack(int value);
        }
    }
    namespace Host
    {
        // 注意: 如果更改此处的类名 "ServiceExample",也必须更新 App.config 中对 "ServiceExample" 的引用。
        [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.PerSession)]
        public class ServiceExample : IServiceExample
        {
            IServiceReturn returnMessage = null;
            public void DoWork()
            {
                  returnMessage = OperationContext.Current.GetCallbackChannel<IServiceReturn>();
                  Thread t = new Thread(new ThreadStart(this.Go));
                  t.IsBackground = true;
                  t.Start();
              
            }
            public void Go()
            {
                for (int i = 0; i < 100; i++)
                {
                    returnMessage.CallBack(i);
                    Thread.Sleep(2);
                }
            }
                
             
        }
    }
    namespace Client
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
            private void Form1_Load(object sender, EventArgs e)
            {
            }
            private void button1_Click(object sender, EventArgs e)
            {
                Back bck = new Back();
                bck.OnStepEvent += new OnStepEventHandler(o_OnStepEvent);
                InstanceContext ic = new InstanceContext(bck);
                ServiceReference.ServiceExampleClient cline = new Client.ServiceReference.ServiceExampleClient(ic);
                cline.DoWork();
            }
            public  void  o_OnStepEvent(int current)
            {
                if (progressBar1.InvokeRequired)
                {
                    this.Invoke(new OnStepEventHandler(this.o_OnStepEvent), new object[] { current });
                }
                else
                {
                    progressBar1.Value = current;
                }
            }
        }
    }
    namespace Client
    {
        public delegate void OnStepEventHandler(int i);
        public class Back : Client.ServiceReference.IServiceExampleCallback
        {
         
            public event OnStepEventHandler OnStepEvent = null;
            public void CallBack(int value)
            {
                if (OnStepEvent != null)
                {
                    OnStepEvent(value);
                }
        
            }
        }
    }













    • 已编辑 my WCF 2009年11月3日 2:14
    2009年10月24日 5:15

答案

  • 谢谢您的回答,当初做这个的时候我是在客户端关闭通道的。后来他们说要在服务器关闭,所有我疑虑了半天。非常感谢。您知道在WCF中如何调用委托吗?我在服务器端定义了 public delegate void aaaEverHandle();,但是我在前台没有获取到,难道是没有暴露在外面:代码如下:
      [ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Multiple, InstanceContextMode=InstanceContextMode.PerSession)]
        public class Hellow : IHellow
        {
            public delegate void aaaEverHandle();
            public string sum(int a, int b)
            {
                return (a + b).ToString();
            }
       }
    客户端没法拿到!


    WCF暂时不支持委托,因为网络传输的必须是可序列化类型,而又不能保证委托可序列化,所以不支持委托.
    你可以使用WCF回调来实现委托的功能.
    2009年11月2日 9:26
  • 你好,

    SingleHostServiceClient类似乎有一些问题,看上去始终会返回唯一的一个实例.你可以修改一下这个类,检查一下当前Channel的状态,不正常的时候new 一个新的实例.
    Please remember to mark the replies as answers if they help and unmark them if they provide no help. Welcome to the All-In-One Code Framework http://cfx.codeplex.com/! If you have any feedback, please tell us.
    2009年10月26日 8:03
    版主

全部回复

  • 你好,

    SingleHostServiceClient类似乎有一些问题,看上去始终会返回唯一的一个实例.你可以修改一下这个类,检查一下当前Channel的状态,不正常的时候new 一个新的实例.
    Please remember to mark the replies as answers if they help and unmark them if they provide no help. Welcome to the All-In-One Code Framework http://cfx.codeplex.com/! If you have any feedback, please tell us.
    2009年10月26日 8:03
    版主
  • 您好,谢谢您的答复。那么我如何保证程序在交互的过程中使用的是同一个session呢。现在我想使用WCF实现代理委托,请问有相关的实例吗?谢谢!如果想捕获委托代理异常时,是否要从客户端和服务器端两个方面下手呢?

    2009年11月2日 0:18
  • 您好,谢谢您的答复。那么我如何保证程序在交互的过程中使用的是同一个session呢。现在我想使用WCF实现代理委托,请问有相关的实例吗?谢谢!如果想捕获委托代理异常时,是否要从客户端和服务器端两个方面下手呢?


    保证同一个SESSION的唯一方式就是通道open后,不发生任何通讯上的错误,这样,直到通道close之前,
    SESSION都是唯一的.

    不太明白你的代理委托是什么意思,捕获异常的话,服务端和客户端是耦合的.
    2009年11月2日 3:34
  • 谢谢。为了保证充分引用硬件资源,当程序完成后,我们必须手动关闭通道,以达到节约资源的目的。那么这个通道的关闭是在服务器端关闭吗?我关闭了客户端的代理,会有什么影响?二者的关系可以这样解释:客户端关闭了,不一定服务器端就关闭了;服务器关闭了,那个客户端就肯定关闭了?望回复。。。。谢

    2009年11月2日 6:17
  • 谢谢。为了保证充分引用硬件资源,当程序完成后,我们必须手动关闭通道,以达到节约资源的目的。那么这个通道的关闭是在服务器端关闭吗?我关闭了客户端的代理,会有什么影响?二者的关系可以这样解释:客户端关闭了,不一定服务器端就关闭了;服务器关闭了,那个客户端就肯定关闭了?望回复。。。。谢


    客户端关闭了,服务器就关闭了;
    服务器关闭会话后,客户端的下一次调用会引发客户端异常,提示会话已关闭,请重新建立会话;
    客户端不显示关闭会话,服务器在一段超时时间段后会自动关闭会话,同时抛出服务端异常.
    2009年11月2日 7:52
  • 谢谢您的回答,当初做这个的时候我是在客户端关闭通道的。后来他们说要在服务器关闭,所有我疑虑了半天。非常感谢。您知道在WCF中如何调用委托吗?我在服务器端定义了 public delegate void aaaEverHandle();,但是我在前台没有获取到,难道是没有暴露在外面:代码如下:
      [ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Multiple, InstanceContextMode=InstanceContextMode.PerSession)]
        public class Hellow : IHellow
        {
            public delegate void aaaEverHandle();
            public string sum(int a, int b)
            {
                return (a + b).ToString();
            }
       }
    客户端没法拿到!

    2009年11月2日 8:42
  • 谢谢您的回答,当初做这个的时候我是在客户端关闭通道的。后来他们说要在服务器关闭,所有我疑虑了半天。非常感谢。您知道在WCF中如何调用委托吗?我在服务器端定义了 public delegate void aaaEverHandle();,但是我在前台没有获取到,难道是没有暴露在外面:代码如下:
      [ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Multiple, InstanceContextMode=InstanceContextMode.PerSession)]
        public class Hellow : IHellow
        {
            public delegate void aaaEverHandle();
            public string sum(int a, int b)
            {
                return (a + b).ToString();
            }
       }
    客户端没法拿到!


    WCF暂时不支持委托,因为网络传输的必须是可序列化类型,而又不能保证委托可序列化,所以不支持委托.
    你可以使用WCF回调来实现委托的功能.
    2009年11月2日 9:26
  • 非常感谢!
    2009年11月2日 9:35
  • 您好,我按照您的意思,做了一个回调,然后在客户端用了一个委托,滚动条的运行情况是完全正确的,但是到第11次的时候,程序就好像死了一样。你能帮我看看这个是怎么回事吗?代码如下: namespace Host { // 注意: 如果更改此处的接口名称 "IServiceExample",也必须更新 App.config 中对 "IServiceExample" 的引用。 [ServiceContract(SessionMode = SessionMode.Required,CallbackContract = typeof(IServiceReturn))] public interface IServiceExample { [OperationContract(IsOneWay=true,IsInitiating=true,IsTerminating=false)] void DoWork(); } public interface IServiceReturn { [OperationContract(IsOneWay = true, IsInitiating = false, IsTerminating =false)] void CallBack(int value); } } namespace Host { // 注意: 如果更改此处的类名 "ServiceExample",也必须更新 App.config 中对 "ServiceExample" 的引用。 [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.PerSession)] public class ServiceExample : IServiceExample { IServiceReturn returnMessage = null; public void DoWork() { returnMessage = OperationContext.Current.GetCallbackChannel(); Thread t = new Thread(new ThreadStart(this.Go)); t.IsBackground = true; t.Start(); } public void Go() { for (int i = 0; i < 100; i++) { returnMessage.CallBack(i); Thread.Sleep(2); } } } } namespace Client { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { } private void button1_Click(object sender, EventArgs e) { Back bck = new Back(); bck.OnStepEvent += new OnStepEventHandler(o_OnStepEvent); InstanceContext ic = new InstanceContext(bck); ServiceReference.ServiceExampleClient cline = new Client.ServiceReference.ServiceExampleClient(ic); cline.DoWork(); } public void o_OnStepEvent(int current) { if (progressBar1.InvokeRequired) { this.Invoke(new OnStepEventHandler(this.o_OnStepEvent), new object[] { current }); } else { progressBar1.Value = current; } } } } namespace Client { public delegate void OnStepEventHandler(int i); public class Back : Client.ServiceReference.IServiceExampleCallback { public event OnStepEventHandler OnStepEvent = null; public void CallBack(int value) { if (OnStepEvent != null) { OnStepEvent(value); } } } }
    2009年11月3日 2:07
  • 你把我难住了.

    你在调试下运行,在程序死循环的时候,按下"暂停"调试,然后看下,程序在干什么,在哪里做死循环.

    你的代码得的等我整理才行.
    2009年11月3日 2:58
  • 可能是没有关闭通道。我在客户端加了一个关闭,就是当进度条达到100的时候我就把Clinet.close().好像是正常了。难道是它里面限制了Cline线程的个数?超过多少就拒绝提供服务?

    2009年11月3日 5:44
  • 可能是没有关闭通道。我在客户端加了一个关闭,就是当进度条达到100的时候我就把Clinet.close().好像是正常了。难道是它里面限制了Cline线程的个数?超过多少就拒绝提供服务?


    你的代码,我运行过了,满10个未关闭会话的操作后,服务端就开始拒绝建立新的会话.
    可能是wsDualHttpBinding默认挂起10个已存在的会话连接,应该可以通过参数设置,
    等明天我修改下绑定测试下.
    2009年11月3日 10:02
  • 非常感谢!这个问题,以前的一个讲师我问过他,他也没正面给过解释,估计也不知道。我今天算是知道为什么了。
    2009年11月3日 11:16
  • 非常感谢!这个问题,以前的一个讲师我问过他,他也没正面给过解释,估计也不知道。我今天算是知道为什么了。

    问题解决.

    在服务行为中配制 serviceThrottling 节,通过修改 maxConcurrentSessions,maxConcurrentInstances 两属性来控制服务端可同时建立的会话数,
    因为maxConcurrentSessions默认为10,所以在未配制下,你的服务只能挂起10个会话.

    注意,如果在ServiceBehavior中指定了InstanceContextMode.PerSession,那么maxConcurrentInstances同样也限制会话数.
    2009年11月5日 1:25
  • 谢谢你的答复:
          可是我确实需要打开会话啊,有什么变通的方法?对了,在WCF传输过程中,我传二进制图片,发现速度好像很难达到我们的要求,像这样的情况,能用什么方式解决呢。我们现在WCF也仅仅只暴露出来了一个接口。

    2009年11月5日 7:53
  • 谢谢你的答复:
          可是我确实需要打开会话啊,有什么变通的方法?对了,在WCF传输过程中,我传二进制图片,发现速度好像很难达到我们的要求,像这样的情况,能用什么方式解决呢。我们现在WCF也仅仅只暴露出来了一个接口。


    修改配置文件

    <serviceThrottling maxConcurrentCalls="400"  maxConcurrentInstances="400" maxConcurrentSessions="100"/>

    这样服务器就支持100个同时在线的会话,你也可以适当修改该值,这依据服务器性能而定.

    传输大数据量数据,论坛上有专门帖子讨论,一般场景下使用 binaryMessageEncoding 会提高一些网络传输效率.
    另外依据你的部署场景,也可以通过选择Transport来改善性能,
    其次,通过使用服务端异步提高服务器的吞吐量.
    2009年11月5日 8:26
  • 恩,好的,我去看看。

    2009年11月6日 2:18