Как использовать событие получения данных в классе Socket? - PullRequest
0 голосов
/ 05 января 2011

Я написал простой клиент, который использует TcpClient в dotnet для связи. Для ожидания сообщений с сервера я использую поток Read(), который использует блокирующий вызов Read() для сокета. Когда я что-то получаю, я должен генерировать различные события. Эти события происходят в рабочем потоке, и поэтому вы не можете напрямую обновлять пользовательский интерфейс. Invoke() можно использовать, но для конечного разработчика это сложно, поскольку мой SDK будет использоваться пользователями, которые вообще не могут использовать пользовательский интерфейс или используют Presentation Framework. У структуры представления есть другой способ справиться с этим. Invoke() в нашем тестовом приложении Microstation Addin на данный момент занимает много времени. Microstation - это однопоточное приложение, и вызов invoke в его потоке не годится, так как он всегда занят рисованием, а другие сообщения занимают слишком много времени.

Я хочу, чтобы мои события генерировались в том же потоке, что и пользовательский интерфейс, поэтому пользователю не нужно проходить через Dispatcher или Invoke.

Теперь я хочу знать, как я могу получать уведомления по сокету при поступлении данных? Есть ли для этого обратный вызов? Мне нравится стиль получения winsock без использования отдельной темы чтения. Я также не хочу использовать таймер окна для опроса данных.

Я обнаружил флаг IOControlCode.AsyncIO в функции IOControl(), которая подсказывает:

Включить уведомление, когда данные в ожидании получения. Это значение равный Winsock 2 FIOASYNC постоянная.

Я не смог найти ни одного примера, как использовать его для получения уведомления. Если я прав в MFC / Winsock, мы должны создать окно size(0,0), которое просто использовалось для прослушивания события получения данных или других событий сокета. Но я не знаю, как это сделать в приложении dotnet.

Ответы [ 2 ]

1 голос
/ 06 января 2011

Хорошо, я запустил его и запустил. Что я действительно искал, так это как легко публиковать события в потоке пользовательского интерфейса, в котором создается мое соединение. Пройдя через фреймворк, я пришел к следующему доказательству концепции. SynchronizationContext можно использовать для привязки моего компонента к потоку пользовательского интерфейса, который его создал. Затем я могу публиковать события в этом потоке пользовательского интерфейса напрямую, без использования Invoke.

В следующем примере я создал ThreadUISafeTimer, который использует отдельный поток, как мой сокет-клиент, который использует один для чтения и вызова событий. В этом случае context используется для публикации события, если оно не равно нулю, в противном случае событие вызывается с использованием рабочего потока.

[DefaultEvent("Tick")]
public class ThreadUISafeTimer : Component
{
    private const int True = 1;
    private const int False = 0;
    private int enabled = False;
    private SynchronizationContext context;

    public event EventHandler Tick = delegate { };

    [DefaultValue(false)]
    public ushort Interval { get; set; }

    public ThreadUISafeTimer() {
        Interval = 100;
        this.Events.AddHandler("Tick", Tick);
        //If this class is created by a UI thread it will always post the Tick event to it.
        //otherwise it would be null and Tick would occur in a seperate thread.
        context = SynchronizationContext.Current;

    }
    protected override bool CanRaiseEvents {
        get {
            return true;
        }
    }
    [DefaultValue(false)]
    public bool Enabled {
        get {
            return enabled == True;
        }
        set {
            int newval = value ? True : False;
            if (enabled != newval) {
                if (newval == False)
                    Thread.VolatileWrite(ref enabled, False);
                else {
                    enabled = True;
                    ThreadPool.QueueUserWorkItem(
                        new WaitCallback(delegate(object o) {
                        try {
                            do {
                                try {
                                    Thread.Sleep(Interval);
                                    if (Thread.VolatileRead(ref enabled) == True) {
                                        var callback = new SendOrPostCallback(delegate(object arg) {
                                            try {
                                                Tick(this, EventArgs.Empty);
                                            }
                                            catch (Exception exp) {
                                                Application.OnThreadException(exp);
                                                return;
                                            }
                                        });
                                        //If context is null raise Tick event from current thread
                                        if (context == null)
                                            callback(null);
                                        else
                                            //otherwise post it to the UI thread that owns this timer.
                                            context.Post(callback, null);
                                    }
                                }
                                catch (ThreadInterruptedException) {
                                }

                            } while (Thread.VolatileRead(ref enabled) == True);
                        }
                        catch (ThreadAbortException) {
                        }
                    }), null);
                }
            }
        }
    }
0 голосов
/ 06 января 2011

Посмотрите на этот вопрос, который примерно такой же и решается с использованием шаблона Event Broker.

Отправка инструкций потоку, ожидающему TCP?

По сути, у вас будет один объект с событием, на которое подписываются все ваши потоки. Он также будет иметь метод, который можно вызвать, который вызовет событие. Возможно, это звучит сложно, но довольно просто.

Пример кода здесь http://msforge.net/blogs/paki/archive/2007/11/20/EventBroker-implementation-in-C_2300_-full-source-code.aspx.

...