Получаване и обработка на непрекъснати пакети с помощта на UDP

Това е текущата ми настройка (използвайки UDP):

void OnDataReceived(IAsyncResult result)
{

    IPEndPoint ep = new IPEndPoint(IPAddress.Any, 0);

    byte[] buffer = socket.EndReceive(result, ref ep);

    Packet p = new Packet(Encoding.ASCII.GetString(buffer, 0, buffer.Length));

    //process packet

    socket.BeginReceive(new AsyncCallback(OnDataReceived), socket);

}

Чудех се какво ще се случи, ако незабавно извикам socket.BeginReceive след извикване на EndReceive и след това обработя пакета, за да получа непрекъснат пакетен поток като този:

void OnDataReceived(IAsyncResult result)
{

    IPEndPoint ep = new IPEndPoint(IPAddress.Any, 0);

    byte[] buffer = socket.EndReceive(result, ref ep);
    socket.BeginReceive(new AsyncCallback(OnDataReceived), socket);

    Packet p = new Packet(Encoding.ASCII.GetString(buffer, 0, buffer.Length));

    //process packets

}

Ако пакет бъде получен веднага след като извикам BeginReceive, това ще противоречи ли по някакъв начин на текущата обработка на пакет?

Освен това, ако това не е в конфликт, промяната на TCP ще направи ли това нефункционално?


person Xortrox    schedule 01.12.2012    source източник


Отговори (1)


Изглежда, че създавате някакъв рекурсивен манипулатор там. Не съм сигурен как ще работи това, вероятно не по добър начин. Обикновено избирам отделна нишка за четене, която слуша входящите данни и ги предава на събитие. Това ми е служило добре в миналото. Все пак не съм разглеждал използването на async за това.

Ето примерен код за това как да използвате отделна нишка за обработка на входящи UDP данни. Не е завършен, но трябва да ви даде представа как да го настроите.

    private Thread _udpReadThread;
    private volatile bool _terminateThread;

    public event DataEventHandler OnDataReceived;
    public delegate void DataEventHandler(object sender, DataEventArgs e);

    private void CreateUdpReadThread()
    {
        _udpReadThread = new Thread(UdpReadThread) { Name = "UDP Read thread" };
        _udpReadThread.Start(new IPEndPoint(IPAddress.Any, 1234));
    }

    private void UdpReadThread(object endPoint)
    {
        var myEndPoint = (EndPoint)endPoint;
        var udpListener = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
        udpListener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);

        // Important to specify a timeout value, otherwise the socket ReceiveFrom() 
        // will block indefinitely if no packets are received and the thread will never terminate
        udpListener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 100);
        udpListener.Bind(myEndPoint);

        try
        {
            while (!_terminateThread)
            {
                try
                {
                    var buffer = new byte[1024];
                    var size = udpListener.ReceiveFrom(buffer, ref myEndPoint);
                    Array.Resize(ref buffer, size);

                    // Let any consumer(s) handle the data via an event
                    FireOnDataReceived(((IPEndPoint)(myEndPoint)).Address, buffer);
                }
                catch (SocketException socketException)
                {
                    // Handle socket errors
                }
            }
        }
        finally
        {
            // Close Socket
            udpListener.Shutdown(SocketShutdown.Both);
            udpListener.Close();
        }
    }

    public class DataEventArgs : EventArgs
    {
        public byte[] Data { get; private set; }
        public IPAddress IpAddress { get; private set; }

        public DataEventArgs(IPAddress ipaddress, byte[] data)
        {
            IpAddress = ipaddress;
            Data = data;
        }
    }
person Jakob Möllås    schedule 01.12.2012
comment
Това изглежда е валиден отговор, но не мога да го гласувам поради моята репутация 11. Подходът, който използвам в момента, е Socket.BeginReceive, който извиква функцията, обвързана в новия аргумент AsyncCallback, когато данните са получени. (Вярвам, че това позволява текущото извикване на OnDataReceived да завърши, като в същото време мога да слушам за нови данни) Основното ми притеснение вероятно е малко глупаво, но се притеснявам как работят множество извиквания към 1 от няколко нишки, когато прави се едновременно - person Xortrox; 02.12.2012
comment
Всъщност пренебрегвайки това, някак намерих решение за това: stackoverflow.com/questions/10467070/ - person Xortrox; 02.12.2012
comment
Това не причинява ли много ненужно преразпределение на паметта? Вие разпределяте своя буфер при всяко преминаване около цикъла, независимо дали се използва или не. - person Loren Pechtel; 05.09.2013
comment
Да, можете леко да оптимизирате нещата тук, като разпределяте само когато нещо е получено. - person Jakob Möllås; 07.09.2013