none
c# UDP Broadcast und ICMP (Host unreachable) RRS feed

  • Frage

  • Hallo!

    Ich habe ein Problem mit meinem Programm. Ich sende einen Broadcast per UDP um nach bstimmten Geräten zu suchen. Das funktionierte bisher auch super. Jetzt hängt hier ein Beamer im Netz und schickt auf meine Anfrage ein ICMP-Paket "Destination Host is unreachable". Das wäre nicht so schlimm, wenn bei Win < Vista (XP, 2003 Server ..) nicht mein lauschender Socket mit einer Exception beendet würde. Ich habe versucht, den Socket, wenn ich die Exception bekomme, wieder zu aktivieren. Das funktioniert aber nicht.

    Hat jemand eine Idee, wie ich dieses Problem löse? Warum ist das bei Windows Vista und 7 anders?

    Hier noch etwas Quellcode:

     

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Net.Sockets;
    using System.Text;
    using System.Threading;
      
    namespace MyNamespace
    {
        class SockReadData
        {
            public Socket soc;
            public SockRead sockRead;
            public byte[] endBuf;
            public byte[] readBuf;
            public EndPoint endPointFrom;
      
            public static int iReadBufMax = 4096;
      
            public SockReadData(SockRead theSockRead)
            {
                soc = null;
                sockRead = theSockRead;
                endBuf = new byte[0];
                readBuf = new byte[iReadBufMax];
                endPointFrom = (EndPoint)new IPEndPoint(new IPAddress(0), 0);
            }
      
            public void Clear()
            {
                soc = null;
                sockRead = null;
                endBuf = new byte[0];
                readBuf = new byte[0];
                endPointFrom = (EndPoint)new IPEndPoint(new IPAddress(0), 0);
            }
        }
      
        class SockRead
        {
            private int _iPort;
            protected Socket _soc;
            public List<SockReadData> _list;
            public bool _stopRecieving = false;
            private Timer _recieveTimer;
            private int _recTimeout = 3000;
            public string service = "noScan";
      
            public SockRead(int iPort, int timeout)
            {
                _list = new List<SockReadData>();
                _iPort = iPort;
                _recTimeout = timeout;
                _recieveTimer = new Timer(new TimerCallback(stopRec), null, _recTimeout, 0);
            }
      
            public void Stop()
            {
                if (_soc == null)
                    return;
                _soc.Shutdown(SocketShutdown.Both);
                _soc.Close();
                _soc = null;
            }
      
            /// <summary>
            /// sendet ein SNMP-Packet und startet das Empfangen von Antworten
            /// </summary>
            /// <param name="localIP">IP-Adresse, von welcher gesendet werden soll</param>
            /// <returns>Boolean: true, wenn keine Fehler auftraten, sonst false</returns>
      
            public bool Start(IPAddress localIP)
            {
                //neue Instanz von SockReadDate, wird die Antworten empfangen
                SockReadData sockReadData = new SockReadData(this);
                string strErr;
      
                // Empfangen ist schon gestartet muß erst gestoppt werden
                if (_soc != null)
                    return false;
                try
                {
                    //Socket erstellen und konfigurieren
                    _soc = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                    sockReadData.soc = _soc;
                    _soc.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
                    _soc.Bind(new IPEndPoint(localIP, _iPort));
                    Thread.Sleep(800);
                    sockReadData.endPointFrom = new IPEndPoint(IPAddress.Broadcast, _iPort);
                    _soc.BeginReceiveFrom(sockReadData.readBuf, 0, SockReadData.iReadBufMax, SocketFlags.None, ref sockReadData.endPointFrom, new AsyncCallback(beginRead), sockReadData);
      
                    //ReciveTimeout-Timer starten
                    _recieveTimer.Change(_recTimeout, 0);
                    return true;
                }
                catch (System.Exception exc)
                {
                    strErr = exc.ToString();
                }
                return false;
            }
      
            public static void beginRead(IAsyncResult ar)
            {
                SockReadData readData = (SockReadData)ar.AsyncState;
                SockReadData readDataNew = new SockReadData(readData.sockRead);
                readDataNew.soc = readData.soc;
      
                EndPoint endPoint = (EndPoint)new IPEndPoint(new IPAddress(0), 0);
                string strErr = "";
                int idx;
                int iRead;
      
                try
                {
                    iRead = readData.soc.EndReceiveFrom(ar, ref readData.endPointFrom);
                    readData.endBuf = new byte[iRead];
      
                    for (idx = 0; idx < iRead; idx++) { readData.endBuf[idx] = readData.readBuf[idx]; }
                    readData.readBuf = null;
      
                    // wieder zum einlesen vorbereiten;
                    readDataNew = new SockReadData(readData.sockRead);
                    readDataNew.soc = readData.soc;
                    readDataNew.endPointFrom = new IPEndPoint(IPAddress.Broadcast, readDataNew.sockRead._iPort);
                    readData.soc.BeginReceiveFrom(readDataNew.readBuf, 0, SockReadData.iReadBufMax, SocketFlags.None, ref readDataNew.endPointFrom, new AsyncCallback(beginRead), readDataNew);
                    readData.sockRead.Add(readData);
                }
                catch (System.Exception exc)
                {
                    strErr = exc.ToString();
                }
            }
      
            public void Add(SockReadData sockReadData)
            {
                _list.Add(sockReadData);
                //Timer zuruecksetzen
      
                if (service == "scan")
                    _recieveTimer.Change(_recTimeout, 0);
            }
      
            public void stopRec(object sender)
            {
                _stopRecieving = true;
            }
      
            public bool Send(byte[] byData)
            {
                string strErr = "";
                if (_soc == null)
                    return false;
                try
                {
                    int iRet = _soc.SendTo(byData, SocketFlags.None, new IPEndPoint(IPAddress.Broadcast, _iPort));
                }
                catch (System.Exception exc)
                {
                    strErr = exc.ToString();
                }
                return false;
            }
        }
    }

    Vielen Dank schon mal für eure zahlreichen Antworten ;o)

    Viele Grüße
    André Grimm

    Montag, 4. Juli 2011 14:12