Форум: "Сети";
Текущий архив: 2004.12.05;
Скачать: [xml.tar.bz2];
ВнизНе могу разобраться с функцией GetAcceptExSockAddrs Найти похожие ветки
← →
Григорьев Антон © (2004-09-28 11:03) [0]Вот код юнита, сделанного мною специально для тестирования этой функции:
unit AETUnit;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,WinSock,
StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
function AcceptThreadFunc(Param:Pointer):Integer;
var S1,S2:TSocket;
Addr,AddrIn,AddrOut:TSockAddr;
Buf:array[0..999] of Byte;
Cnt:DWORD;
AddrInLen,AddrOutLen:Integer;
Ov:TOverlapped;
begin
FillChar(Buf,SizeOf(Buf),0);
S1:=Socket(AF_Inet,Sock_Stream,0);
S2:=Socket(AF_Inet,Sock_Stream,0);
Addr.sin_family:=AF_Inet;
Addr.sin_port:=htons(12345);
Addr.sin_addr.S_addr:=Inet_Addr("127.0.0.1");
FillChar(Addr.sin_zero,SizeOf(Addr.sin_zero),0);
Cnt:=Bind(S1,Addr,SizeOf(Addr));
Cnt:=Listen(S1,1);
Ov.hEvent:=CreateEvent(nil,False,False,nil);
AcceptEx(S1,S2,@Buf,100,32,32,Cnt,@Ov);
GetOverlappedResult(S1,Ov,Cnt,True); // (*)
GetAcceptExSockAddrs(@Buf,100,32,32,AddrIn,AddrInLen,AddrOut,AddrOutLen);
Result:=Cnt
end;
procedure TForm1.Button1Click(Sender: TObject);
var S:TSocket;
Addr:TSockAddr;
Buf:string;
Data:TWSAData;
ThreadID:Cardinal;
begin
WSAStartup($101,Data);
BeginThread(nil,0,AcceptThreadFunc,nil,0,ThreadID);
Sleep(100);
S:=Socket(AF_Inet,Sock_Stream,0);
Addr.sin_family:=AF_Inet;
Addr.sin_port:=htons(12345);
Addr.sin_addr.S_addr:=Inet_Addr("127.0.0.1");
FillChar(Addr.sin_zero,SizeOf(Addr.sin_zero),0);
Connect(S,Addr,SizeOf(Addr));
Sleep(1000);
Buf:="abcde";
Send(S,Buf[1],Length(Buf)+1,0);
Sleep(500); // (**)
Button1.Caption:="OK"
end;
end.
Запускаю, ставлю строку останова на строку (*), прохожу главную нить под отладчиком. Точка останова срабатывает, когда выполнение доходит до строки (**). Смотрю, что лежит в буфере Buf и вижу там, во-первых, присланные данные, а во-вторых, адрес отправителя и адрес сокета, к которому оказывается привязан сокет S2, т.е. до этого места всё нормально. Но когда я делаю следующий шаг и выполняю строку (*), в переменных AddrIn и AddrOut оказывается полная ерунда (хотя переменные AddrInLen и AddrOutLen получают значение 16, как и должно быть). Но тех значений, которые в результате копируются в AddrIn и AddrOut, в Buf просто нет! Откуда эти данные берутся - не понимаю, но они всегда одни и те же. Пробовал вместо стандартного модуля WinSock использовать WinSock 2 Алекса Коншина - результат тот же самый. Экспериментировал с различными значениями размеров буфера - ничего не меняется. В своём коде ошибки не вижу, в MSDN"е описаний такой проблемы не нашёл. В чём может быть дело?
← →
Digitman © (2004-09-28 11:53) [1]WSAStartup($202,Data);
← →
Григорьев Антон © (2004-09-28 12:20) [2]
> Digitman © (28.09.04 11:53) [1]
> WSAStartup($202,Data);
Не помогло :(
Да и, честно говоря, я бы очень удивился, если б помогло - AcceptEx и иже с ним являются частью спецификации WinSock 1, WinSock 2 тут не обязателен. Правда, поддерживаются только в линии NT, но у меня 2000, так что и тут всё в порядке. Кстати, проверил уже на двух компьютерах - и на обоих поля структур AddrIn и AddrOut получают одинаковые значения. Следовательно, адрес, откуда они берутся, а также то, что по этому адресу находится, скорее всего, строго детерминировано, вот только непонятно, как именно.
← →
Digitman © (2004-09-28 12:59) [3]в борландовскую декларацию GetAcceptExSockaddrs вкралась досадная очепятка, если не сказать - ляп
смотрим в MSDN и видим что эти параметры передаются как косвенный указатель (указатель на переменную, куда ф-ция возвратит не саму структуру, а указатель на нее)
LPSOCKADDR* LocalSockaddr
LPSOCKADDR* RemoteSockaddr
на самом деле ф-цию следовало (в полном соответствии с MSDN) декларировать хотя бы так:
procedure GetAcceptExSockaddrs(lpOutputBuffer: Pointer;
dwReceiveDataLength, dwLocalAddressLength, dwRemoteAddressLength: DWORD;
var LocalSockaddr: PSockAddr; var LocalSockaddrLength: Integer;
var RemoteSockaddr: PSockAddr; var RemoteSockaddrLength: Integer); stdcall;
убедись сам, вызвав не штатную GetAcceptExSockaddrs, а переопределенную тобой ф-цию
procedure FixedGetAcceptExSockaddrs(lpOutputBuffer: Pointer;
dwReceiveDataLength, dwLocalAddressLength, dwRemoteAddressLength: DWORD;
var LocalSockaddr: PSockAddr; var LocalSockaddrLength: Integer;
var RemoteSockaddr: PSockAddr; var RemoteSockaddrLength: Integer); stdcall; external "wsock32.dll" name "GetAcceptExSockaddrs";
соотв-но и переменные объяви по-новому
Addr: TSockAddr;
AddrIn,AddrOut:PSockAddr;
← →
Григорьев Антон © (2004-09-28 13:38) [4]
> Digitman © (28.09.04 12:59) [3]
Да, всё заработало, спасибо! Проглядел я этот момент.
Кстати, получается, что у Алекса Коншина та же ошибка в его alpha-релизе. Надо будет ему сказать...
← →
Digitman © (2004-09-28 13:47) [5]
> получается, что у Алекса Коншина та же ошибка в его alpha-релизе
и не только у него
модулей winsock2.pas всяких разных целое море по сети гуляет, у меня, к примеру, есть пара других реализаций этого модуля, ка в одном из них ф-ция вообще не присутствует, а в другом она содрана один-в-один с борландовского модуля
← →
Digitman © (2004-09-28 13:50) [6]кстати, а чего ты завелся на AcceptEx ?
особо выдающихся прелестей я не вижу в его использовании
м.б. он и выигрывает по ресурсам и производительности, но заведомо проигрывает ф-ции WSAAccept по отсутствию весьма полезной функциональности - реализации условного акцепта вх.запросов на коннект
← →
Григорьев Антон © (2004-09-28 14:40) [7]
> Digitman © (28.09.04 13:50) [6]
> кстати, а чего ты завелся на AcceptEx ?
Всё просто :) Статью я пишу про всё это. Ну и вот, для полноты картины... Ты, может, уже обратил внимание, что я тут последнее время задаю вопросы, в основном, не практического, а теоретического характера. По той же причине :)
← →
Digitman © (2004-09-28 15:21) [8]
> Григорьев Антон © (28.09.04 14:40) [7]
до кучи уж тогда и про true conditional acceptance напиши
толковых статей в Рунете я что-то не видел, а вопросы нет-нет да и возникают на эту тему
> последнее время задаю вопросы, в основном, не практического,
> а теоретического характера
заметил
← →
Григорьев Антон © (2004-09-28 16:21) [9]
> Digitman © (28.09.04 15:21) [8]
> до кучи уж тогда и про true conditional acceptance напиши
А это что ещё за зверь такой?
Вряд ли я я напишу по это, раз я об этом никогда не слышал. Разве что вдруг окажется, что я эти самые true conditional acceptance знаю, но привык называть другими словами :)
← →
Digitman © (2004-09-28 16:33) [10]
> это что ещё за зверь такой?
а зверь такой что в случае обычного accept() клиент в ответ на connect() получает SYN-ACK еще ДО того как сервер выполнит accept() .. т.е. после listen() клиент в любом случае получает акцепт от сервера, в то время как при использовании механизма условного акцепта клиент будет акцептирован только если сервер примет решение о допустимости акцепта данного клиента .. иными словами при условном акцепте в ответ на свой SYN клиент может получить SYN-ACK (запрос на коннект акцептирован сервером, коннект успешен) или RST (запрос на коннект НЕ акцептирован сервером, клиент нежелателен, коннект НЕ успешен)
← →
Digitman © (2004-09-28 16:38) [11]вся эта кухня вертится начиная с W2k/XP вокруг ф-ций setsockopt(so_conditional_accept = True) + WSAAccept
почитай про это в MSDN и на book.itep.ru
настоящий серьезный сервер просто обязан уметь не пускать флудеров-спамеров и прочую сомнительную клиентскую братию
← →
Григорьев Антон © (2004-09-28 17:10) [12]
> Digitman © (28.09.04 16:33) [10]
Всё, понял, вставлю пару абзацев об этом. Как я и думал, я слышал об этом, но мне это особо важным не показалось. Видимо, потому, что я использую сокеты для работы в технологических замкнутых сетях, куда никто посторонний просто физически не имеет доступа. Мне и сама возможность подключения по условию, честно говоря, особо полезной не показалась :)
← →
Digitman © (2004-09-28 17:18) [13]
> использую сокеты для работы в технологических замкнутых
> сетях
дык ыть - не дай божЕ "заразиться" лодному из компов в такой сети .. затрахает он прокси ж ! ... вот хотя бы на стороне прокси и была б полезна сия "приблуда" .... вник ?
← →
Digitman © (2004-09-28 17:20) [14]
> лодному
= любому
← →
Григорьев Антон © (2004-09-28 17:30) [15]
> Digitman © (28.09.04 17:18) [13]
Да нет там никаких прокси :)
Там стоят несколько контроллеров, поддерживающих Ethernet и TCP/IP, работающих под управлением чего-нибудь типа OS-9 или VxWorks (в крайнем случае - Embedded NT), и штуки три-четыре полноценных компьютеров, которые получают от этих контроллеров данные, сохраняют их в БД и показыают оператору красивую картинку. И никаких проводов вовне. А капельно-воздушным путём компьютерные вирусы пока, к счастью, не передаются :)
← →
Digitman © (2004-09-28 17:36) [16]ну ты-то не только для "стерильных" сетей, надеюсь, статью сотворяшь) ... посему и было б нехило заикнуться в ней про такую расчудесную фичу
← →
Григорьев Антон © (2004-09-28 17:56) [17]
> Digitman © (28.09.04 17:36) [16]
Обязательно заикнусь :)
← →
Григорьев Антон © (2004-09-29 11:06) [18]Посмотрел, что есть по условному подключению - надо сказать, его не очень жалуют :) Даже в книге http://www.delphikingdom.com/asp/book.asp?BookID=202 о ней написано так: На самом деле, условная функция бесполезна. При использовании протокола TCP нельзя отклонить клиентское соединение само по себе, потому что оно уже было установлено на уровне TCP. Кроме того, поставщик не передаёт действительные параметры QoS условной функции, даже если сообщение PATH уже поступило. В силу этих причин мы не рекомендуем применять условную функцию WSAAccept. А ведь книга издана не кем попало, а Microsoft Press.
← →
Digitman © (2004-09-29 11:43) [19]
> При использовании протокола TCP нельзя отклонить клиентское
> соединение само по себе, потому что оно уже было установлено
> на уровне TCP
глупость какая-то ...
на уровне TCP фактическое установление соединения подразумевает цепочку
c->s SYN
s->c SYN-ACK
c->s ACK
в случае условного акцепта, если сервер отвергает запрос на соединение (возвращая CF_REJECT в callback-ф-ции), цепочка выглядит иначе
c->s SYN
s->c RST (!!)
в результате клиентская ф-ция connect() вернет WSAECONNREFUSED, означающую что сервер отверг запрос, т.е. соединение на уровне TCP не установлено
если же условный акцепт не задействован сервером, то цепочка
c->s SYN
s->c SYN-ACK
c->s ACK
выполняется еще ДО того как сервер выполнил акцепт, т.е. клиентский вызов connect() успешен в любом случае, хотя сервер еще не акцептировал запрос и не создал соотв.гнездо
и у меня это (условный акцепт) работает вполне успешно, так как и описано в ориг.документации MS
> поставщик не передаёт действительные параметры QoS условной
> функции
это никак не влияет на успешность работы механизма усл.акцепта
в большинстве случаев серверу на момент анализа источника запроса на акцепт не нужно знать о клиенте более чем его хост/адрес/порт - этой инф-ции достаточно для анализа на предмет потенциального отвержения данного клиента
← →
Григорьев Антон © (2004-09-29 12:21) [20]
> Digitman © (29.09.04 11:43) [19]
>
> > При использовании протокола TCP нельзя отклонить клиентское
>
> > соединение само по себе, потому что оно уже было установлено
>
> > на уровне TCP
>
>
> глупость какая-то ...
Согласен, написал сюда это просто в качестве курьёза.
> и у меня это (условный акцепт) работает вполне успешно,
> так как и описано в ориг.документации MS
И у меня работает - специально проверял. Просто не все об этом знают :)
← →
Digitman © (2004-09-29 12:30) [21]
> Григорьев Антон © (29.09.04 12:21) [20]
видимо, автор статьи либо не знает либо явно не упоминает того, что ф-ция setsockopt(so_conditional_accept=true) работает только на w2k/xp, на nt/win9x же опция недоступна, соответственно и механизм усл.акцепта не реализован
Страницы: 1 вся ветка
Форум: "Сети";
Текущий архив: 2004.12.05;
Скачать: [xml.tar.bz2];
Память: 0.52 MB
Время: 0.042 c