Главная Delphi Forum Регистрация

Вход

Приветствую Вас Гость | RSSСуббота, 18.05.2024, 19:51
Меню сайта

Категории каталога
Кодинг для новичков [2]
В этом разделе описаны основы кодинга в дельфи
WinAPI и системное программирование [0]
Сети [2]
Делфи и взаимодействие с сетью
Видео и графика [0]
Базы данных [0]
Общее [1]
Все, что невошло в другие разделы

Наш опрос
Что надо менять?
Всего ответов: 11

Каталог статей
Главная » Статьи » Сети

Клиент-сервер на низком уровне. Часть I
В этой статье будут рассмотрены основные принципы создания
клиентно-серверных приложений используя ф-ции постовляемые библиотекой ws2_32.dll(WinSock).
Более опытные програмисты не найдут в этой статье ничего нового т.к статья расчитана на начинающих кодеров, но я не ставил перед собой задачу описать кажудую ф-цию детально, моей целью являлось дать основные понятия работы
с библиотекой WinSock.

Начнём с того что научимся инициализировать WinSock для дальнейшей работы с ним, а после окончания работы, его нужно финализировать.
И так, для того чтобы инициализировать библиотеку WinSock используется
ф-ция WSAStartup:

function WSAStartup ( wVersionRequested: WORD; var WSData: TWSAData ) : Integer;

Первым её аргументом является версия библиотеки которую мы хотим использовать, указовать её мы будем в зависимости от того какой версии является используемый тобой модуль WinSock.
Если это WinSock перовой версии, то ты будешь писать:
$0101

Если второй (WinSock2):
$0202

Сразу хочу оговориться что модуль WinSock2 по умолчанию не входит в состав Delphi, поэтому все примеры будут расчитаны на 1-ый WinSock.

Вторым аргументом является структура типа WSADATA(в Delphi TWSAData), в которую помещяется детальная информация о сокете.
Если инициализация прошла успешно, то ф-ция WSAStartup вернёт 0.
Пример:
var
WSAData: TWSAData;
begin
...
if WSAStartup( $0101, WSAData) 0 then ...
...
end;

Для финализации служит ф-ция WSACleanup, у этой ф-ции нет параметров.
В успешном случае она вернёт 0.
Пример:
...
begin
...
if WSACleanup 0 then ...
...
end;

Следующим шагом как правило идёт создание сокета, для этого предназначена ф-ция socket:

function Socket( af: Integer; struct: Integer; protocol: Integer ) : Integer;

Параметрами которой является конфигурация нашего будующего Сокета:

1) Установить к каком режиме будет работать наш сокет: AF_INET или PF_INET.
(в асинхронном или в синхронном)
2) Указать тип: SOCK_STREAM или SOCK_DGRAM. (TCP или UDP)
3) Протокол.(чаще всего это IPPROTO_IP).

Если при создании сокета произошла ошибка, то Сокет будет равен INVALID_SOCKET.
Пример:
var
...
Sock: TSocket;
begin
...
Sock := Socket( PF_INET, SOCK_STREAM, IPPROTO_IP );
if Sock = INVALID_SOCKET then ...
...
end;

По завершению работы с сокетом его нужно закрыть, ф-ция CloseSocket:

function CloseSocket(s: Integer) : Integer;

Единственным её аргументом явлается сокет который мы хотим закрыть. Если при закрытии
произошла ошибка, то она вернёт SOCKET_ERROR.
Пример:
var
...
Sock: TSocket;
...
begin
...
if CloseSocket(Sock) = SOCKET_ERROR then ...
...
end;

После того как сокет был создан переходим к заполнению структуры sockaddr_in,
в этой структуре храниться такая информация как:
(три основных св-ва)

1) sin_family - Тип подключения. (AF_INET или PF_INET)
2) sin_port - Порт.
3) sin_addr.S_addr - IP Адрес.

Тут надо учесть тот факт что для сервера указовать IP адрес не нужно,
поэтому если ты будешь делать сервер, то установи св-во sin_addr.S_addr в INADDR_ANY,
Пример:
...
var
Addr: sockaddr_in;
begin
...
// Для сервера:
with Addr do
begin
sin_family := PF_INET;
sin_port := htons( 12345 );
sin_addr.S_addr := INADDR_ANY;
end;

// Для клиента:
with Addr do
begin
sin_family := PF_INET;
sin_port := htons( 12345 );
sin_addr.S_addr := inet_addr( '127.0.0.1' );
end;
...
end;

Передём к рассмотрению ф-ций которые будем использовать для создания сервера:

1) function Bind(s: Integer; var addr: sockaddr_in; namelen: Integer) : Integer; (Bind перевод с англ. "связать")

Первым параметром является сокет, второй параметр струкрура sockaddr_in, третий параметр должен указать длину нашей структуры sockaddr_in.

2) function Listen(s: Integer; backlog: Integer) : Integer; (Listen перевод с англ. "слушать")

Первый параметр - сокет, второй - длина очереди соединений ждущих обработки сервера.

Обе ф-ции в случае неудачи вернут SOCKET_ERROR.

Для наглядности создай новое приложение(File->New->Application), обьяви одну глобальную переменную типа TSocket, кинь на форму 2 кнопки (TButton), по нажанию на первую кнопку мы будем запускать сервер, вторая кнопка для его остановки.
Код(Упрощёный пример, без проверок на ошибки):

uses WinSock;

var
Sock: TSocket; // глобальная переменная

procedure TForm1.Button1Click(Sender: TObject);
var
Addr: sockaddr_in;
WSAData: TWSAData;
begin
WSAStartup( $0101, WSAData );
Sock := Socket( PF_INET, SOCK_STREAM, IPPROTO_IP );

with Addr do // начинаем заполнять структуру sockaddr_in
begin
sin_family := PF_INET; // тип то же что и у сокета
sin_port := htons( 12345 ); // порт, htons обязательно !
sin_addr.S_addr := INADDR_ANY; // для сервера
end;

Bind( Sock, Addr, SizeOf( Addr ) ); // "Биндим" сокет
Listen( Sock, SOMAXCONN ); // начинаем "слушать" (открываем порт)
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
CloseSocket( Sock );
WSACleanup;
end;

С серверной частью разобрались, на очереди создание клиента.
Для установки соединения используется ф-ция Connect - по параметрам
аналогична ф-ции Bind.

uses WinSock;

var
Sock: TSocket; // глобальная переменная

procedure TForm1.Button1Click(Sender: TObject);
var
Addr: sockaddr_in;
WSAData: TWSAData;
begin
WSAStartup( $0101, WSAData );
Sock := Socket( PF_INET, SOCK_STREAM, IPPROTO_IP );

with Addr do // начинаем заполнять структуру sockaddr_in
begin
sin_family := PF_INET; // тип то же что и у сокета
sin_port := htons( 12345 ); // порт, htons обязательно !
sin_addr.S_addr := inet_addr( '127.0.0.1' ); // ip
end;

if Connect( Sock, Addr, SizeOf( Addr ) ) = SOCKET_ERROR then { пытаемся установить соединение }
Button2.Click; { если не получилось, то кликаем по 2-ой кнопке }

end;

procedure TForm1.Button2Click(Sender: TObject);
begin
CloseSocket( Sock );
WSACleanup;
end;


На этом пока всё что я хотел рассказать, в следующией статье я покажу как
надо отлавливать события(такие как OnConnect, OnRead ...etc), как получать данные и как их отправлять.
Категория: Сети | Добавил: Sneg0k (31.12.2007) | Автор: R_a_ID_e_R
Просмотров: 5557 | Рейтинг: 5.0/2 |
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Форма входа

Поиск

Друзья сайта

Copyright MyCorp © 2024Сайт управляется системой uCoz