2011-01-05 54 views
0

我寫了一個簡單的客戶端,它使用dotnet中的TcpClient進行通信。爲了等待來自服務器的數據消息,我使用了一個Read()線程,它使用阻塞Read()調用套接字。當我收到我必須產生的各種事件。這些事件發生在工作線程中,因此您無法直接從它更新UI。 Invoke()可以使用,但對於最終開發者來說很困難,因爲我的SDK可能會被可能根本不使用UI或使用Presentation Framework的用戶使用。表示框架有不同的處理方式。我們的測試應用程序上的Invoke()因爲Microstation Addin需要花費大量的時間。 Microstation是單線程應用程序,並且其線程上的調用調用並不好,因爲它總是忙於執行繪圖和其他東西消息需要太長的時間來處理。如何在Socket類中使用數據接收事件?

我想我的事件生成在與UI相同的線程中,因此用戶不必通過DispatcherInvoke

現在我想知道我怎樣才能通過插座時通知數據到達的?是否有一個回調的構建。我喜歡winsock樣式接收事件,而不使用單獨的讀取線程。我也不想使用窗口計時器來輪詢數據。

我發現IOControlCode.AsyncIO標誌IOControl()功能,幫助說

啓用時,數據是 等待接收的通知。此值是 等於Winsock 2 FIOASYNC 恆定。

我找不到任何關於如何使用它來獲取通知的示例。如果我在MFC/Winsock中正確,我們必須創建一個窗口size(0,0),它僅用於偵聽數據接收事件或其他套接字事件。但我不知道如何在dotnet應用程序中做到這一點。

+0

在linux中它很容易使用。但是仍然無法找到在dotnet應用程序中使用'FIOASYNC'的例子。 – affan 2011-01-05 10:04:35

+0

看來我必須使用回調函數調用'BeginReceive()',並且在該回調函數中我再次調用'BeginReceive()'。這從msdn。 – affan 2011-01-05 11:11:27

回答

1

好吧我得到它運行起來。我真正想要的是如何將事件無縫地發佈到UI線程中,在該線程中創建了我的連接。在通過框架代碼之後,我提出了以下概念驗證。 SynchronizationContext可用於將我的組件綁定到創建它的UI線程。然後,我可以直接將事件發佈到該UI線程,而不使用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); 
       } 
      } 
     } 
    } 
相關問題