首页 文章

如何检测udpclient何时收到数据?

提问于
浏览
2

我目前正在制作一个家庭使用的小程序(主要是因为每次我想告诉我爸爸的事情,我都懒得跑下楼梯) .

至于我的问题:

一旦udpclient收到来自对等体的消息,我怎样才能让这段代码调用我的 ReceiveText 方法? (注意:运行这个's only going to be 2 pc',将两个ip硬编码到其中)


同时感谢艾哈迈德·伊利亚斯回答了上述问题,但是我遇到了他发布的链接中的特征:

邮件正好像这样发送:

sendMe.Connect("192.168.0.121", 60500);
sendBytes = Encoding.ASCII.GetBytes(txtSend.Text);
sendMe.Send(sendBytes, sendBytes.Length);
sendMe.Close();

这个问题似乎存在于接收端,从我从异常中读到的异常情况看来,当我尝试实际使用已发送的数据时,我可以为我的Rich Text Box正确格式化等 .

这是接收和解析传入数据的代码:

UdpClient sendMe = new UdpClient(60500);
UdpClient illReceive = new UdpClient(60501);
Byte[] sendBytes;
string returnData;
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);

...
try
{
        illReceive.BeginReceive(new AsyncCallback(RecieveText), null);
    }
    catch (Exception e)
    {
        MessageBox.Show(e.ToString());
}
...

void ReceiveText(IAsyncResult res)
{
    try
    {
        System.Reflection.Assembly a = _
System.Reflection.Assembly.GetExecutingAssembly();
        System.IO.Stream s = a.GetManifestResourceStream("IPSend.ns.wav");
        SoundPlayer player = new SoundPlayer(s);
        player.Play();

        byte[] received = illReceive.EndReceive(res, ref RemoteIpEndPoint);
        returnData = Encoding.UTF8.GetString(received);
        TextRange tr = new _
TextRange(rtbPast.Document.ContentEnd, rtbPast.Document.ContentEnd);
        tr.Text = String.Format("{0} - Yorrick: {1} {2}", _
DateTime.Now.ToShortTimeString(), returnData, Environment.NewLine);
        tr.ApplyPropertyValue(TextElement.ForegroundProperty, Brushes.Red);
        tr.ApplyPropertyValue(TextElement.BackgroundProperty, Brushes.Black);
        illReceive.BeginReceive(new AsyncCallback(RecieveText), null);
    }
    catch (Exception e)
    {
        MessageBox.Show(e.ToString());
    }
}

PS:我现在正在使用MessageBox.Show,因此我可以清楚地看一下抛出的异常,从我理解的那些,它似乎是 ReceiveText 方法中的某个问题 .

被抛出的异常:(第1行翻译:"The call thread can not open this object because it is owned by another thread.")
Exception


尝试C.Evenhuis代码后的新异常(在为WPF更改后):
New Exception
此异常背后的代码:

void ReceiveText(IAsyncResult res)
{
    try
    {
        byte[] received = illReceive.EndReceive(res, ref RemoteIpEndPoint);
        returnData = Encoding.UTF8.GetString(received);

        InformUser(returnData);

        illReceive.BeginReceive(new AsyncCallback(ReceiveText), null);
    }
    catch (Exception e)
    {
        MessageBox.Show(e.ToString());
    }
}

void InformUser(string data)
{
    // InvokeRequired tells you you're not on the correct thread to update the _
//rtbPast
    if (rtbPast.Dispatcher.CheckAccess())
    {
        // Call InformUser(data) again, but on the correct thread
        rtbPast.Dispatcher.Invoke(new Action<string>(InformUser), data);

        // We're done for this thread
        return;
    }

    System.Reflection.Assembly a = _
System.Reflection.Assembly.GetExecutingAssembly();
    System.IO.Stream s = a.GetManifestResourceStream("IPSend.ns.wav");
    SoundPlayer player = new SoundPlayer(s);
    player.Play();

    TextRange tr = new TextRange(rtbPast.Document.ContentEnd, _
rtbPast.Document.ContentEnd);
    tr.Text = String.Format("{0} - Pa: {1} {2}", _
DateTime.Now.ToShortTimeString(), data, Environment.NewLine);
    tr.ApplyPropertyValue(TextElement.ForegroundProperty, Brushes.Red);
    tr.ApplyPropertyValue(TextElement.BackgroundProperty, Brushes.Black);
}

PS:如果你需要看看我的整个代码,我实际上发布它有点太长了:Entire code on Pastebin

2 回答

  • 2

    Yorrick,InformUser()中的“检查访问”逻辑被反转 . 如果当前线程与调度程序关联,CheckAccess()将返回true . 只有在CheckAccess()返回false时才应调用Invoke() . 当前正在发生的事情是你正在调用InformUser(),CheckAccess()返回false,并且执行会因为你仍然从错误的线程访问控件而落入给你带来麻烦的相同代码 .

    你需要的是这个(否定支票):

    if (!rtbPast.Dispatcher.CheckAccess()) // Invoke only when CheckAccess returns false
    {
        // Call InformUser(data) again, but on the correct thread
        rtbPast.Dispatcher.Invoke(new Action<string>(InformUser), data);
    
        // We're done for this thread
        return;
    }
    
  • 1

    导致此问题是因为像 ReceiveText 这样的AsyncCallback方法通常在与"main"线程不同的线程中运行 . 控件只能从创建它们的线程中访问 .

    要解决此问题,您需要拆分“接收”部分:

    void ReceiveText(IAsyncResult res)
        {
            try
            {
                byte[] received = illReceive.EndReceive(res, ref RemoteIpEndPoint);
                returnData = Encoding.UTF8.GetString(received);
    
                InformUser(returnData);
    
                illReceive.BeginReceive(new AsyncCallback(RecieveText), null);
            }
            catch (Exception e)
            {
                MessageBox.Show(e.ToString());
            }
        }
    

    从“显示”部分:

    void InformUser(string data)
        {
            // InvokeRequired tells you you're not on the correct thread to update the rtbPast
            if (rtbPast.InvokeRequired)
            {
                // Call InformUser(data) again, but on the correct thread
                rtbPast.Invoke(new Action<string>(InformUser), data);
    
                // We're done for this thread
                return;
            }
    
            System.Reflection.Assembly a = System.Reflection.Assembly.GetExecutingAssembly();
            System.IO.Stream s = a.GetManifestResourceStream("IPSend.ns.wav");
            SoundPlayer player = new SoundPlayer(s);
            player.Play();
    
            TextRange tr = new TextRange(rtbPast.Document.ContentEnd, rtbPast.Document.ContentEnd);
            tr.Text = String.Format("{0} - Yorrick: {1} {2}", DateTime.Now.ToShortTimeString(), data, Environment.NewLine);
            tr.ApplyPropertyValue(TextElement.ForegroundProperty, Brushes.Red);
            tr.ApplyPropertyValue(TextElement.BackgroundProperty, Brushes.Black);
        }
    

相关问题