C#通过TCP接收远程命令并在WinForm上调用它们(多线程)

时间:2010-08-28 19:18:32

标签: c# winforms multithreading tcp command

我有一个控制台,我想在另一台计算机上调用WinForm上的命令(我现在通过localhost测试它)。

当表单启动时,它会实例化CommandListener以通过TCP接收命令。每当我尝试在没有单独线程的情况下实例化它时,winform根本不显示,所以我使用“Initialize”在一个单独的线程上运行它。

    public CommandListener(Form client)
    {
        this.ClientControl = client;

        Socket CommandSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        IPAddress ipa = IPAddress.Loopback;
        IPEndPoint ipe = new IPEndPoint(ipa, 23120);

        CommandSocket.Bind(ipe);
        CommandSocket.Listen(1);

        Thread RemoteCommandListener = new Thread(new ParameterizedThreadStart(Initialize));
        RemoteCommandListener.Start(CommandSocket);

    }

    private void Initialize(object obj)
    {
        Socket CommandSocket = (Socket)obj;

        while (true)
        {
            allDone.Reset();
            CommandSocket.BeginAccept(new AsyncCallback(AcceptCallback), CommandSocket);
            allDone.WaitOne();
        }
    }

不幸的是,如果我使用单独的线程,在尝试在winform上调用命令时,我会收到“交叉线程操作无效”作为错误。

            int bytesRead = Master.EndReceive(ar);
            if (bytesRead > 0)
            {
                state.sb.Append(Encoding.ASCII.GetString(state.Buffer, 0, bytesRead));

                command = state.sb.ToString();
                if (command.IndexOf("Write") > -1)
                {
                    try
                    {
                        MethodInfo method = typeof(Multiboxxy).GetMethod(command);
                        method.Invoke(ClientControl, new object[] { "Success!" });
                    }
                    catch (Exception e)
                    {
                        MessageBox.Show(e.InnerException.Message);
                    }
                }
                else
                {
                    Master.BeginReceive(state.Buffer, 0, StateObject.BufferSize, 0,
                       new AsyncCallback(ReadCallback), state);
                }
            }

2 个答案:

答案 0 :(得分:1)

我建议改用WCF; WCF中有一个选项可以自动同步到主机的SynchronizationContext

下一个最佳选择是使用自动同步套接字对象,例如Nito.Async中的套接字对象。

第三个选项是保留.NET Socket类,但是当您需要进行UI更新时,请使用计划到UI线程Task的{​​{1}}。 TaskScheduler.FromCurrentSynchronizationContextTask内置于.NET 4.0中,available in a library适用于.NET 3.5。

第四个选项是保留.NET TaskScheduler类并直接使用Socket来更新UI。

答案 1 :(得分:0)

使用:

而不是MethodInfo.Invoke
// somewhere, define a delegate type for the invoked method (e.g. 'InvokerDelegate')

if (ClientControl.InvokeRequired)
    ClientControl.Invoke(Delegate.CreateDelegate(typeof(InvokerDelegate), ClientControl, method), "Success!");
else
    method.Invoke(ClientControl, new object[] { "Success!" });

据我所知,Control类'Invoke()方法是在控件上调用方法时执行正确线程同步的唯一方法。