Начнем с отзывов. Во-первых, спасибо за положительные. Во-вторых, я допустил
ошибку, а никто и не увидел. Процесс обработки очереди надо все-таки
терминайтить. Но об этом далее. В-третьих, комментариев в коде вполне
достаточно. Я так пишу. Охоту к написанию комментариев у меня отбили еще в
универе. А если не можешь разобраться, так нафига вообще трепыхаться - ходи на
порно-сайты и дыши с присвистом. В-четвертых, объясню почему сервер писался на
асме. На это есть 6 причин:
- Быстродействие. Все равно быстрее будет работать чем на сях и delphi (не
говоря уже о тормознутом визуал бейсике. Такой язык надо в школе изучать - это
надо ж, грузить dll-и и запускать с них функции);
- Размеры. 11 kb "всунуть" в что-то все таки легче чем, например, 100;
- Если мы пишем на асме, то имеем дело с ошибками своими и мелкософта, а не с
глюками программера из фирмы Borland. Взять хотя-бы "RadioGroup" в Delphi;
- В ранних версиях "DTr", периодически возникала ошибка 10060 асинхронной
работы. Только на некоторых компьютерах, но все-таки. Написание сервера на сях
не помогло. После выхода версии на асме и сооружения в клиенте процесса
обработки очереди приходящих сообщений, у меня еще такой ошибки не возникало;
- В своих продуктах фирмы по производству программного обеспечения, любят при
ошибке вызывать исключительную ситуацию, на что виндоуз реагирует показом
"красивого" окошка с сообщением об ошибке. Некоторые такие реакции не
подавляются try-except. Для сервера это, мягко сказать, нежелательно. В асме все
проще;
- Для борьбы с буржуйскими программами с помощью WINdasm, SoftIce и т.п.,
ассемблер надо знать. А для того чтобы его знать, на нем иногда надо писать.
Завести 2-ой комп и бегать, смотреть на одном окно SoftIce, а на другом доки -
это сильно круто.
Теперь продолжим разговор о нашем клиенте. Как я уже говорил, процесс
обработки очереди при разсоединении и выходе из проги надо прерывать. Для этого
модифицируем нашу процедуру "ClientSocket1Disconnect", вставив в нее вот такой
код:
if not RecvThread.Terminated then begin while not RecvThread.Terminated do begin try RecvThread.Terminate; except end; sleep(100); Application.ProcessMessages; end; end; LstRbeg:=nil; LstRend:=nil;
|
Также нас интересует событие, происходящее перед выходом из клиента. Выделим
нашу форму ("Form1"), перейдем в "Object Inspector" на закладку "Events" и 2
раза "click"-нем по "onClose". Перейдем в раздел кода и запишем:
// Выход из проги procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin Action := caNone; if constat then Form1.Button1Click(Sender); Application.ProcessMessages; Application.Terminate; Halt(1); end;
|
Теперь поговорим о визуализации и удобстве работы с клиентом. Кнопки, которые
отвечают за посылание серверу команд, надо как-то выделить. Для этого
воспользуемся объектом "ImageList" с закладки "Win32" ("ImageList1"). Помещаем
его на форму и с помощью правой кнопки мыши добавляем в него изображения для
кнопок. Теперь нужно выделить "ToolBar1" и в его свойстве "Images", из
всплывающего списка, поставить "ImageList1". После этого перейдем на
"ToolButton1", в свойстве "ImageIndex", выберем нужный рисунок. Для отображения
"всплывающей" подсказки в свойстве "ShowHint" поставим "true", а в свойстве
"Hint", напишем "Кнопка № 1". Очень информативно.
Сканер для сервера.
Допустим, мы знаем, что серверная часть запущена у человека (это звучит
гордо), пользующегося услуами провайдера "Slow". Мы также знаем пространство
адресов этого провайдера. Но мы не знаем, какой адрес даст провайдер этому челу.
Или у нас есть локалка. Почему-то иногда прога путает адреса на плюс-минус
два. Почему - до сих пор не знаю (данная проблема была замечена не мной), но
если кто знает, то пусть отпишет в "Отзывы".
Или мы изменили порт, а какой забыли.
Для всего этого нам нужен сканер по адресам и портам. То, о чем пойдет речь
далее, можно использовать не только для нашего сервера. Итак, в Delphi, в
проекте нашего сервера, выбираем в верхнем меню "File"-->"New Form". Пусть
это будет "Form2". В свойстве "Caption" пишем "Сканер". Размещаем на форме
компоненты:
- Edit1
- С какого порта начинать сканирование;
- Edit2
- По какой порт;
- Edit3
- Первые 3 цифры адреса в виде "xxx.xxx.xxx.xxx" (без точки в конце);
- Edit4, Edit5
- Диапазон последней цифры адреса;
- Edit6
- Время ожидания соединения (в секундах);
- Button1
- Начать/прекратить сканирование;
- Memo1
- Отчет сканирования;
- ProgressBar1, ProgressBar2 (Win32)
- Для визуализации процесса перебора по адресам и портам соответственно;
- ClientSocket1
- И так понятно.
Теперь на "Form1" лепим кнопку, обзываем ее "Scaner" и нажимаем на ней два
раза. В разделе кода пишем :
// Scaner procedure TForm1.Button2Click(Sender: TObject); begin Form2.WindowState := wsNormal; Form2.Visible := true; Form2.SetFocus; end;
|
В раздел "uses" добавляем "Unit2". Переходим на "Form2". Два раза нажимаем на
"Button1", на события "onConnect" и "onError" в "ClientSocket1" и на "onClose" в
"Form2". Вот текст модуля "Unit2.pas":
unit Unit2;
interface
uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ComCtrls, StdCtrls, ScktComp;
type TForm2 = class(TForm) Edit1: TEdit; Edit2: TEdit; Edit3: TEdit; Edit4: TEdit; Edit5: TEdit; Edit6: TEdit; Button1: TButton; Memo1: TMemo; ProgressBar1: TProgressBar; ProgressBar2: TProgressBar; ClientSocket1: TClientSocket; procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure Button1Click(Sender: TObject); procedure ClientSocket1Error(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer); procedure ClientSocket1Connect(Sender: TObject; Socket: TCustomWinSocket); private { Private declarations } public { Public declarations } end;
var Form2: TForm2; Rez11: Boolean = false; Bool: Boolean = false;
implementation
{$R *.DFM}
//Close Scaner procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction); begin // если запущен, то прерываем процесс if Rez11 then begin Action := caNone; Form2.Button1Click(Sender); end; end;
// Включить/отключить сканер procedure TForm2.Button1Click(Sender: TObject); var I, J, K: Integer; DopStr: string; begin if Rez11 then begin // прервать сканирование if Application.MessageBox('Прервать сканирование?', 'Сканер', mb_YesNo + mb_IconQuestion) = idYes then begin Rez11 := false; Bool := false; end; end else begin // запуск сканера if StrToInt(Form2.Edit2.Text) < StrToInt(Form2.Edit1.Text) then begin Application.MessageBox('Неверно указан диапазон для портов','Сканер', mb_Ok + mb_IconStop); exit; end;
if StrToInt(Form2.Edit5.Text) < StrToInt(Form2.Edit4.Text) then begin Application.MessageBox('Неверно указан диапазон IP-адресов','Сканер', mb_Ok + mb_IconStop); exit; end;
Form2.Caption:='Идет сканирование...'; Form2.Memo1.Lines.Clear;
try DopStr := trim(Form2.Edit3.Text); Rez11 := true; Form2.Button1.Caption := 'Отмена'; Form2.Memo1.Lines.Add('-------------' + #13 + #10 + '===========');
// начальные значения для порта и адреса I := StrToInt(Form2.Edit1.Text); J := StrToInt(Form2.Edit4.Text);
try Form2.ProgressBar1.Max := StrToInt(Form2.Edit2.Text) - StrToInt(Form2.Edit2.Text) + 2; Form2.ProgressBar1.Position := 1; Form2.ProgressBar2.Max := StrToInt(Form2.Edit5.Text) - StrToInt(Form2.Edit4.Text) + 2; Form2.ProgressBar2.Position := 1;
// цикл по адресам while I <= StrToInt(Form2.Edit2.Text) do begin J := StrToInt(Form2.Edit4.Text); // цикл по портам while J <= StrToInt(Form2.Edit5.Text) do begin Application.ProcessMessages; if not Rez11 then break; Form2.ClientSocket1.Active := false; Form2.ClientSocket1.Port := I; Form2.ClientSocket1.Address := trim(DopStr) + '.' + trim(IntToStr(J));
try // попытка соедениться Form2.ClientSocket1.Active := true; Application.ProcessMessages;
// время ожидания Bool := true; K := round(StrToInt(Form2.Edit6.Text) * 1000 / 50); while Bool do begin Sleep(50); Application.ProcessMessages; dec(K); if K=0 then begin
try Form2.ClientSocket1.Active:=false; except end; break; end; end; except end;
Application.ProcessMessages; Form2.ProgressBar2.Position := Form2.ProgressBar2.Position + 1; inc(J); end; inc(I); Application.ProcessMessages;
if not Rez11 then break;
Form2.ProgressBar1.Position := Form2.ProgressBar1.Position + 1; end; Form2.ProgressBar2.Position := Form2.ProgressBar1.Position + 1; Form2.ProgressBar1.Position := Form2.ProgressBar1.Position + 1; except Application.MessageBox('Ошибка выполнения операции', 'Сканер', MB_Ok + mb_IconStop); end; Form2.Button1.Caption := 'Сканер'; Form2.ProgressBar1.Position := 0; Form2.ProgressBar2.Position := 0; Form2.Caption := 'Сканер по адресам и портам'; if Rez11 then begin Application.MessageBox('Процедура сканирования по адресам и портам закончена.', 'Сканер', mb_Ok + mb_IconAsterisk); Form2.Memo1.Lines.Add('-----------------'+#13+#10+'========== ВСЕ АДРЕСА И ПОРТЫ ОТСКАНИРОВАНЫ'+#13+#10+#13+#10); Rez11 := false; end else Form2.Memo1.Lines.Add('------------'+#13+#10+'============== ПРЕРВАНО НА порт-'+IntToStr(I)+', адрес-'+trim(DopStr)+'.'+IntToStr(J-1)+#13+#10+#13+#10); except Application.MessageBox('Ошибка инициализации процесса.','Сканер',mb_Ok+mb_IconStop); end; Form2.Caption:='Сканер по адресам и портам'; end; end;
// Есть ответ сервера procedure TForm2.ClientSocket1Connect(Sender: TObject; Socket: TCustomWinSocket); begin // если соеденились вывести сообщение Form2.Memo1.Lines.Add('***' + #13 + #10 + 'Порт: ' + IntToStr(Form2.ClientSocket1.Port) + ' ' + 'Адрес: ' + Form2.ClientSocket1.Address + ' - ЕСТЬ ОТВЕТ' + #13 + #10); Application.ProcessMessages; // прервать время ожидания try Form2.ClientSocket1.Active := false; except end; Bool := false; end;
// Ошибка при соединении procedure TForm2.ClientSocket1Error(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer); begin // прервать время ожидания если ошибка ErrorCode := 0; Bool := false; end;
end.
|
Теперь проверим. Запускаем сервер и клиент. Жмем кнопку "Сканер". В "Edit1"
пишем "10001", в "Edit2" - "10001", в "Edit3" - "127.0.0", в "Edit4" - "1", в
"Edit5" - "254", в "Edit6" - "1". Все значения без кавычек. Жмем нашу кнопку
начала сканирования. Все, проверка закончена.
P.S. Статья и программа предоставлена в целях обучения и вся ответственность
за использование ложится на твои хилые плечи.
|