Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2012.04.08;
Скачать: [xml.tar.bz2];

Вниз

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;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.47 MB
Время: 0.003 c
2-1324146298
SQLEX
2011-12-17 22:24
2012.04.08
Почему? Value assigned to ... never used


15-1323241735
Dennis I. Komarov
2011-12-07 11:08
2012.04.08
Routing OS


11-1206012968
Nikfel
2008-03-20 14:36
2012.04.08
Как вывести окно с прозрачным цветом.


15-1322861999
константин
2011-12-03 01:39
2012.04.08
jvcl


15-1323030602
Юрий
2011-12-05 00:30
2012.04.08
С днем рождения ! 5 декабря 2011 понедельник





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский