Последние записи
- Как в Delphi XE обнулить таймер?
- Изменить цвет шрифта TextBox на форме
- Ресайз PNG без потери прозрачности
- Вывод на печать графического файла
- Взаимодействие через командную строку
- Перенести программу из Delphi в Lazarus
- Определить текущую ОС
- Автоматическая смена языка (раскладки клавиатуры)
- Сравнение языков на массивах. Часть 2
- wprintf как напечатать кириллицу
Интенсив по Python: Работа с API и фреймворками 24-26 ИЮНЯ 2022. Знаете Python, но хотите расширить свои навыки?
Slurm подготовили для вас особенный продукт! Оставить заявку по ссылке - https://slurm.club/3MeqNEk
Online-курс Java с оплатой после трудоустройства. Каждый выпускник получает предложение о работе
И зарплату на 30% выше ожидаемой, подробнее на сайте академии, ссылка - ttps://clck.ru/fCrQw
8th
Фев
Программа по отправке и принятию UDP пакетов
Posted by obzor under .NET
//для рандомного диапазона
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 == bytes_r)
{
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 включает таймер, таймер срабатывает и так по кругу. Включу устройство все опять работает, он нормально считает пакеты, принимает, но вот если во время нормального приема отключить сеть, то опять виснет как описано выше.
pu4koff
Send тоже в отдельный поток выделить или использовать асинхронные сокеты BeginSend и всё такое.
Qaliti
Пробовал оба варианта, и одновременно. Не получилось. Включил и второй поток на отправку, и использовал и 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);
static TimerCallback timeCB = new TimerCallback(MyTimerCallback);
static System.Threading.Timer MyTimer = new System.Threading.Timer(timeCB, null, Timeout.Infinite, 0);
И все заработало как и задумано ) при отключение сети таймер срабатывает
Пишу, вдруг тоже кто столкнется с такой проблемой, ну и может кто объяснит почему такое было, интересно все же.
Я в потоках не особо разбираюсь, но возможно связанный с ними трабл был. Таймер из System.Windows.Forms который был, привязывается к потоку создателя, а таймер из Threading использует свой поток. Значит можно предположить что поток создателя был занят всегда, но это не так, все было раскинуто по потокам и все функции асинхронны, ну никак ни что не могло стопать поток создателя. В этом и непонятки
Случайные статьи
Купить рекламу на сайте за 1000 руб
пишите сюда - alarforum@yandex.ru
Да и по любым другим вопросам пишите на почту
пеллетные котлы
Пеллетный котел Emtas
Наши форумы по программированию:
- Форум Web программирование (веб)
- Delphi форумы
- Форумы C (Си)
- Форум .NET Frameworks (точка нет фреймворки)
- Форум Java (джава)
- Форум низкоуровневое программирование
- Форум VBA (вба)
- Форум OpenGL
- Форум DirectX
- Форум CAD проектирование
- Форум по операционным системам
- Форум Software (Софт)
- Форум Hardware (Компьютерное железо)