Анимация
JavaScript


Главная  Библионтека 

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 [ 198 ] 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242

17.3. Передача данных через TCP 611

17.3. Передача данных через TCP

Проблема

Требуется передать или принять данные по ТСР-соединению.

Решение

Следующее решение предполагает, что связь осуществляется через Интернет. ТСР-подобные коммуникации на одном компьютере рассматриваются в рецепте 17.6.

Первый вариант - print или <>:

print SERVER "What is your name>\n", chomp ($response = <SERVER>);

Второй вариант - функции send и recv:

defined (send(SERVER, $data to send, $flags)) or die "Cant send . $i\n";

recvCSERVER, $data read, $maxlen, Sflags) or die Cant receive S\n;

Третий вариант - соответствующие методы объекта IO::Socket:

use 10.:Socket;

$server->send($data to send, Sflags) or die "Cant send $i\n ,

$server->recv(Sdata read, Sflags) or die "Can t recv $! \n ,

Чтобы узнать, могут ли быть получены или приняты данные, воспользуйтесь функцией select, для которой в классе IO::Socket также предусмотрена удобная оболочка:

use 10 Select;

Sselect = 10 •Select->new();

$select->add(.FROM SERVER);

$select->add(Sto client);

(aread from = $select->can read($timeout); foreach Ssocket ((aread from) {

# Прочитать ожидающие данные из Ssocket

Комментарий

Сокеты используются в двух принципиально различных типах ввода/вывода, каждый из которых обладает своими достоинствами и недостатками. Стандартные функции ввода/вывода Perl, используемые для файлов (кроме seek и sysseek),



работают и для потоковых сокетов, однако для датаграммных сокетов необходимы системные функции send и recv, работающие с целыми записями.

При программировании сокетов очень важно помнить о буферизации. Хотя буферизация и была спроектирована для повышения быстродействия, она может повлиять на интерактивное поведение некоторых программ. Если при вводе данных с помощью о будет обнаружен разделитель записей, программа может попытаться прочитать из сокета больше данных, чем доступно в данный момент. И print и о используют буферы stdio, поэтому без включения автоматической очистки буфера (см. введение главы 7 «Доступ к файлам») для манипулятора сокета данные не отправятся на другой конец в момент их передачи функцией print. Вместо этого они будут ждать заполнения буфера

Вероятно, для клиентов и серверов с построчным обменом данных это подходит - при условии, что вы не забыли включить автоматическую очистку буфера. Новые версии IO::Socket делают это автоматически для анонимных файловых манипуляторов, возвращаемых 10 Socket->new.

Но стандартный ввод/вывод - не единственный источник буферизации Операции вывода (print, printf, syswrite - или send для сокета TCP) буферизуются на уровне операционной системы по так называемому алгоритму Нейгла. Если пакет данных отправлен, но еще не подтвержден, другие передаваемые данные ставятся в очередь и отправляются либо после набора следующего полного пакета, либо при получении подтверждения. В некоторых ситуациях (события мыши в оконных системах, нажатия клавиш в приложениях реального времени) такая буферизация оказывается неудобной или попросту неверной. Буферизация Нейгла отключается параметром сокета TCP NODELAY:

use Socket

require sys/socket ph , й Для &TCP NODELAY

setsockopt(SOCKET, SOL SOCKET &TCP NODELAY 1)

or die Couldn t disable Nagle s algorithm $\n ,

Ее повторное включение происходит так:

setsockopt(SOCKET, SOL SOCKET &TCP NODELAY, 0)

or die Couldn t enable Nagle s algorithm S\n

Как правило, TCP NODELAY все же лучше не указывать. Буферизация TCP существует не зря, поэтому не отключайте ее без крайней необходимости - например, если ваше приложение работает в режиме реального времени с крайне интенсивным обменом пакетов.

TCP NODELAY загружается из sys/socket.ph - этот файл не устанавливается автоматически вместе с Perl, но может быть легко построен. Подробности приведены в рецепте 12.14.

Буферизация чрезвычайно важна, поэтому в вашем распоряжении имеется функция select. Она определяет, какие манипуляторы содержат непрочитанный ввод, в какие манипуляторы возможна запись и для каких имеются необработанные «исключительные состояния». Функция select получает три строки, интерпретируемые как двоичные данные; каждый бит соответствует файловому манипулятору. Типичный вызов select выглядит так:



17.3. Передача данных через TCP 613

$rin = , # Инициализировать маску

vec($rin, fileno(SOCKET), 1) = 1, # Пометить SOCKET в $rin # Повторить вызовы vec() для каждого проверяемого сокета

$timeout = 10, # Подождать 10 секунд

$nfound = select($rout = $rin, undef, undef, $timeout), if (vec($rout fileno(socket) 1)){

# В SOCKET имеются данные для чтения

Функция select вызывается с четырьмя аргументами. Три из них представляют собой битовые маски: первая проверяет в манипуляторах наличие непрочитанных данных в манипуляторах; вторая - возможность безопасной записи без блокировки; третья - наличие в них исключительных состояний. Четвертый аргумент определяет максимальную длительность ожидания в секундах (может быть вещественным числом).

Функция модифицирует передаваемые ей маски, поэтому при выходе из нее биты будут установлены лишь для манипуляторов, готовых к вводу/выводу. Отсюда один стандартный прием - входная маска ($Г1П в предыдущем примере) присваивается выходной ($rout), чтобы вызов select изменил только $rout и оставил $Г1П в прежнем состоянии.

Нулевой тайм-аут определяет режим опроса (проверка без блокировки). Некоторые начинающие программисты не любят блокировки, и в их программах выполняется «занятое ожидание» (busy-wait) - программа в цикле выполняет опрос, снова и снова. Когда программа блокируется, операционная система понимает, что процесс ждет ввода, и передает процессорное время другим программам до появления входных данных. Когда программа находится в «занятом ожидании», система не оставляет ее в покое, поскольку программа всегда что-то делает - проверяет ввод! Иногда опрос действительно является правильным решением, но гораздо чаще это не так. Тайм-аут, равный undef, означает отсутствие тайм-аута, поэтому ваша программа терпеливо блокируется до появления ввода.

Поскольку select использует битовые маски, которые утомительно создавать и трудно интерпретировать, в решении используется стандартный модуль IO::Select. Он обходит работу с битовыми масками и, как правило, более удобен.

Полное объяснение исключительных состояний, проверяемых третьей маской select, выходит за рамки настоящей книги.

Другие флаги send и recv перечислены в страницах руководства этих системных функций.

[> Смотри также-

Описание функций send, recv, fileno, vec и setsockopt в perlfunc(l); разделы «I/O Operators» и «Bitwise String Operators» вperlop(l); страница руководства setsockopt{2) вашей системы (если есть); документация по стандартным модулям Socket и IO::Socket; раздел «Internet TCP Clients and Servers» perHpc(i); рецепты 17.1-17.2.



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 [ 198 ] 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242