如何在Socket类中使用数据接收事件?

时间:2011-01-05 09:49:44

标签: c# .net sockets winsockets

我写了一个简单的客户端,在dotnet中使用TcpClient进行通信。为了等待来自服务器的数据消息,我使用Read()线程在socket上使用阻塞Read()调用。当我收到的东西,我必须生成各种事件。这些事件发生在工作线程中,因此您无法直接从其更新UI。 Invoke()可以使用,但对于最终开发人员来说很困难,因为我的SDK可能会被完全不使用UI或使用Presentation Framework的用户使用。演示框架有不同的处理方式。 Invoke()在我们的测试应用上,Microstation Addin目前需要花费大量时间。 Microstation是单线程应用程序,并且在其线程上调用调用并不好,因为它总是忙于绘图,而其他消息需要花费太长时间来处理。

我希望我的事件在与UI相同的线程中生成,因此用户不必通过DispatcherInvoke

现在我想知道当数据到达时如何通过套接字通知我?是否有内置回调。我喜欢winsock样式接收事件而不使用单独的读取线程。我也不想使用窗口计时器来轮询数据。

我在IOControlCode.AsyncIO函数中找到了IOControl()标记,这有助于说明

  

启用数据时间通知   等待收到。这个值是   等于Winsock 2 FIOASYNC   恒定。

我找不到任何关于如何使用它来获取通知的示例。如果我在MFC / Winsock中是正确的,我们必须创建一个size(0,0)窗口,该窗口仅用于监听数据接收事件或其他套接字事件。但我不知道如何在dotnet应用程序中这样做。

2 个答案:

答案 0 :(得分:1)

好的,我把它拿起来跑了。我真正想要的是如何将事件无缝地发布到UI线程,在该线程中创建了我的连接。在完成框架代码之后,我想出了以下概念证明。 SynchronizationContext可用于将我的组件绑定到创建它的UI线程。然后我可以直接将事件发布到该UI线程,而不使用Invoke

在下面的示例中,我创建了一个ThreadUISafeTimer,它使用了一个单独的线程,就像我的socket客户端一样,用于读取和引发事件。在这种情况下,context用于发布事件(如果不为null),否则使用工作线程引发事件。

[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);
                }
            }
        }
    }

答案 1 :(得分:0)

看看这个大致相同的问题,并使用Event Broker模式解决。

Sending instructions to a thread which is waiting for TCP?

基本上你会有一个对象包含你所有线程都订阅的事件。它还将有一个可以调用的方法来调用该事件。这可能听起来很复杂,但相当简单。

示例代码在这里http://msforge.net/blogs/paki/archive/2007/11/20/EventBroker-implementation-in-C_2300_-full-source-code.aspx