Форум: "Сети";
Текущий архив: 2003.06.26;
Скачать: [xml.tar.bz2];
ВнизNonblocking Socket в отдельном потоке Найти похожие ветки
← →
Akni (2003-04-22 16:18) [0]Простите, если надоедаю глупыми вопросами, но проблема такая:
Создаю отдельный поток.
procedure TfrmPC.FormCreate(Sender: TObject);
begin
ServerThread:=TISServerThread.Create(Self, fLog);
...
end;
В этом потоке создаю сокет.
constructor TISServerThread.Create;
begin
fLog:=Log;
fOwner:=Own;
FreeOnTerminate:=true;
fServerSocket:=TServerSocket.Create(fOwner);
fServerSocket.ServerType:=stNonBlocking;
fServerSocket.OnAccept:=SocketAccept;
fServerSocket.OnClientDisconnect:=SocketClientDisconnect;
fServerSocket.OnClientConnect:=SocketClientConnect;
fServerSocket.OnClientRead:=SocketRead;
fServerSocket.OnListen:=SocketListen;
fServerSocket.OnClientError:=SocketError;
fServerSocket.Port:=PortNr;
inherited Create(false);
end;
procedure TISServerThread.Execute;
begin
fServerSocket.Active:=true;
...
Пишу для этого сокета обработчики на OnConnect, OnRead,...
А как теперь все это с Thread.OnExecute "связать"? Как сделать так, чтобы поток реагировал только на наступление этих событий?
← →
Digitman (2003-04-22 16:35) [1]видишь ли, в доп.код.потоке будут выполнены только те строки кода, которые находятся в теле метода TISServerThread.Execute
все, что ты делаешь ВНЕ этого метода, в дан.случае будет выполняться в том потоке, который вызвал конструктор TISServerThread.Create()
← →
Digitman (2003-04-22 16:37) [2]и - что это за класс TISServerThread ? Среди стандартных в Д5 таких классов нет
← →
Akni (2003-04-22 17:03) [3]в доп.код.потоке будут выполнены только те строки кода, которые находятся в теле метода TISServerThread.Execute
ну это даже мне понятно
и - что это за класс TISServerThread ?
потомок стандартного TThread
TISServerThread = class(TThread)
private
{ Private-Deklarationen }
...
fLog: TISLog;
fOwner: TComponent;
fServerSocket: TServerSocket;
procedure SocketAccept(Sender: TObject; Socket: TCustomWinSocket);
procedure SocketRead(Sender: TObject; Socket: TCustomWinSocket);
procedure SocketWrite(Sender: TObject; Socket: TCustomWinSocket);
procedure SocketListen(Sender: TObject; Socket: TCustomWinSocket);
procedure SocketError(Sender: TObject; Socket: TCustomWinSocket;
ErrorEvent: TErrorEvent; var ErrorCode: Integer);
procedure SocketClientConnect(Sender: TObject;
Socket: TCustomWinSocket);
procedure SocketClientDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
procedure WrLog;
protected
iRecvdCode: integer;
procedure Execute; override;
public
constructor Create(Own: TComponent; Log: TISLog);
end;
все, что ты делаешь ВНЕ этого метода, в дан.случае будет выполняться в том потоке, который вызвал конструктор TISServerThread.Create()
и что это значит? что сокетные события (OnRead и т.п.) нужно в Execute запихивать?
← →
Digitman (2003-04-22 17:28) [4]
> ну это даже мне понятно
раз понятно - создавай TServerSocket в теле метода Execute... и там же назначай обработчики его событий... которые являются соотв.методами класса TISServerThread
← →
Akni (2003-04-22 17:46) [5]если честно, то эта идея и меня тоже осенила.
Теперь код выглядит так:
Constructor TISServerThread.Create;
begin
fLog:=Log;
fOwner:=Own;
FreeOnTerminate:=true;
inherited Create(false);
end;
procedure TISServerThread.Execute;
var iCode: integer;
iRes: integer;
begin
fServerSocket:=TServerSocket.Create(fOwner);
fServerSocket.ServerType:=stNonBlocking;
fServerSocket.OnAccept:=SocketAccept;
fServerSocket.OnClientDisconnect:=SocketClientDisconnect;
fServerSocket.OnClientConnect:=SocketClientConnect;
fServerSocket.OnClientRead:=SocketRead;
fServerSocket.OnListen:=SocketListen;
fServerSocket.OnClientError:=SocketError;
fServerSocket.Port:=PortNr;
fServerSocket.Active:=true;
Но только вот как тогда быть с классическим
while (not Terminated) do
begin
...
end;
в котором и находится обычно вся логика потока?
← →
Digitman (2003-04-22 18:02) [6]обычный цикл обработки оконных сообщений - вот и вся логика !
← →
Akni (2003-04-22 18:23) [7]А нельзя ли на эту тему поподробнее?
Насколько я понимаю, для этого и используется ф-ция WSAAsyncSelect.
Описываю
ScktMsg: integer; //глоб. переменная
потом в TISServerThread.Execute:
iRes:=WSAAsyncSelect(fServerSocket.Socket.SocketHandle,Handle, ScktMsg,
FD_READ or FD_WRITE or FD_ACCEPT or FD_CONNECT or FD_CLOSE);
Но не очень понимаю, как я теперь могу отловить эти сообщения в цикле.
← →
Polevi (2003-04-23 09:41) [8]WSAAsyncSelect сообщает ОС КАКИЕ сообщения интересуют программу.
procedure TTransport.Execute;
var
msg:TMsg;
wc:WNDCLASS;
client:TClient;
i:integer;
begin
try
with wc do
begin
style:= 0;
lpfnWndProc:= @DefWindowProc;
cbClsExtra:= 0;
cbWndExtra:= 0;
hInstance:= 0;
hIcon:= 0;
hCursor:= 0;
hbrBackground:= 0;
lpszMenuName:= nil;
lpszClassName:= "FCTransportWndClass";
hInstance := HInstance;
end;
Windows.RegisterClass(wc);
FWindowHandle:=CreateWindowEx(WS_EX_TOOLWINDOW, wc.lpszClassName,
"", WS_POPUP {!0}, 0, 0, 0, 0, 0, 0, HInstance, nil);
while not Terminated do
case MsgWaitForMultipleObjects(1, FWaitEvent, False, INFINITE, QS_ALLINPUT) of
WAIT_OBJECT_0:
Terminate;
WAIT_OBJECT_0 + 1:
while PeekMessage(msg, 0, 0, 0, PM_REMOVE) do
begin
case LOWORD(msg.lParam) of
FD_ACCEPT:
FD_CONNECT:
FD_READ:
FD_WRITE:
FD_CLOSE:
end;
в твоем случае все будет проще, устроит стандартный цикл PeekMessage, DispathMessage
← →
Digitman (2003-04-23 10:26) [9]
> Насколько я понимаю, для этого и используется ф-ция WSAAsyncSelect.
Эта ф-ция уже вызывается в коде самого TServerSocket, который в дан.случае активизизуется для работы в режиме stNonBlocking. Так что никаких доп.мер принимать не нужно.
Все, что от тебя требуется - это организовать цикл ожидания/ диспетчеризации сообщений , в 1-ю очередь - гнездовых сообщений, адресованных окнам, создаваемым в контексте объектов TCustomWinSocket.
Вот пример упрощенного кода, реализующего минимально необходимую логику.
procedure TISServerThread.ProcessMessagesAndEvents;
var
Msg: TMsg;
begin
while not Terminated and GetMessage(Msg, 0, 0, 0) do
if Msg.hWnd = 0 then
Dispatch(Msg.Message)
else
Dispatchmessage(Msg);
end;
procedure TISServerThread.Execute;
begin
try
fServerSocket:=TServerSocket.Create(nil); // создаем серверное гнездо
try
with fServerSocket do
begin
ServerType:=stNonBlocking;
Port:=PortNr;
OnAccept:=SocketAccept;
OnClientDisconnect:=SocketClientDisconnect;
OnClientConnect:=SocketClientConnect;
OnClientRead:=SocketClientRead;
OnClientWrite:=SocketClientWrite;
OnListen:=SocketListen;
OnClientError:=SocketError;
Active:=True;
end;
try
ProcessMessagesAndEvents; // старт цикла
finally
// здесь можно предусмотреть какие-то обязательные безусловные действия по нормальному/исключительному выходу из цикла
end;
finally
fServerSocket.Free; // безусловно разрушаем серверный объект
end;
except
// здесь можно организовать лог-регистрацию исключений
end;
end;
В момент, когда выполнение код.потока блокировано исполнением вызванной им ф-цией ожидания сообщений (GetMessage), ОС-ядро при поступлении любых оконных сообщений (в дан.случае - посвлаемых гнездами в составе серверного объекта) автоматически вызовет "callback"-ф-ции их обработки (которые в дан.случае в конечном итоге представлены назначенными тобой обработчиками событий OnListen, OnClientConnect, OnClientDisconnect, OnClientError и т.д), и по завершению обработки продолжит исполнение ф-ции GetMessage() до тех пор, пока :
- код.потоку не будет послано сообщение WM_QUIT; в этом случае GetMessage() вернет False и цикл обработки завершится по этому условию;
- код.потоку не будет послано любое иное (неоконное) сообщение;
в этом случае ф-цией-диспетчером Dispatch(Msg.Message) будет вызван соответствующий предопределенный обработчик (если он предусмотрен в классе TISServerThread);
- любой из обработчиков любого из сообщений (будь оно оконное или неоконное) в ходе своего исполнения (в контексте ДАННОГО код.потока !) вызовет некое исключение;
в этом случае исполнение GetMessage() и, как следствие, цикл ожидания/диспетчеризации/обработки будет безусловно прерван (по возникшему исключению) и управление будет передано через finally-блоки в except-блок.
Главное правило - не выпускать любое потенциально возникающее (но неперехваченное/необработанное при этом, т.е. "непогашенное") исключение за пределы тела метода Execute ! Нарушение этого правила ведет к фатальным ошибкам в работе процесса в целом и к непредсказуемым последствиям.
p.s. Для автоматической реакции на оконные сообщения от гнезд в составе серверного объекта вместо GetMessage() м.б. использована любая ф-ция ожидания, например, WaitMessage/PeekMessage, MsgWaitForSingle/MultipleObject[s] и т.п. Важно понимать, что в дан.случае ОС-ядро имет возможность автоматически передать управление "callback"-ф-ции - обработчику сообщения ТОЛЬКО в тот момент, когда код.поток вызвал некую ф-цию ожидания (из вышеупомянутых и аналогичных по назначению) и находится при этом в блокированном состоянии (в состоянии ожидания, не занимающем процессорное время, кванты которого выделяются код.потоку)
← →
Akni (2003-04-23 12:13) [10]>Digitman
>Polevi
спасибо за помощь. с этой проблемой вроде бы разобралась
Страницы: 1 вся ветка
Форум: "Сети";
Текущий архив: 2003.06.26;
Скачать: [xml.tar.bz2];
Память: 0.49 MB
Время: 0.028 c