Исходник на языке C#, для тестирования и изучения протокола UDP. В отличие от первой части в данной приложении получатель и отправитель в одном пакете. Тестовое приложение рассчитано на передачу сообщений по локальной сети. Для взаимодействия двух программ на одном компьютере необходимо изменить SendPort у одной на 15001 и ReceivePort у другой на 15001; либо ip хост-адрес одной на 127.0.0.2 и удаленный ip адрес на 127.0.0.2 у другой. Только в этом случае программы, работающие по UDP, смогут общаться на локальной машине.
Это связано с тем, что невозможно запустить две прослушивающие (извлекающие сообщения) программы с одинаковыми ip адресами и одинаковыми портами. На разных машинах программы будут работать нормально, и отсылать, получать сообщения без проблем. Протокол UDP позволяет работать по сети без установки соединения, что и демонстрируют тестовые программы.
Работа сетевого протокола без установления соединений и без проверки отсылаемых и входных данных дают существенный выигрыш в скорости. Хотя использованы блокирующие методы, но при работе их в отдельном потоке, интерфейс приложения не блокируется.
void Send()
{
// Для создания объекта класса UdpClient используем
// конструктор по умолчанию
UdpClient udp = new UdpClient();
// Преобразуем строку сообщения в
// массив байтов для отправки по локальной сети
byte[] message = Encoding.Default.GetBytes(textBoxSend.Text);
// Указываем объекту реквизиты удаленной точки
// и отправляем сообщение, удаленный ip адрес
// можно изменять в текстовом боксе.
IPEndPoint ep = new IPEndPoint
(IPAddress.Parse(textBoxRemote.Text), 15000);
udp.Send(message, message.Length, ep);
// Закрываем UDP соединение
udp.Close();
}
void StartReceive()
{
// Чтобы основной поток приложения не заблокировался,
// для извлечения сообщений запускаем дополнительный поток.
ThreadStart tstart = new ThreadStart(Receive);
workReceive = new Thread(tstart);
workReceive.Start();
}
// Необходимым объектам и переменным обеспечиваем
// видимость на уровне класса. Это даст нам возможность
// принудительной остановки дополнительного потока
bool stopReceive = false;
Thread workReceive = null;
UdpClient udp = null;
// Функция запускаемая из дополнительного потока
// для цикличного процесса извлечения сообщений
void Receive()
{
try
{
IPEndPoint ep = new IPEndPoint(IPAddress.Parse(textBoxHostAddress.Text), 15000);
udp = new UdpClient(ep);
while (true)
{
IPEndPoint remote = null;
byte[] message = udp.Receive(ref remote);
ShowMessage(Encoding.Default.GetString(message) );
if (stopReceive == true) break;
}
}
catch(Exception e)
{
// В данном месте исходного кода можно
// отслеживать возникающие исключения
//MessageBox.Show(e.Message);
}
finally
{
if (udp != null) udp.Close();
}
}
// Специальный код доступа к свойствам объектов из других потоков.
// Рассматривать данный код будем в других исходниках
delegate void SetTextCallback(string message);
void ShowMessage(string message)
{
if (this.textBoxReceive.InvokeRequired)
{
SetTextCallback dt = new SetTextCallback(ShowMessage);
this.Invoke(dt, new object[] { message });
}
else
{
this.textBoxReceive.Text = message;
}
}
// Безопасный останов дополнительного потока
void StopReceive()
{
// Останавливаем цикл приема сообщений
stopReceive = true;
if (udp != null) udp.Close();
// Для правильного, последовательного завершения
// дополнительного потока подключаем его к основному потоку.
if (workReceive != null) workReceive.Join();
}
// Перед закрытием формы остановим дополнительный поток
void FormClosing()
{
StopReceive();
}