Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Сети";
Текущий архив: 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.03 c
14-84620
Сатир
2003-06-02 14:15
2003.06.26
---|Ветка была без названия|---


14-84558
Soft
2003-06-07 19:56
2003.06.26
И когда за мною придут врачи


1-84258
Far
2003-06-13 01:28
2003.06.26
QReport


1-84136
REA
2003-06-10 15:16
2003.06.26
Чтение компонента


3-84034
st-av
2003-05-31 18:13
2003.06.26
DBGrid и форматированный ввод





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский