В этой статье будут рассмотрены основные принципы создания
клиентно-серверных приложений используя ф-ции постовляемые библиотекой 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:
Параметрами которой является конфигурация нашего будующего Сокета:
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;
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
Добавлять комментарии могут только зарегистрированные пользователи. [ Регистрация | Вход ]