Форум: "Начинающим";
Текущий архив: 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.005 c