скрыть

скрыть

  Форум  

Delphi FAQ - Часто задаваемые вопросы

| Базы данных | Графика и Игры | Интернет и Сети | Компоненты и Классы | Мультимедиа |
| ОС и Железо | Программа и Интерфейс | Рабочий стол | Синтаксис | Технологии | Файловая система |



Google  
 

Работа с Winsock на Delphi



Паук подает в суд на World WideWeb: за нарушение копирайта. Впрочем, он будет вполне удовлетворен, если ему в качестве компенсации будут отдавать мух, которых сгоняют с мониторов курсором мыши.

Наверное, все, кто хотя бы немного работал с Delphi, сталкивались с компонентами закладки Internet, а именно с TServerSocket и TClientSocket. Эти два невизуальных компонента очень просты в использовании и вполне пригодны для выполнения стандартных задач. Но что делать, если мы хотим написать приложение малого размера или нам необходим больший контроль над сокетом, чем дают стандартные компоненты? В этом случае необходимо использовать средство Windows для работы с сокетами, чем и является библиотека winsock.dll.

Заголовки всех процедур и функций, находящихся в этой dll-ке можно найти в Delphi5\source\rtl\win\winsock.pas.

Я кратко опишу те из них, который понадобятся для понимания нижеприведенного исходника:

1. function WSAStartup(wVersionRequired: word; var WSData: TWSAData): Integer; Входящий параметр wVersionRequired - наивысшая версия сокетов Windows, которую можно использовать. Исходящий параметр WSData - указатель на структуру данных WSAData. В случае успешного завершения функция возвращает значение ноль, в противном случае код ошибки. Эта функция должна быть ОБЯЗАТЕЛЬНО вызвана один раз, перед началом работы с сокетами.

2. function inet_addr(cp: PChar): u_long; Входящий параметр cp - нуль терминальная строка. Если нет ошибок, функция возвращает стандартный IP адрес для использования по протоколу TCP\IP. В случае ошибки возвращаемое значение - INADDR_NONE.

3. function htons(hostshort: u_short): u_short; Входящий параметр hostshort - число (16 битное). Функция возвращает 16 битный номер в специальном формате, который можно использовать в протоколе TCP\IP.

4. function socket(af, Struct, protocol: Integer): TSocket; Входящий параметр af - спецификация семейства сокетов, может принимать значение AF_INET, AF_IPX и др. struct - спецификация типа нового сокета (принимает значение SOCK_STREAM или SOCK_DGRAM). protocol - специфический протокол, который будет использоваться сокетом (если не хочешь ничего специфического - пиши 0). Если функция выполнена без ошибок, она возвращает дескриптор на новый сокет, если ошибки есть возвращается INVALID_SOCKET. Код ошибки можно узнать, вызвав функцию WSAGetLastError.

5. function connect(s: TSocket; var name: TSockAddr; namelen: Integer): Integer; Входящий параметр s - дескриптор, идентифицырующий сокет (это значение возвращает функция socket). name - имя с которым будет связан сокет после коннекта, namelen - длинна этого имени (легко можно получить, используя функцию sizeof). В случае успешного коннекта функция возвращает значение ноль. Если коннект не удался, возвращаемое значение - SOCKET_ERROR (код ошибки можно получить, используя функцию WSAGetLastError).

6. function WSACleanup: Integer; Если выполнена успешно - возвращает ноль и прекращает использования сокетов Windows. Если есть ошибка во время выполнения возвращает код ошибки.

Это далеко не все функции, находящиеся в winsock.dll. Еще раз повторю, что полный их список можно найти в файле winsock.pas, а описание можно посмотреть в Win32 API Reference - Windows Sockets 2 Reference. Надеюсь, что Вы поняли все вышенаписанное и знакомы с основами функционирования сокетов, т.е. понимаете, что такое сокет. Для закрепления полученных знаний, как обычно, напишим маленькую программку.. Все знают, что такое Socks сервер и для чего он нужен.. Если у Вас провал в памяти, я напомню: Socks прокси работают по Socks протоколу, который не зависит от высокоуровневых протоколов (http, ftp, telnet и.т.д.) и поэтому может использоваться для передачи данных по любому протоколу "высокого уровня". После всего выше изложенного будет вполне закономерно, что для тренировки мы напишем простой консольный сканер диапазонов IP адресов на открытый 1080 порт, который является стандартным портом Socks серверов.


program scan;

{$APPTYPE CONSOLE}

{ Для использования winsock необходимо описать этот модуль в uses. }
uses
  sysutils,winsock;

{ дефолтовый порт Socks прокси. Сюда можно вписать любой порт,
превратив наш сканнер, к примеру, в httpd (80 порт) сканнер. }
const
  port = 1080;

{ Здесь объявляем переменные }
var
  D:WSAData;
  S:TSocket;
  A:TSockAddr;
  m1,m2,mask,val:String;
  i:Integer;
begin
  { Если наш сканер запущен без параметров, выводим некоторую информацию.. }
  if paramcount < 1 then
  begin
    writeln('Socks Scanner by har0n, har0n@gmx.net');
    writeln('Example: scan.exe 127.0.0 1-255');
    writeln('http://www.security.net.tf');
  exit;
end
else
{ Если сканер запущен с параметрами, в переменную mask заносим 1-ый параметр,
в val 2-ой параметр }
begin
  mask:=paramstr(1);
  val:=paramstr(2);
  { Определяем диапазон сканирования}
  m1:= copy(val,1,pos('-',val)-1);
  m2:= copy(val,pos('-',val)+1,length(val));
  writeln('- Scanning begin: '+mask+'.'+m1+' - '+mask+'.'+m2+' -');
  writeln;
  { Если WSAStartup() возвращает не нулевое значение, выводим сообщение об ошибке
  и выходим из программы}
if WSAStartup($101,D)<>0 then
begin
  writeln('error..');
  exit;
end;
{ Начинаем процесс сканирования }
for i:= strtoint(m1) to strtoint(m2) do
begin
  { Определяем тип семейства сокетов, и IP адрес для сканирования }
  A.sin_family:=AF_INET;
  A.sin_addr.S_addr:=inet_addr(pchar(mask+'.'+inttostr(i)));
  { Создаем сокет }
  S:=socket(AF_INET,SOCK_STREAM,0);
  { Если возвращено значение INVALID_SOCKET, выводим сообщение об ошибке }
  if S=INVALID_SOCKET then
    writeln('socket error');
  { Определяем порт (задается константой) }
  A.sin_port:=htons(port);
  { Пытаемся подконнектиться, если удачно - выводим сообщение, что порт открыт,
  в другом случае - сообщение о том, что порт закрыт (или недоступен) }
  if connect(S,A,sizeof(A))=0 then
    writeln(mask+'.'+inttostr(i)+' port '+inttostr(port)+' opened') else
  writeln(mask+'.'+inttostr(i)+' port '+inttostr(port)+' closed');
end;
{ Завершаем работу с сокетами }
WSACleanup;
writeln;
writeln('- Scanning is completed -');
end;
end.

Запускать сканер будем так: scan.exe 127.0.0 1-255, при этом будут проверены IP адреса с 127.0.0.1 по 127.0.0.255. Я компилировал исходник на Delphi 5 update pack 1, Windows 2000 SP2, но, думаю, и под другими версиями Delphi и Windows проблем не возникнет. Ну все, удачи!






Copyright © 2004-2016 "Delphi Sources". Delphi World FAQ




Группа ВКонтакте   Ссылка на Twitter   Группа на Facebook