【发布时间】:2012-01-12 12:15:06
【问题描述】:
以下代码旨在通过线程内的套接字读取数据。
//main method from dll
function GetSocketData(const IP, Port: PChar): PChar; export; cdecl;
var
Thread: TMyThread;
DataIsRead: TEvent;
begin
DataIsRead := TEvent.Create(nil, True, False, '');
Thread:= TMyThread.Create(DataIsRead, IP, Port);
DataIsRead.WaitFor(INFINITE);
Result := BlockAlloc(Thread.ResultData);
DataIsRead.Free;
Thread.Free;
end;
TMyThreadBase = class(TThread)
protected
FResultData: string;
public
constructor Create;
property ResultData: string read FResultData;
end;
constructor TMyThreadBase.Create;
begin
inherited Create(False); // Suspended
FResultData := '';
FreeOnTerminate := False;
end;
TMyThread = class(TMyThreadBase)
private
FMyData: TMyData;
FSocketCom: TSocketCom;
//other params
protected
procedure Connect(Sender: TObject);
procedure Execute; override;
public
constructor Create(DataIsRead: TEvent; const IP, Port: PChar);
destructor Destroy; override;
end;
constructor TMyThread.Create(const IP, Port: PChar);
begin
inherited Create;
/init params/
CoInitialize(nil);
FSocketCom := ComCreate(FPort, FIP);
FSocketCom.OnConnect := Connect;//Connect method sends the special command to the port {`ClientSckt.Socket.SendBuf(B[0], Count)`}
FSocketCom.Reopen;
FMyData := TMyData.Create(DataIsRead, FSocketCom);//class used for received data interpretation
//DataIsRead event is being set when all data is interpreted
FSocketCom.SetRxFunc(FMyData.NCData);//set method for data interpretation
FMyData.InitData(...);//init values needed while data is being interpreted
end;
destructor TMyThread.Destroy;
begin
CoUninitialize;
inherited;
end;
procedure TMyThread.Execute;
begin
inherited;
while not Terminated do
Sleep(100);
//that is the place where I do not know what to do to wait while OnRead event is fired.
end;
TSocketCom = class(TCustomCom)
private
ClientSckt: TClientSocket;
procedure SocketConnect(Sender: TObject; Socket: TCustomWinSocket);
procedure SocketRead(Sender: TObject; Socket: TCustomWinSocket);
protected
procedure SetThread; override;
public
constructor Create;
destructor Destroy; override;
function Open:Boolean; override;
function Read( Buf:PAnsiChar; Size:Integer; Wait:Integer = 0 ):Integer; override;
end;
procedure TCustomCom.SetRxFunc(OnRxData: TRxDataEvent);
begin
...
SetThread;
...
end;
function TSocketCom.Open:boolean;
var
i,j:integer;
begin
...
ClientSckt:=TClientSocket.Create(nil);
ClientSckt.ClientType:=ctBlocking;
ClientSckt.HostAndAddress:='127.0.0.0';
ClientSckt.Port:=1234;
ClientSckt.OnConnect:=SocketConnect;
ClientSckt.Open;
...
end;
function TSocketCom.Read(Buf:PAnsiChar;Size:Integer; Wait:Integer):Integer;
begin
if Opened then
Result:=ClientSckt.Socket.ReceiveBuf(Buf^,Size);
if Result<0 then Result:=0;
end;
procedure TSocketCom.SetThread;
begin
inherited;
ClientSckt.OnRead:=SocketRead;
end;
问题:OnRead 事件没有被触发,尽管它接缝了所有需要的实例都在线程中创建。建立连接并发送命令。
【问题讨论】:
-
如果您想等待线程,您应该使用
Terminate将其标记为已完成并简单地调用WaitFor而不是while循环。 -
好的。这将解决持有主线程的问题。但是如何强制在该线程中读取套接字?正如我所看到的,只有从执行中调用的方法才能在线程中运行。但是套接字读取发生在调用其 Read 方法时。我不能在 Execute 中调用它。
-
为什么不能在Execute中调用呢?
-
因为在服务器发送数据时,ClientSocket 的 OnRead 事件会调用它。
-
动态加载您的 onRead 事件 - 请参阅我的另一篇文章。如果您想在线程中有效地使用 TClientSocket,最好尽量避免在表单上使用组件并依赖消息来触发事件 - 只需在线程构造函数的代码中或在“执行”方法的顶部构造一个 TClientSocket 套接字。
标签: multithreading delphi sockets