Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > .NET Frameworks (точка нет фреймворки) > C# (си шарп)
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 19.01.2018, 17:02   #1
Qaliti
Форумчанин
 
Регистрация: 04.01.2010
Сообщений: 229
Смущение Отправка и принятие UDP пакетов

Добрый день. Суть программы: она отправляет udp пакет (каждый раз случайная длина пакета в определенном диапазоне, и случайное заполнение) на устройство, это устройства пересылает точно такой же пакет назад на комп, естественно поменяв маки местами и ip, ну и подправив порт, и поставив чек сумму в udp части в 0. Задача программы на C# считать количество принятых пакетов без ошибок (то есть рандомное заполнение осталось такое же), количество с ошибками, и количество потерянных пакетов. По сути тестирование.



Код:
        //для рандомного диапазона
        Int32 min;
        Int32 max;
        Int32 size_rnd;
        Random rnd = new Random();
        //хранение массива байт отправляемого и принимаемого пакета, для сравнения
        byte[] bytes_s = new byte[1200]; // s - for send
        byte[] bytes_r = new byte[1200]; // r - for Receiver

        //хранит значения отправленых, принятых без ошибок, потеряных, и принятых с ошибками
        Int64 sent_count = 0;
        Int64 get_count = 0;
        Int64 lost_count = 0;
        Int64 error_count = 0;

        Int64 test = 0;
        //флаг что идет передача (нужен что бы останавливать процесс)
        bool transfer = false;

        //для приема
        UdpClient receivingUdpClient = new UdpClient(Convert.ToInt32("50000"));
        IPEndPoint RemoteIpEndPoint = null;
        //для передачи
        UdpClient eth_csr = new UdpClient();
        IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("192.168.0.1"), Convert.ToInt32("50000"));


        //start
        private void button1_Click(object sender, EventArgs e)
        {  //сначала идет ресет
            sent.Text = "0";
            get.Text = "0";
            lost.Text = "0";
            error.Text = "0";
            sent_count = 0;
            get_count = 0;
            lost_count = 0;
            error_count = 0;
            //небольшая проверка адекватности диапазона
            if (Convert.ToInt32(max_size.Text) < 1) max_size.Text = Convert.ToString(Convert.ToInt64(max_size.Text)*(-1));
            if (Convert.ToInt32(max_size.Text) > 1200) max_size.Text = "1200";
            if (Convert.ToInt32(min_size.Text) > Convert.ToInt32(max_size.Text)) min_size.Text = max_size.Text;
            if (Convert.ToInt32(min_size.Text) < 1) min_size.Text = "1";
            
            //определяем диапазон
            max = Convert.ToInt32(max_size.Text);
            min = Convert.ToInt32(min_size.Text);
            timer2.Enabled = true; //включаем таймер статистики
            transfer = true;
            Send(); // вызов отправки тестового пакета
        }

        //send UDP packet
        private void Send()
        {
            if (transfer)
            {   //диапазон и заполнение рандомом массива
                size_rnd = rnd.Next(min, max);
                rnd.NextBytes(bytes_s);

                eth_csr.Send(bytes_s, size_rnd, endPoint);//послали

                timer1.Enabled = true;//включили таймер ожидания пакета
            }
            
        }

        //другой поток, т.к. прием вешает программу если пакет потерялся
        private void Receiver()
        {
            while (true)
            {
                
                bytes_r = receivingUdpClient.Receive(ref RemoteIpEndPoint); //приняли
                //проверили правильный ли он
                for (int i = 0; i < size_rnd; i++)
                {
                    if (bytes_s[i] == bytes_r[i])
                    {
                        if (i == (size_rnd - 1))
                        {
                            //good, end
                            sent_count++;
                            get_count++;
                        }
                    } else
                    {
                        //error
                        sent_count++;
                        error_count++;
                        break;
                    }
                }
                //отключили таймер ожидания пакета, и вызвали отправку следующего
                timer1.Enabled = false;
                Send();
            }
        }

        //кнопка остановки процесса
        private void button2_Click(object sender, EventArgs e)
        {
            transfer = false;
            timer2.Enabled = false;
        }

        //timer for error
        private void timer1_Tick(object sender, EventArgs e)
        {   //если время пришло и ресивер нам его не отключил, то пакет потерялся 
            test++;
            timer1.Enabled = false;
            sent_count++;
            lost_count++;
            //вызываем отправку тестового пакета
            Send();
        }

        private void timer2_Tick(object sender, EventArgs e)
        {//обновление статистики
            sent.Text = Convert.ToString(sent_count);
            get.Text = Convert.ToString(get_count);
            lost.Text = Convert.ToString(lost_count);
            error.Text = Convert.ToString(error_count);
            label4.Text = Convert.ToString(test);//для отладки
        }

        public Form1()
        {
            InitializeComponent();
            //запуск потока для ресивера
            Thread tRec = new Thread(new ThreadStart(Receiver));
            tRec.Start();
            
            
        }
Собственно все работает если все хорошо. Если отключить сеть в процессе тестов, то все повиснет, и не отвиснет даже если включить. По идее когда сеть отключается,или пакет теряется, то срабатывает таймер1, он пишет в статистику потерю, и вызывает следующую отправку пакета, пакет отправляется, таймер1 включается, проходит время, он срабатывает и так до бесконечности пока не включим сеть. Что на самом дела: после отключения сети таймер1 включен всегда, значения статистики не изменяются, функция send() не вызывает. Он включен но словно не срабатывает. Так и висим. Таймер статистики кстати всегда работает и все гуд с ним.
Тут в коде я повесил тестовую переменную на таймер1, и типо когда он сработает переменная увеличится. И выведется в тестовое поле, с помощью таймера статистики. Так вот, эта переменная test всегда в нуле при этой ситуации, но при это в другое поле я выводил состояние таймера - и он включен.

И еще один важный момент. Если включить программу при отключенном устройстве, и запустить тест, то все работает ) то есть таймер1 срабатывает, вызывает send(), send включает таймер, таймер срабатывает и так по кругу. Включу устройство все опять работает, он нормально считает пакеты, принимает, но вот если во время нормального приема отключить сеть, то опять виснет как описано выше. Что за хрень я не пойму..

Помогите люди добрые ))

------------------------------------------

Дополнение: Сеть и комп находятся в общей сети, и от сети отключаю устройство, комп остается в сети.

Последний раз редактировалось Qaliti; 19.01.2018 в 17:17.
Qaliti вне форума Ответить с цитированием
Старый 22.01.2018, 17:30   #2
Qaliti
Форумчанин
 
Регистрация: 04.01.2010
Сообщений: 229
По умолчанию

ап.. все еще не удалось решить проблему
Qaliti вне форума Ответить с цитированием
Старый 22.01.2018, 18:49   #3
pu4koff
Старожил
 
Аватар для pu4koff
 
Регистрация: 22.05.2007
Сообщений: 9,520
По умолчанию

Send тоже в отдельный поток выделить или использовать асинхронные сокеты BeginSend и всё такое.
pu4koff вне форума Ответить с цитированием
Старый 23.01.2018, 16:43   #4
Qaliti
Форумчанин
 
Регистрация: 04.01.2010
Сообщений: 229
По умолчанию

Пробовал оба варианта, и одновременно. Не получилось. Включил и второй поток на отправку, и использовал и BeginSend, и SendAsync с async/await, и прием сменил на асинхронный BeginRecive. И нефига, все равно глюк с тем что таймер был включен но тик не вызывался по истечению времени. Подумал куда уже тут поточнее, ну вот никак мешать срабатыванию таймера ничего не может. И стал копать под таймер.

Взял таймер из класса Threading.
Код:
        static void MyTimerCallback(object state)
        {
            MyTimer.Change(Timeout.Infinite, 0);
            test++;
            sent_count++;
            lost_count++;
            Send();
        }

        static TimerCallback timeCB = new TimerCallback(MyTimerCallback);
        static System.Threading.Timer MyTimer = new System.Threading.Timer(timeCB, null, Timeout.Infinite, 0);
И все заработало как и задумано ) при отключение сети таймер срабатывает
Пишу, вдруг тоже кто столкнется с такой проблемой, ну и может кто объяснит почему такое было, интересно все же.
Я в потоках не особо разбираюсь, но возможно связанный с ними трабл был. Таймер из System.Windows.Forms который был, привязывается к потоку создателя, а таймер из Threading использует свой поток. Значит можно предположить что поток создателя был занят всегда, но это не так, все было раскинуто по потокам и все функции асинхронны, ну никак ни что не могло стопать поток создателя. В этом и непонятки
Qaliti вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Scapy отправка Http и UDP пакетов shaman1 Помощь студентам 3 24.04.2013 14:19
Просмотр UDP пакетов и повторная отправка grafgrial Работа с сетью в Delphi 9 25.07.2012 17:24
отправка/принятие данных с порта. romank26 Win Api 1 26.03.2012 12:51
перехват TCP и UDP пакетов prog.delphin Работа с сетью в Delphi 4 31.03.2010 13:21
Отправка/Принятие почты через потоки... Vol666 Работа с сетью в Delphi 0 13.09.2009 15:22