О чём не пишут в книгах по Delphi
Шрифт:
Ориентироваться мы будем только на два протокола передачи данных — TCP и UDP. Хотя библиотека сокетов поддерживает и другие протоколы, но эти два, во-первых, применяются наиболее часто, а во-вторых, именно на них во многом ориентированы стандартные сокеты. Поэтому здесь мы не будем касаться особенностей работы функций библиотеки сокетов, которые проявляются только для протоколов, отличных от TCP и UDP. Объем информации, с которой придется познакомиться, и без того большой, а с другими протоколами легче ознакомиться потом, изучив TCP и UDP.
2.1. Стандартные сокеты
Сначала рассмотрим классические методы работы с сокетами, которые не учитывают ни существования окон и оконных сообщений, ни возможности распараллеливания работы программы на несколько нитей. Это. впрочем, не означает, что программа, использующая эти методы, должна быть безоконной и однонитевой, оконные и многонитевые программы есть среди примеров этого раздела. Просто приспосабливать стандартные сокеты к окнам и распараллеливанию приходится вручную, а не за счет средств самой библиотеки. Тем не менее из-за своей простоты стандартные сокеты нередко оказываются более удобными, чем сокеты Windows, даже в оконных приложениях.
2.1.1 Соглашения об именах
Первые библиотеки сокетов писались на языке С. В этом языке идентификаторы чувствительны к регистру символов, т.е., например,
Чувствительность С к регистру символов создаст некоторые проблемы при переноce библиотек, написанных на этом языке, в Delphi. Это связано с тем, что разные объекты могут иметь имена, различающиеся только регистром символов, в частности, есть тип
Ранее был упомянут термин "макроопределение". Он может быть непонятен тем, кто не работал с языками С и C++, потому что в Delphi макроопределения отсутствуют. Нормальная последовательность трансляции программы в Delphi следующая: сначала компилятор создает объектный код, в котором вместо реальных адресов функций, переменных и т.п. стоят ссылки на них (на этапе компиляции эти адреса еще не известны). Затем компоновщик размещает объекты в памяти и заменяет ссылки реальными адресами. Так получается готовая к исполнению программа. В С/C++ трансляция включает в себя еще один этап: перед компиляцией текст программы модифицируется препроцессором, и компилятор получает уже несколько видоизмененный текст. Макроопределения, или просто макросы, — это директивы препроцессору, предписывающие ему, как именно нужно менять текст программы. Макрос задаст подмену: везде, где в программе встречается имя макроса, препроцессор изменяет его на тот текст, который задан при определении этого макроса. Определяются макросы с помощью директивы препроцессору
В простейшем случае макросы используются для определения констант. Например, директива
Макросы позволяют в некоторых случаях существенно сократить программу и повысить ее читабельность. Тем не менее они считаются устаревшим средством. т.к. их использование может привести к существенным проблемам (обсуждение этого выходит за рамки данной книги). В современных языках от макросов отказываются. В частности, в C++ макросы поддерживаются в полном объеме, но использовать их не рекомендуется, т.к. есть более безопасные инструменты, решающие типичные для макросов задачи. В С# и Java макросы отсутствуют. Тем не менее в заголовочных файлах для системных библиотек Windows (в том числе и библиотеки сокетов) макросы широко применяются, т.к. требуется обеспечить совместимость с языком С. При портировании таких файлов в Delphi макросы без параметров заменяются константами, а макросы с параметрами — функциями (иногда один макрос приходится заменять несколькими функциями для разных типов данных).
2.1.2. Общие сведения о сокетах
Сокетом (от англ. socket — гнездо, розетка) называется специальный объект, создаваемый для отправки и получения данных через сеть. Отметим, что под термином "объект" в данном случае подразумевается не объект в терминах объектно-ориентированного программирования, а некоторая сущность, внутренняя структура которой скрыта от нас, и мы можем оперировать с ней только как с единым и неделимым (атомарным) объектом. Этот объект создается внутри библиотеки сокетов, а программист, работающий с данной библиотекой, получает уникальный номер (дескриптор) этого сокета. Конкретное значение этого дескриптора не несет для программиста никакой полезной информации и может быть использовано только для того, чтобы при вызове функции из библиотеки сокетов указать, с каким сокетом требуется выполнить операцию. В этом смысле тип
Чтобы две программы могли общаться друг с другом через сеть, каждая из них должна создать сокет. Каждый сокет обладает двумя основными характеристиками: протоколом и адресом, к которым он привязан. Протокол задается при создании сокета и не может быть изменен впоследствии. Адрес сокета задаётся позже, но обязательно до того, как через сокет пойдут данные. В некоторых случаях привязка сокета к адресу может быть неявной.
Формат адреса сокета определяется конкретным протоколом. В частности, для протоколов TCP и UDP адрес состоит из IP-адреса сетевого интерфейса и номера порта.
Каждый сокет имеет два буфера: для входящих и для исходящих данных. При отправке данных они сначала помещаются в буфер исходящих, и лишь затем отправляются в фоновом режиме. Программа в это время продолжает свою работу. При получении данных сокет помещает их в буфер для входящих, откуда они затем могут извлекаться программой.
Сеть может связывать разные аппаратные платформы, поэтому требуется согласование форматов передаваемых данных, в частности форматов целых чисел. Двухбайтные целые числа хранятся в памяти в двух последовательно расположенных байтах. При этом возможны два варианта: в первом байте хранится младший байт числа, а во втором — старший, и наоборот. Способ хранения определяется аппаратной частью платформы. Процессоры Intel используют первый вариант, т.е. первым хранится младший байт, а другие процессоры (например, Motorola) — второй вариант. То же касается и четырёхбайтных чисел: процессоры Intel хранят их, начиная с младшего байта, а некоторые другие процессоры — начиная со старшего. Сетевой формат представления таких чисел совпадает с форматом процессора Motorola, т.е. на платформах с процессором Intel необходимо переставлять байты при преобразовании чисел в сетевой формат.
Библиотека сокетов разрабатывалась для ОС Unix в которой традиционно высоко ценилась переносимость между платформами, поэтому она содержит функции, позволяющие не задумываться о порядке байтов в числах: