Чтение онлайн

ЖАНРЫ

О чём не пишут в книгах по Delphi

Григорьев Антон Борисович

Шрифт:

Но самое неудобное то, что пакеты не только склеиваются, но и разбиваются на части. Принимающая сторона может получить пакет меньшего размера, чем отправленный, если этот пакет был послан по частям, и на момент его чтения принимающей стороной еще не все части были получены. Тогда приходится повторять операцию чтения данных, пока не будет получено все, что нужно.

В отличие от UDP, в TCP данные, которые программа отправляет одной командой, могут разбиваться на части и отправляться несколькими IP-пакетами. Поэтому ограничение на длину данных, отправляемых за один раз, в TCP отсутствует (точнее, определяется доступными ресурсами системы). Количество данных, получаемое отправителем за одну операцию чтения, ограничено размером низкоуровневого буфера сокета и может быть разным в различных реализациях. Следует иметь в виду,

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

2.1.7. Сетевые экраны

Сеть не только позволяет пересылать полезные данные, но и может служить путем проникновения вредоносных программ, несанкционированного доступа к данным и т.п. С этим, естественно, борются, и один из способов борьбы — сетевые экраны (они же брандмауэры, иди firewalls). Мы здесь не будем детально знакомиться с ними, но затронем эту тему, потому что сетевые экраны могут повлиять на работоспособность наших примеров. Сетевые экраны бывают аппаратными и программными. Их общий принцип действия заключается в проверке пакетов, идущих по сети, и блокировании тех из них, которые не удовлетворяют заданным критериям. Критерии могут быть различными и зависят от настройки конкретного сетевого экрана. Все пакеты делятся на входящие и исходящие. Для входящих UDP-сообщений обычно оставляют открытыми некоторые порты, а все сообщения, присланные на другие порты, отсекаются. Для исходящих сообщений тоже может быть задан набор портов, но обычно сетевые экраны осуществляют проверку по-другому: у них есть список приложений, которым разрешено отправлять исходящие UDP-сообщения, а пакеты, отправляемые другими приложениями, сетевой экран не пропускает.

Для протокола TCP настройки обычно задаются на уровне соединения, а не отдельного пакета. Составляется список портов, открытых для внешнего подключения. Если сервер использует порт не из этого набора, клиент не сможет к нему подключиться. Для исходящих подключений тоже составляется список программ, которым разрешено это к делать, и, если клиент, отсутствующий в "белом" списке сетевого экрана, пытается подключиться к удаленному серверу, сетевой экран не допускает этого.

Примечание

Здесь описаны наиболее типичные способы локальной фильтрации пакетов сетевым экраном. В каждом конкретном случае могут применяться другие правила.

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

2.1.8. Создание сокета

До сих пор мы обсуждали только теоретические аспекты работы с сокетами. Далее будут рассматриваться конкретные функции, позволяющие осуществлять те или иные операции с сокетами. Эти функции экспортируются системной библиотекой wsock32.dll (а также библиотекой ws2_32.dll; взаимоотношение этих библиотек будет обсуждаться во втором разделе данной главы), для их использования в Delphi в раздел uses нужно добавить стандартный модуль

WinSock
. Полное формальное описание функций этого модуля здесь приводиться не будет (для этого есть MSDN), но для каждой функции будет дано описание, достаточно полное для понимания ее предназначения. Кроме того, мы будем также обращать внимание на некоторые моменты, которые в MSDN найти трудно. Тем не менее после знакомства с этим текстом настоятельно рекомендуется самостоятельно прочитать в MSDN описания всех упомянутых в нем функций.

Хотя ранее мы договорились, что будем обсуждать только стандартные сокеты, тем не менее, есть три функции, относящиеся к сокетам Windows, не познакомившись с которыми мы не сможем двигаться

дальше. Это функции
WSAStartup
,
WSACleanup
и
WSAGetLastError
(префикс WSA означает Windows Sockets API и служит для именования большинства функций, относящихся к Windows-расширению библиотеки сокетов).

Функция

WSAStartup
предназначена для инициализации библиотеки сокетов. Эту функцию необходимо вызвать до вызова любой другой функции из этой библиотеки. Ее прототип имеет вид:

function WSAStartup(wVersionRequired: Word; var WSData: TWSAData): Integer;

Параметр

wVersionRequired
задает требуемую версию библиотеки сокетов. Младший байт задает основную версию, старший — дополнительную. Допустимы версии 1.0 ($0001), 1.1 ($0101), 2.0 ($0002) и 2.2 ($0202). Пока мы работаем со стандартными сокетами, принципиальной разницы между этими версиями нет, но версии 2.0 и выше пока лучше не использовать, т.к. модуль
WinSock
не рассчитан на их поддержку. Вопросы взаимоотношения библиотек и версий будут рассматриваться во втором разделе этой главы, а пока ограничимся версией 1.1.

Параметр

WSData
выходной, т.е. значение, которое имела переменная до вызова функции, игнорируется, а имеет смысл только то значение, которое эта переменная получит после вызова функции. Через этот параметр передается дополнительная информация о библиотеке сокетов. В большинстве случаев эти сведения не представляют никакого интереса, поэтому их можно игнорировать. 

Нулевое значение, возвращаемое функцией, говорит об успешном завершении, в противном случае возвращается код ошибки. Обычно функция, завершившаяся с ошибкой, возвращает значение

SOCKET_ERROR
.

Функция

WSACleanup
завершает работу с библиотекой сокетов. Эта функция не имеет параметров и возвращает ноль в случае успешного завершения или код ошибки в противном случае. Функцию
WSAStartup
достаточно вызвать один раз, даже в многонитевом приложении, в этом ее отличие от таких функций, как, например,
CoInitialize
, которая должна быть вызвана в каждой нити, использующей COM. Функцию можно вызывать повторно — в этом случае ее вызов не дает никакого эффекта, но для завершения работы с библиотекой сокетов функция
WSACleanup
должна быть вызвана столько же раз, сколько была вызвана
WSAStartup
.

Большинство функций библиотеки сокетов возвращают значение, позволяющее судить только об успешном или неуспешном завершении операции, но не дающее информации о том, какая именно ошибка произошла (если она произошла). Для получения сведений об ошибке служит функция

WSAGetLastError
, не имеющая параметров и возвращающая целочисленный код последней ошибки, произошедшей в библиотеке сокетов в данной нити. После неудачного завершения функции из библиотеки сокетов следует вызывать функцию
WSAGetLastError
, чтобы выяснить причину неудачи.

Забегая чуть вперед, отметим, что библиотека сокетов содержит стандартную функцию

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

Для создания сокета предусмотрена стандартная функция

socket
со следующим прототипом:

function socket(af, struct, protocol: Integer): TSocket;

Параметр

аf
задаёт семейство адресов (address family). Этот параметр определяет, какой способ адресации (т.е. по сути дела, какой стек протоколов) будет использоваться для данного сокета. Для TCP/IP этот параметр должен быть равен
AF_INET
, для других стеков также есть соответствующие константы, которые можно посмотреть в файле WinSock.pas.

Поделиться с друзьями: