Анимация
JavaScript
|
Главная Библионтека существующих программ). Используйте символические имена вместо числовых значений, поскольку последние могут измениться (что неод1юкратно происходило). Имена протоколов (например, tcp и udp) тоже соответствуют числам, используемым операционной системой. Встроенная функция Perl getprotobyname возвращает номер по имени протокола. Если функциям сокетов передается значение О, система выберет подходящий протокол по умолчанию. Perl содержит встроенные функции для создания сокетов и управления ими; они в основном дублируют свои прототипы на С. Хотя это удобно для получения низкоуровневого, прямого доступа к системе, большинство предпочитает работать с более удобными средствами. На помощь приходят классы IO::Socket::INET и IO::Socket::UNIX - они обеспечивают высокоуровневый интерфейс к низкоуровневым системным функциям. Начнем с рассмотрения встроенных функций. В случае ошибки все они возвращают undef и присваивают $i соответствующее значение. Функция socket создает сокет, bind - назначает ему локальное имя, connect - подключает локальный сокет к другому (возможно, удаленному). Функция listen готовит сокет к подключениям со стороны других сокетов, а accept последовательно принимает подключения. При обмене данными с потоковыми сокетами можно использовать как print и о, так и syswrite и sysread, а при обмене с датаграммными сокетами - send и recv. Типичный сервер вызывает socket, bind и listen, после чего в цикле вызывает accept в блокирующем режиме, ожидая входящих подключений (см. рецепты 17.2 и 17.5). Типичный клиент вызывает socket и connect (см. рецепты 17.1 и 17.4). Да-таграммные клиенты ведут себя особым образом. Они не обязаны вызывать connect для передачи данных, поскольку могут указать место назначения в качестве аргумента send. При вызове bind, connect или send для конкретного приемника необходимо указать имя сокета. Имя сокета Интернета состоит из хоста (IP-адрес, упакованный функцией inet aton) и порта (числа), объединенных в С-подобную структуру функцией sockaddr in: use Socket; $packed ip = inet aton(208.146 240 Г); $socket name = sockaddr in($port, $packed ip); Имя сокета UNIX представляет собой имя файла, упакованное в структуру С функцией sockaddr un: use Socket, $socket nanie = sockaddr un("/tmp/mysock). Чтобы преобразовать упакованное имя сокета и снова получить имя файла или пару «хост/порт», вызовите sockaddr un или sockaddr in в списковом контексте: (Sport, $packed ip) = sockaddr in($socket name): # Для сокетов PF INET (Sfilename) = sockaddr un($socket name); # Для сокетов PF UNIX Функция inet ntoa преобразует упакованный IP-адрес в ASCII-строку. $ip address = inet ntoa($packed ip); $packed ip = inet aton("гОД.148.40. 9"): $packed ip = inet aton("www.oreilly.com"); В большинстве рецептов используются сокеты Интернета, однако практически все сказанное в равной мере относится и к сокетам UNIX. В рецепте 17.6 объясняются отличия и возможные расхождения. Сокеты являются основой для работы сетевых серверов. Мы рассмотрим три варианта построения серверов: в первом для каждого входящего подключения создается порожденный процесс (рецепт 17,11), во втором сервер создает порожденные процессы заранее (рецепт 17.12), а в третьем процесс-сервер вообще не создает порожденные процессы (рецепт 17.13). Некоторые серверы должны одновременно вести прослушивание по многим IP-адресам (см. рецепт 17.14). Хорошо написанный сервер деинициализируется и перезапускается при получении сигнала HUP; в рецепте 17.16 показано, как реализовать такое поведение в Perl. Кроме того, вы узнаете, как идентифицировать оба конца соединения (см. рецепты 17.7 и 17.8). 17.1. Написание клиента TCP Проблема Вы хотите подключиться к сокету па удаленном компьютере. Решение Следующее решение предполагает, что связь осуществляется через Интернет. ТСР-нодобные коммуникации на одгюм компьютере рассматриваются в рецепте 17.6. Либо воспользуйтесь стандартным (для версии 5.004) классом IO:;Socket;:INET: use 10:;Socket; Ssocket = 10::Socket::INET->new(PeerAddr => Sremote host, PeerPort => $remote port, Proto => "tcp", Type => S0CK STREAM) or die "Couldnt connect to Sremote host:$remote port : S@\n", # .. . Сделать что-то с сокетом print Ssocket "Why dont you call me anymore\n"; Sanswer = <Ssocket>; # Отключиться после завершения close($socket); либо создайте сокет вручную, чтобы лучше управлять его поведением: use Socket; # Создать сокет 17.1. Написание клиента TCP 607 socket(SERVER, PF INET, SOCK STREAM, getprotobyname(tcp)): # Построить адрес удаленного компьютера $internet addr = inet aton($remote host) or die "Couldnt convert $remote host into an Internet address; $\n"; Spaddr = sockaddr in($remote port, $internet addr); # Подключиться connect(TO SERVER, Spaddr) or die "Couldnt connect to $reniote host;$remote port ; $i\n", # ... Сделать что-то с сокетом print TO SERVER "Why dont you call me anymoreXn"; # И отключиться после завершения close(TO SERVER); Комментарий Ручное кодирование состоит из множества действий, а класс IO::Socket::INET объединяет их все в удобном конструкторе. Главное, что необходимо знать, - куда вы направляетесь (параметры PeerAddr и PeerPort) и каким образом (параметр Туре). По переданной информации IO::Socket::INET пытается узнать все остальное. Так, протокол по возможности вычисляется но тину и номеру порта; если это не удается сделать, предполагается протокол tcp. Параметр PeerAddr содержит строку с именем хоста ("www. oreiUy. com) или его IP-адресом ("204.148.40.9"). PeerPort - целое число, номер порта для подключения. Номер порта можно включить в адрес в виде "www. oreilly. com; 80". Параметр Type определяет тип создаваемого сокета: SOCK DGRAM для датаграммного сокета или SOCK STREAM для потокового. Чтобы подключиться через SOCK STREAM к порту конкретного компьютера, не поддерживающего других возможностей, передайте 10::Socket: :INET->new одну строку с именем хоста и портом, разделенными двоеточием: Sclient = 10; ;Socket;;INET->new("www.yahoo.com:80") or die $@; При возникновении ощибки IO::Socket::INET возвращает undef, a переменной $§ (не $!) присваивается сообщение об ошибке. $s = 10:;Socket:;INET->new(PeerAddr => "Does not Exist", Peerport => 80, Type => SOCK STREAM ) or die $@; Если ваши пакеты бесследно исчезают в глубинах сети, вероятно, невозможность подключения к порту будет обнаружена лишь через некоторое время. Вы можете уменьшить этот промежуток, передавая параметр Timeout при вызове 10;;Socket;;INET->new(): $s = 10;;Socket;;INET->new(PeerAddr => "bad.host.com", PeerPort => 80, 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 |