Отправка данных TCP и UDP

В предыдущих разделах мы объясняли, как обрабатывать входящий поток данных. Можно сказать, что работа шла по входящим данным. Иногда нужно прямо противоположное - выполнять операции в зависимости от отправки данных.

Отправка данных с помощью события on_sock_data_sent

Допустим, в некоторой системе при нажатии кнопки нужно отправить длинную строку данных. Простой код для этого выглядел бы так:

sub on_button_pressed
	sock.setdata("This is a long string waiting to be sent. Send me already!")
	sock.send
end sub

Этот код будет работать, но только если в момент его выполнения в буфере TX достаточно свободного места (иначе данные будут усечены). Поэтому перед отправкой нужно убедиться, что в буфере TX есть необходимый объём свободного места. Простое решение с опросом выглядело бы так:

sub on_button_pressed
	dim s as string
	s = "This is a long string waiting to be sent. Send me already!"
	while sock.txfree < len(s)
	wend
	sock.setdata(s)
	sock.send
end sub

И это снова не очень хорошо, поскольку блокируются другие обработчики событий. Поэтому вместо такого подхода мы используем код с событием on_sock_data_sent:

dim s as string
s = "This is a long string waiting to be sent. Send me already!"
sub on_button_pressed
	sock.notifysent(sock.txbuffsize-len(s)) ' causes the on_sock_data_sent event to fire when the TX buffer has space for our string
end sub
sub on_sock_data_sent
	sock.setdata(s)  ' put data in TX buffer
	sock.send  ' start sending it.
end sub

При нажатии кнопки генерируется событие on_button_pressed, и система узнаёт, что нужно отправить строку. С помощью sock.notifysent мы заставляем систему сгенерировать событие on_sock_data_sent, когда освободится необходимый объём места. Это событие сработает только один раз - и сработает сразу же, если места уже достаточно.

В обработчике этого события мы помещаем данные в буфер TX и запускаем отправку.

Внимание

Объём данных, при котором срабатывает on_sock_data_sent, не включает незафиксированные данные в буфере TX.

Датаграммы UDP формируются по мере их создания

В разделе Использование буферов в режиме UDP мы объясняли, что в UDP вы полностью контролируете, как отправляемые данные делятся на датаграммы UDP. Каждый вызов метода sock.send проводит границу между датаграммами: предыдущая «закрывается», а новая «начинается». Можно даже отправить пустую датаграмму UDP, выполнив sock.send без предварительного sock.setdata.

Правильный ответ отправителю каждой датаграммы UDP

В UDP ваш сокет может принимать датаграммы от нескольких разных хостов. При входе в обработчик события on_sock_data_arrival (см. Приём данных в режиме UDP) следующие свойства автоматически отражают источник текущей датаграммы: sock.remotemac, sock.remoteip и sock.remoteport. Кроме того, свойство sock.bcast показывает, была ли датаграмма обычной или широковещательной (этот материал уже рассматривался в разделе Проверка состояния соединения).

Кроме того, любая датаграмма, созданная и отправленная из обработчика события on_sock_data_arrival, отправляется отправителю той датаграммы, из-за которой был вызван этот обработчик.

Суть в том, что, отправляя датаграмму из обработчика события on_sock_data_arrival, вы автоматически отвечаете отправителю обрабатываемой датаграммы. Следующий пример в ответ на любую датаграмму, принятую сокетом, отправляет обратно строку «GOT DATAGRAM FROM xxx.xxx.xxx.xxx»:

sub on_sock_data_arrival
	sock.setdata("GOT DATAGRAM FROM " + sock.remoteip)
	sock.send
end sub

В этом примере даже если несколько хостов одновременно отправят датаграммы на сокет, каждый из них получит правильный ответ!

А теперь другой пример: при каждом нажатии кнопки формируется одно и то же сообщение.

sub on_button_pressed
	sock.setdata("GOT DATAGRAM FROM " + sock.remoteip)
	sock.send
end sub

Разница в том, что при нажатии кнопки датаграмма будет отправлена отправителю самой последней входящей датаграммы UDP, которую сокет принял (и одобрил)!

Исходный материал Tibbo обновлён 11 августа 2022Оригинал на docs.tibbo.com · Сообщить об ошибке