草庐IT

c# - 在 winforms 或 wpf 上托管的 Tcp wcf 服务挂起

coder 2023-09-19 原文

我在 winforms 或 WPF 上托管的 Tcp Wcf 服务中遇到错误。 该服务挂起或引发“线程已退出”错误。

相同的代码在控制台应用程序中运行良好。

谢谢。

服务器:

    namespace WCFService
    {
        //interface declarations just like the client but the callback 
        //decleration is a little different
        [ServiceContract]
        interface IMessageCallback
        {
            [OperationContract(IsOneWay = true)]
            void OnMessageAdded(string message, DateTime timestamp);
        }

        //This is a little different than the client 
        // in that we need to state the SessionMode as required or it will default to "notAllowed"
        [ServiceContract(CallbackContract = typeof(IMessageCallback), SessionMode = SessionMode.Required)]
        public interface IMessage
        {
            [OperationContract]
            void AddMessage(string message);
            [OperationContract]
            bool Subscribe();
            [OperationContract]
            bool Unsubscribe();
        }

        [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
        class RCRServer : IMessage
        {
            private static List<IMessageCallback> subscribers = new List<IMessageCallback>();
            public ServiceHost host = null;


            public void Connect()
            {
                //I'm doing this next part progromatically instead of in app.cfg 
                // because I think it makes it easier to understand (and xml is stupid)
                 host = new ServiceHost(typeof(RCRServer), new Uri("net.tcp://localhost:8000"));

                    //notice the NetTcpBinding?  This allows programs instead of web stuff
                    // to communicate with each other
                    host.AddServiceEndpoint(typeof(IMessage), new NetTcpBinding(), "ISubscribe");

                    try
                    {
                        host.Open();
                        Console.WriteLine("Successfully opened port 8000.");
                        //Console.ReadLine();
                        //host.Close();
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e.Message);
                    }

            }



            public bool Subscribe()
            {
                try
                {
                    //Get the hashCode of the connecting app and store it as a connection
                    IMessageCallback callback = OperationContext.Current.GetCallbackChannel<IMessageCallback>();
                    if (!subscribers.Contains(callback))
                        subscribers.Add(callback);
                    return true;
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                    return false;
                }
            }

            public bool Unsubscribe()
            {
                try
                {
                    //remove any connection that is leaving
                    IMessageCallback callback = OperationContext.Current.GetCallbackChannel<IMessageCallback>();
                    if (subscribers.Contains(callback))
                        subscribers.Remove(callback);
                    return true;
                }
                catch
                {
                    return false;
                }
            }

            public void AddMessage(String message)
            {

                //Console.WriteLine("Calling OnMessageAdded on callback");

                //foreach (Subscriber s in subscribers.Values.ToList())
                //{ }

                try
                {
                    Console.WriteLine("Clients connected to service " + subscribers.Count.ToString());
                    IMessageCallback callback = OperationContext.Current.GetCallbackChannel<IMessageCallback>();
                    callback.OnMessageAdded(message, DateTime.Now);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }

                //Go through the list of connections and call their callback funciton
                //subscribers.ForEach(delegate (IMessageCallback callback)
                //{

                //    //System.Threading.Thread.Sleep(1000);
                //    if (((ICommunicationObject)callback).State == CommunicationState.Opened)
                //    {
                //        Console.WriteLine("Clients connected to service " + subscribers.Count.ToString());
                //        callback.OnMessageAdded(message, DateTime.Now);
                //    }
                //    else
                //    {
                //        subscribers.Remove(callback);
                //    }
                //});

            }
        }
    }


Client:



    namespace WCFClient
    {
        //These are the interface declerations for the client
        [ServiceContract]
        interface IMessageCallback
        {
            //This is the callback interface decleration for the client
            [OperationContract(IsOneWay = true)]
            void OnMessageAdded(string message, DateTime timestamp);
        }


        [ServiceContract(CallbackContract = typeof(IMessageCallback))]
        public interface IMessage
        {
            //these are the interface decleratons for the server.
            [OperationContract]
            void AddMessage(string message);
            [OperationContract]
            bool Subscribe();
            [OperationContract]
            bool Unsubscribe();
        }



        class RCRProxy : IMessageCallback, IDisposable
        {
            IMessage pipeProxy = null;

            //MainWindow mainwindow = new MainWindow();
            //public RCRProxy(MainWindow main)
            //{
            //    mainwindow = main;
            //}
            public bool Connect()
            {
                //note the "DuplexChannelFactory".  This is necessary for Callbacks.
                // A regular "ChannelFactory" won't work with callbacks.
                DuplexChannelFactory<IMessage> pipeFactory =
                      new DuplexChannelFactory<IMessage>(
                          new InstanceContext(this),
                          new NetTcpBinding(),
                          new EndpointAddress("net.tcp://localhost:8000/ISubscribe"));


                try
                {
                    //Open the channel to the server
                    pipeProxy = pipeFactory.CreateChannel();
                    //Now tell the server who is connecting
                    pipeProxy.Subscribe();
                    return true;
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                    return false;
                }
            }
            public void Close()
            {
                pipeProxy.Unsubscribe();
            }



            //This function sends a string to the server so that it can broadcast
            // it to all other clients that have called Subscribe().
            public string SendMessage(string message)
            {
                try
                {
                    System.Threading.Thread.Sleep(1000);
                    pipeProxy.AddMessage(message);
                    return "sent >>>>  " + message;
                }
                catch (Exception e)
                {
                    return e.Message;
                }
            }

            //This is the function that the SERVER will call
            public void OnMessageAdded(string message, DateTime timestamp)
            {
                //Console.WriteLine(message + ": " + timestamp.ToString("hh:mm:ss"));
               // mainwindow.txtblkStatus.Text = message + ": " + timestamp.ToString("hh:mm:ss");
            }

            //We need to tell the server that we are leaving
            public void Dispose()
            {
                pipeProxy.Unsubscribe();
            }
        }
    }



    namespace StockTickerClient
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        /// 


        public class DataItem
        {
            public string Symbol { get; set; }
            public string Series { get; set; }
            public float? AskPrice { get; set; }
            public float? BidPrice { get; set; }
            public float? LTP { get; set; }
            public int? Volume { get; set; }
            public string Description { get; set; }
            public DateTime? SentDate { get; set; }

            public DataItem(string symbol, string series, float? askprice, float? bidprice, float? ltp, int? volume, string

description, DateTime? sentdate) { Symbol = symbol; Series = series; AskPrice = askprice; BidPrice = bidprice; LTP = ltp; Volume = volume; Description = description; SentDate = sentdate; } }

        public partial class MainWindow : Window
        {

            private void btnSubscribe_Click(object sender, RoutedEventArgs e)
            {
                RCRProxy rp = new RCRProxy();
                if (rp.Connect() == true)
                {

                    // Console.WriteLine("please space to end session");
                    string tmp = "Start";// Console.ReadLine();
                    while (tmp != "Exit")
                    {
                        try
                        {
                            rp.SendMessage(tmp);
                        }
                        catch (Exception ex)
                        {

                            txtblkStatus.Text = ex.Message;
                        }

                        // tmp = Console.ReadLine();
                        // txtblkStatus.Text = rp.SendMessage(tmp);
                    }
                }
                if (((ICommunicationObject)rp).State == CommunicationState.Opened)
                    rp.Close();
            }
        }
    }

最佳答案

在 winforms/wpf 应用程序中,服务器和客户端之间的通信应该在仅负责该通信的辅助线程上完成。如果您将按钮 btnSubscribe_Click 上的操作放在新线程中,应用程序将正常运行。

查看有关如何在 wpf 中使用线程的更多详细信息:

c# wpf run button click on new thread

https://www.c-sharpcorner.com/UploadFile/1c8574/threads-in-wpf/

https://msdn.microsoft.com/en-us/library/ms741870(v=vs.85).aspx

关于c# - 在 winforms 或 wpf 上托管的 Tcp wcf 服务挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49607474/

有关c# - 在 winforms 或 wpf 上托管的 Tcp wcf 服务挂起的更多相关文章

  1. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  2. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

  3. ruby-on-rails - 启动 Rails 服务器时 ImageMagick 的警告 - 2

    最近,当我启动我的Rails服务器时,我收到了一长串警告。虽然它不影响我的应用程序,但我想知道如何解决这些警告。我的估计是imagemagick以某种方式被调用了两次?当我在警告前后检查我的git日志时。我想知道如何解决这个问题。-bcrypt-ruby(3.1.2)-better_errors(1.0.1)+bcrypt(3.1.7)+bcrypt-ruby(3.1.5)-bcrypt(>=3.1.3)+better_errors(1.1.0)bcrypt和imagemagick有关系吗?/Users/rbchris/.rbenv/versions/2.0.0-p247/lib/ru

  4. ruby-on-rails - s3_direct_upload 在生产服务器中不工作 - 2

    在Rails4.0.2中,我使用s3_direct_upload和aws-sdkgems直接为s3存储桶上传文件。在开发环境中它工作正常,但在生产环境中它会抛出如下错误,ActionView::Template::Error(noimplicitconversionofnilintoString)在View中,create_cv_url,:id=>"s3_uploader",:key=>"cv_uploads/{unique_id}/${filename}",:key_starts_with=>"cv_uploads/",:callback_param=>"cv[direct_uplo

  5. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  6. ruby - 用 Ruby 编写一个简单的网络服务器 - 2

    我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b

  7. ruby-on-rails - 在 Rails 中调试生产服务器 - 2

    您如何在Rails中的实时服务器上进行有效调试,无论是在测试版/生产服务器上?我试过直接在服务器上修改文件,然后重启应用,但是修改好像没有生效,或者需要很长时间(缓存?)我也试过在本地做“脚本/服务器生产”,但是那很慢另一种选择是编码和部署,但效率很低。有人对他们如何有效地做到这一点有任何见解吗? 最佳答案 我会回答你的问题,即使我不同意这种热修补服务器代码的方式:)首先,你真的确定你已经重启了服务器吗?您可以通过跟踪日志文件来检查它。您更改的代码显示的View可能会被缓存。缓存页面位于tmp/cache文件夹下。您可以尝试手动删除

  8. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  9. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  10. ruby - 我的 Ruby IRC 机器人没有连接到 IRC 服务器。我究竟做错了什么? - 2

    require"socket"server="irc.rizon.net"port="6667"nick="RubyIRCBot"channel="#0x40"s=TCPSocket.open(server,port)s.print("USERTesting",0)s.print("NICK#{nick}",0)s.print("JOIN#{channel}",0)这个IRC机器人没有连接到IRC服务器,我做错了什么? 最佳答案 失败并显示此消息::irc.shakeababy.net461*USER:Notenoughparame

随机推荐