C # Получение удаленных команд по TCP и вызов их в WinForm (многопоточный) - PullRequest
0 голосов
/ 28 августа 2010

У меня есть консоль, которую я хочу использовать для вызова команд на 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 ]

1 голос
/ 28 августа 2010

Я рекомендую вместо этого использовать WCF;в WCF есть опция для автоматической синхронизации с SynchronizationContext хоста.

Следующим лучшим вариантом является использование автоматически синхронизируемых объектов сокетов, таких как Nito.Async .

Третий вариант - сохранить класс .NET Socket, но когда вам нужно выполнить обновления пользовательского интерфейса, используйте Task, запланированный для потока пользовательского интерфейса (TaskScheduler.FromCurrentSynchronizationContext).Task и TaskScheduler встроены в .NET 4.0 и доступны в библиотеке для .NET 3.5.

Четвертый вариант - сохранить класс .NET Socket ииспользуйте SynchronizationContext непосредственно для обновления пользовательского интерфейса.

0 голосов
/ 28 августа 2010

Вместо 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 class 'Invoke(), насколько мне известно, является единственным способом для правильной синхронизации потоков при вызове методов.на контроле.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...