Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2012.04.08;
Скачать: CL | DM;

Вниз

WSAWaitForMultipleEvents не отпускает по FD_ACCEPT   Найти похожие ветки 

 
ProgRAMmer Dimonych ©   (2011-12-16 16:37) [0]

Доброго времени суток. Набросал простенькую заготовку TCP-сервера, слушающего входящие соединения и создающего для каждого новый поток. Делаю WSACreateEvent()-WSAEventSelect() после чего вызываю WSAWaitForMultipleEvents() для двух event"ов: привязанного к слушающему сокету и моего, выставляемого при завершении приложения.

procedure TfrmMain.FormCreate(Sender: TObject);
var
 wsadata    : TWSAData;
 dwThreadId : Cardinal;
begin
 WSAStartup(2, wsadata);
 hTerminateEvent := CreateEvent(nil, True, False, nil);
 hLstnThread := BeginThread(nil, 0, @Thread_Listen, nil, 0, dwThreadId);
end;

function Thread_Listen(lpParams: Pointer): LRESULT;
var
 hLstnSocket : TSocket;
 hTermEvent  : THandle;
 hLstnEvent  : THandle;
 hDataSocket : TSocket;
 addr        : TSockAddrIn;
 addrlen     : Integer;
 ne          : TWSANetworkEvents;
begin
 Result := 0;
 hLstnSocket := socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
 if hLstnSocket = INVALID_SOCKET then Exit;
 hLstnEvent := WSACreateEvent;
 if hLstnEvent = 0 then Exit;
 hTermEvent := hTerminateEvent;

 ZeroMemory(@addr, SizeOf(addr));
 addr.sin_family      := AF_INET;
 addr.sin_port        := htons(7);
 addr.sin_addr.S_addr := INADDR_ANY;

 if bind(hLstnSocket, @addr, SizeOf(addr)) <> 0 then Exit;
 if listen(hLstnSocket, SOMAXCONN) <> 0 then Exit;
 if WSAEventSelect(hLstnSocket, hLstnEvent, FD_ACCEPT or FD_CLOSE) <> 0 then Exit;

 while WSAWaitForMultipleEvents(2, @hTermEvent, False, INFINITE, True) = WAIT_OBJECT_0+1 do
 begin
   WSAEnumNetworkEvents(hLstnSocket, hLstnEvent, @ne);
   hDataSocket := accept(hLstnSocket, addr, addrlen);
   CreateServiceThread(hDataSocket);
 end;  
end;


Беда в том, что WSAWaitForMultipleEvents() уводит поток в ожидание до срабатывания hTermEvent. В это время клиент успешно устанавливает соединение с сервером и отправляет данные, но сервер в тело цикла не входит :( Уже всё, что могло в голову прийти, перерыл :(

В чём может быть причина?


 
Сергей М. ©   (2011-12-16 16:53) [1]

А ты и не ждешь hLstnEvent


 
ProgRAMmer Dimonych ©   (2011-12-16 17:18) [2]

> [1] Сергей М. ©   (16.12.11 16:53)
> А ты и не ждешь hLstnEvent

Уже разобрался. Ждать-то я его ждал. Точнее должен был ждать, но Delphi, видимо, решила по-своему разместить локальные переменные и в стеке за hTermEvent оказывался не hLstnEvent, а что-то ещё. В результате действительно получалось, что не ждал. Подвела ассемблерная привычка :) Решил созданием локального массива на 2 элемента.


 
Сергей М. ©   (2011-12-16 17:23) [3]


> в стеке за hTermEvent оказывался не hLstnEvent, а что-то
> ещё


Не "что-то еще", а конкретно hLstnEvent


> Delphi, видимо, решила по-своему разместить локальные переменные


Она разместила их в стеке по известному правилу - переменные размещается в стеке в порядке обратном их объявлению.


 
Сергей М. ©   (2011-12-16 17:24) [4]


> а конкретно hLstnEvent

hLstnSocket


 
Сергей М. ©   (2011-12-16 17:29) [5]


> в тело цикла не входит


По идее WSAWaitForMultipleEvents и висеть-то не должна в ожидании hTermEvent - один из двух тобой указанных хендлов не является хэндлом объекта синхронизации, потому ф-ция должна бы вернуть WSA_WAIT_FAILED


 
ProgRAMmer Dimonych ©   (2011-12-16 23:10) [6]

> [3] Сергей М. ©   (16.12.11 17:23)
> > Delphi, видимо, решила по-своему разместить локальные
> переменные
> Она разместила их в стеке по известному правилу - переменные
> размещается в стеке в порядке обратном их объявлению.

Ну-ну-ну, нет такого правила. Есть соглашения вызова типа stdcall, определяющие порядок передачи аргументов. Но в данном случае речь идёт о локальных переменных. Набросал тестовый проектик (процедурка с локальными переменными), побрал указатели от локальных переменных, чтобы Delphi не вздумала в регистрах их держать всё время (вот это по ходу и было в моём случае), и открыл окно CPU:



var
 A : Integer;
 B : Integer;
 C : Integer;
begin
 A := 10;
 B := 20;
 C := 30;
 Params(@A, @B, @C);
end;

=======

A := 10;
mov [esp], $0000000a
B := 20;
mov [esp+4], $00000014
C := 30;
mov [esp+8], $0000001e

; Дальше вызов процедуры, параметры определяются через LEA
...


Соответственно


> По идее WSAWaitForMultipleEvents и висеть-то не должна в
> ожидании hTermEvent - один из двух тобой указанных хендлов
> не является хэндлом объекта синхронизации, потому ф-ция
> должна бы вернуть WSA_WAIT_FAILED


не вело себя так на самом деле, потому что оказывался там не хэндл сокета, а что-то другое:

* либо неинициализированный к тому времени hDataSocket
* либо первые 4 байта sockaddr_in - но они меньше похожи на хэндл объекта синхронизации.

Вот такое расследование :)


 
Сергей М. ©   (2011-12-17 21:47) [7]

> Ну-ну-ну, нет такого правила

Есть, если под лок.переменные задействуется стековый фрейм с EBP-адресацией.

Убедись сам на приведенном мною коде, включив опцию "Stack frames" и/или выключив опцию "Optimization"


procedure Params(var A, B, C: Integer);
begin
 WriteLn(IntToHex(Integer(@a), 8), " = ", a);
 WriteLn(IntToHex(Integer(@b), 8), " = ", b);
 WriteLn(IntToHex(Integer(@c), 8), " = ", c);
end;

procedure proc;
var
A : Integer;
B : Integer;
C : Integer;
begin
A := 10;
B := 20;
C := 30;
Params(A, B, C);
end;

..

proc;




Страницы: 1 вся ветка

Текущий архив: 2012.04.08;
Скачать: CL | DM;

Наверх




Память: 0.49 MB
Время: 0.01 c
8-1222099174
ruf
2008-09-22 19:59
2012.04.08
Использовать свои шрифты


4-1253393188
Stepan Darchuk
2009-09-20 00:46
2012.04.08
Запуск приложения не из файла


15-1323102788
Eraser
2011-12-05 20:33
2012.04.08
Какой хостинг посоветуете?


15-1323103260
Artem
2011-12-05 20:41
2012.04.08
О жизни


2-1324013868
И. Павел
2011-12-16 09:37
2012.04.08
Перезапуск службы после остановки системой