0

dotnet で TcpClient を使用して通信する単純なクライアントを作成しました。サーバーからのデータメッセージを待つために、ソケットでRead()ブロッキング呼び出しを使用するスレッドを使用します。Read()何かを受け取ると、さまざまなイベントを生成する必要があります。これらのイベントはワーカー スレッドで発生するため、そこから直接 UI を更新することはできません。Invoke()使用できますが、UI をまったく使用しないユーザーやプレゼンテーション フレームワークを使用するユーザーが SDK を使用するため、最終開発者にとっては困難です。プレゼンテーション フレームワークでは、これを処理する方法が異なります。Invoke()現時点では、Microstation Addin としてのテスト アプリでは多くの時間がかかります。Microstation はシングル スレッド アプリケーションであり、そのスレッドでの call invoke は、常に描画を行うのに忙しく、他のメッセージの処理に時間がかかりすぎるため、適切ではありません。

Dispatcherユーザーがまたはを通過する必要がないように、UI と同じスレッドでイベントを生成したいInvoke

データが到着したときにソケットから通知を受ける方法を知りたいですか? そのためのコールバックが組み込まれていますか。別の読み取りスレッドを使用せずに winsock スタイルの受信イベントが好きです。また、データのポーリングにウィンドウタイマーを使用したくありません。

ヘルプが言う関数にIOControlCode.AsyncIOフラグが見つかりましたIOControl()

データの受信待ちの通知を有効にします。この値は、Winsock 2FIOASYNC 定数と同じです。

それを使用して通知を受け取る方法の例は見つかりませんでした。私が MFC/Winsock にいる場合size(0,0)は、データ受信イベントまたは他のソケット イベントをリッスンするために使用されたウィンドウを作成する必要があります。しかし、ドットネット アプリケーションでそれを行う方法がわかりません。

4

2 に答える 2

1

わかりました。起動して実行しました。私が本当に探していたのは、接続が作成される UI スレッドにイベントをシームレスに投稿する方法でした。フレームワークコードを調べた後、次の概念実証を思い付きました。SynchronizationContextコンポーネントをそれを作成した UI スレッドにバインドするために使用できます。次に、を使用せずに、その UI スレッドにイベントを直接投稿できますInvoke

次の例ThreadUISafeTimerでは、イベントの読み取りと発生に別のスレッドを使用するソケット クライアントと同じように、別のスレッドを使用する を作成しました。この場合、contextnull でない場合はイベントを投稿するために使用され、それ以外の場合はワーカー スレッドを使用してイベントが発生します。

[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);
                }
            }
        }
    }
于 2011-01-05T21:00:15.717 に答える
0

この質問を見てください。これはほぼ同じで、Event Broker パターンを使用して解決されます。

TCP を待機しているスレッドに命令を送信しますか?

基本的に、すべてのスレッドがサブスクライブするイベントを持つ 1 つのオブジェクトがあります。また、イベントを呼び出すメソッドを呼び出すこともできます。複雑に聞こえるかもしれませんが、かなり単純です。

コード例はhttp://msforge.net/blogs/paki/archive/2007/11/20/EventBroker-implementation-in-C_2300_-full-source-code.aspxです。

于 2011-01-05T21:13:01.633 に答える