Приём данных в режиме TCP
Мы уже объясняли, что буферы RX и TX работают по-разному в режимах TCP и UDP. В этом разделе рассказано, как принимать данные, когда сокет использует протокол TCP.
В типичной системе постоянно нужно обрабатывать входящий поток данных. Простой подход - опрос. Вы в цикле опрашиваете буфер, проверяя, нет ли в нём свежих данных, и когда они появляются, что-то с ними делаете. Выглядит это так:
sub on_sys_init
while sock.rxlen = 0
wend ' basically keeps executing again and again as long as sock.rxlen = 0
s = sock.getdata(255) ' once loop is exited, it means data has arrived. We extract it.
end sub
Так работать можно, но программа навсегда застрянет в одном обработчике события (например, on_sys_init), а другие события не получат шанса выполниться. Это пример блокирующего кода, из-за которого система может зависнуть. Конечно, можно использовать оператор doevents, но в целом блокирующего подхода советуем избегать.
Поскольку наша платформа событийно-ориентированная, о появлении новых данных должны сообщать события. Есть событие on_sock_data_arrival, которое генерируется всякий раз, когда в буфере RX есть данные:
sub on_sock_data_arrival
dim s as string
s = sock.getdata(255) ' Extract the data -- but in a non-blocking way.
' .... code to process data ....
end sub
Событие on_sock_data_arrival генерируется, когда в буфере RX есть данные, но только один раз. В очереди никогда не бывает двух событий on_sock_data_arrival (для одного и того же сокета). Следующее событие генерируется только после завершения обработки предыдущего, если к тому времени в буфере RX есть данные.
Это значит, что при обработке этого события вовсе не обязательно забирать все данные из буфера RX. Можно обработать часть данных, и после выхода из обработчика будет сгенерировано новое событие того же типа.
Вот правильный пример обработки поступающих данных сокета через событие on_sock_data_arrival. Этот пример реализует возврат данных (loopback): всё, что принял сокет, тут же отправляется обратно.
sub on_sock_data_arrival
sock.setdata(sock.getdata(sock.txfree))
s = sock.send
end sub
Этот loopback нужно сделать как можно эффективнее, но при этом нельзя переполнить буфер TX. Поэтому нельзя просто копировать все поступающие данные из буфера RX в буфер TX: надо проверить, сколько свободного места в буфере TX. Именно это делает первая строка кода: sock.getdata берёт из буфера RX столько данных, сколько возможно, но не больше sock.txfree (свободного места в буфере TX). Вторая строка просто отправляет данные.
На самом деле за один проход этот вызов обработает не более 255 байт. Хотя данные как будто копируются напрямую из буфера RX в буфер TX, на деле это происходит через временную строковую переменную, которая создаётся автоматически. В этой платформе строковые переменные не могут превышать 255 байт.