我被困住了。我以前使用过服务器和客户端套接字(非indy),它们很好地异步并且易于使用。我正在尝试制作一个简单的客户端服务器。连接到客户端后,服务器会在计时器事件上发送小块数据。时间是77ms,数据块大约是100字节。 我尽力在这里和那里以及人们的例子中找出indy。 (显然,如果人们能够迅速开展工作,那么在网络上就不会有太多关于它的内容)。下面我从客户端和服务器中提取了相关部分。
我将ip设置为localhost,我试图首先调试服务器端。我启动客户端,我在调试器中启动服务器。客户端连接,我可以在onconnect事件上设置一个断点,程序就在那里。现在应该发生的是计时器已启用,然后每次跳闸我发送我的数据块。 (这至少在调试器中没有发生)
编译器强迫我为服务器添加onexecute事件,我现在不知道如何处理它。我尝试了一个空白事件,我尝试了一个虚拟读取。 在客户端。一旦有连接它就应该从别处复制一个读线程,并在数据块发生时读取它们。现在我没有进行任何错误检查或自动检测连接丢失和尝试重新连接。
我当然感谢任何帮助,无论是在开展这项工作还是提示如何处理角落案件。
感谢 罗伯特
服务器端这应该每77毫秒发送一个数据块 .................................................. ..................................
type
TForm8 = class(TForm)
SendButton: TButton;
SendWaveFormTimer: TTimer;
IdUDPClient1: TIdUDPClient;
IdTCPServer1: TIdTCPServer;
procedure SendWaveFormTimerTimer(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure IdTCPServer1Connect(AContext: TIdContext);
procedure IdTCPServer1Execute(AContext: TIdContext);
private
connectedto:TIdContext;
{ Private declarations }
public
{ Public declarations }
end;
var
Form8: TForm8;
procedure TForm8.IdTCPServer1Connect(AContext: TIdContext);
// this is not in the main ui thread and can't call showmessage
begin
connectedto:=acontext; // save the connected TIDcontext for use elsewhere?
self.SendWaveFormTimer.Enabled:=true; {set the send timer}
end;
procedure TForm8.SendWaveFormTimerTimer(Sender: TObject);
var tempbyte:tidbytes;
begin
tempbyte:=RawToBytes(WaveFormSample,sizeof(TWaveFormSample));
form8.connectedto.Connection.IOHandler.Write(tempbyte, sizeof(TWaveFormSample));
end;
procedure TForm8.IdTCPServer1Execute(AContext: TIdContext);
// again this in second thread
var recv:string;
begin
//I don't know what to put here I am not expecting anything right now
recv := AContext.Connection.Socket.ReadLn;
end;
客户端
type
TForm3 = class(TForm)
IdUDPServer1: TIdUDPServer;
Label1: TLabel;
IdTCPClient1: TIdTCPClient;
Button1: TButton;
procedure IdUDPServer1UDPRead(AThread: TIdUDPListenerThread;
const AData: TIdBytes; ABinding: TIdSocketHandle);
procedure FormActivate(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
TReadingThread = class(TThread)
protected
FConn: TIdTCPConnection;
procedure Execute; override;
public
constructor Create(ACon: TIdTCPConnection); reintroduce;
end;
type
TMyNotify = class(TidNotify)
private
recvd_block:TWaveFormSample;
protected
procedure DoNotify; override;
end;
var
Form3: TForm3;
Udp_message_ID:tmessageid;
UDp_WaveFormSample:twaveformsample;
ReadingThread: TReadingThread = nil;
implementation
constructor TReadingThread.Create(ACon: TIdTCPConnection);
begin
FConn := ACon;
inherited Create(False);
end;
procedure TForm3.IdTCPClient1Connected(Sender: TObject);
begin
readingthread.Create(IdTCPClient1);
readingthread.execute; //this must be wrong
end;
procedure tform3.Button1Click(Sender: TObject);
begin
IdTCPClient1.Connect; //this works on the other end
end;
procedure TReadingThread.Execute;
var
TCP_TWaveFormSample:twaveformsample;
AData: TIdBytes;
data_rdy:boolean;
MyNotify: TMyNotify;
begin
MyNotify := TMyNotify.Create;
MyNotify.Notify;
data_rdy:=false;
while not Terminated do
begin
FConn.IOHandler.CheckForDataOnSource(1000);
FConn.IOHandler.CheckForDisconnect;
if not FConn.IOHandler.InputBufferIsEmpty and not data_rdy then
begin
fconn.iohandler.ReadBytes(Adata,sizeof(TWaveFormSample));
Idglobal.BytesToRaw(AData, TCP_message_ID, sizeof(tmessageid)); //global load
Idglobal.BytesToRaw(AData, TCP_TWaveFormSample, sizeof(twaveformsample));
data_rdy:=true;
end; // data
If not Drawing and data_rdy then //make sure the other thread can take it
begin
MyNotify.recvd_block :=Udp_TWaveFormSample;
MyNotify.Notify;
data_rdy:=false;
end;
end;
end ;
procedure TMyNotify.DoNotify;
begin
waveformunit.writenewdata (recvd_block.WaveformIndex,recvd_block.WaveformData,
samples_per_send);
drawing:=false;
end;
答案 0 :(得分:5)
TIdTCPServer
是一个多线程组件。它的事件在工作线程中被触发。您的计时器不起作用,因为TTimer
是基于消息的计时器,并且这些线程中没有消息循环来为其提供服务。
您应该在服务器的OnExecute
事件中与客户端进行I / O工作,该事件在管理客户端连接的线程中触发,而不是在主UI线程中触发。
您在服务器端显示的所有内容都是错误的。尝试更像这样的东西:
interface
...
type
TForm8 = class(TForm)
IdTCPServer1: TIdTCPServer;
procedure FormCreate(Sender: TObject);
procedure IdTCPServer1Connect(AContext: TIdContext);
procedure IdTCPServer1Execute(AContext: TIdContext);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form8: TForm8;
implementation
type
TMyContext = class(TIdServerContext)
LastSend: TIdTicks;
end;
procedure TForm8.FormCreate(Sender: TObject);
begin
IdTCPServer1.ContextClass := TMyContext;
end;
procedure TForm8.IdTCPServer1Connect(AContext: TIdContext);
begin
TMyConext(AContext).LastSend := Ticks64;
end;
procedure TForm8.IdTCPServer1Execute(AContext: TIdContext);
var
Ctx: TMyContext;
temp: TIdBytes;
begin
Ctx := TMyContext(AContext);
if GetElapsedTicks(Ctx.LastSend) >= 77 then
begin
// grab the latest sample and send it...
temp := RawToBytes(Waveformsample, sizeof(TWaveFormSample));
AContext.Connection.IOHandler.Write(temp);
Ctx.LastSend := Ticks64;
end;
// in case the client sends something, just ignore it for now...
AContext.Connection.IOHandler.InputBuffer.Clear;
Sleep(0);
end;
话虽如此,由于您的服务器只需要一个客户端,您可能会考虑使用TIdSimpleServer
,而不是多线程,因此如果您愿意,可以从主UI线程运行它。但是,如果您想为多个客户提供服务,请坚持使用TIdTCPServer
。
在客户端,你所展示的一切也都是错的。您滥用TThread
,IOHandler
和TIdNotify
。尝试更像这样的东西:
interface
...
type
TForm3 = class(TForm)
IdTCPClient1: TIdTCPClient;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form3: TForm3;
implementation
type
TReadingThread = class(TThread)
protected
FConn: TIdTCPConnection;
procedure Execute; override;
public
constructor Create(ACon: TIdTCPConnection); reintroduce;
end;
TMyNotify = class(TIdNotify)
private
recvd_block: TWaveFormSample;
protected
procedure DoNotify; override;
end;
var
ReadingThread: TReadingThread = nil;
constructor TReadingThread.Create(ACon: TIdTCPConnection);
begin
FConn := ACon;
inherited Create(False);
end;
procedure TForm3.IdTCPClient1Connected(Sender: TObject);
begin
ReadingThread := TReadingThread.Create(IdTCPClient1);
end;
procedure Tform3.Button1Click(Sender: TObject);
begin
IdTCPClient1.Connect;
end;
procedure TReadingThread.Execute;
var
WaveFormSample: TWaveFormSample;
AData: TIdBytes;
MyNotify: TMyNotify;
begin
while not Terminated do
begin
FConn.IOHandler.ReadBytes(AData, sizeof(TWaveFormSample), False);
BytesToRaw(AData, WaveFormSample, sizeof(TWaveFormSample));
MyNotify := TMyNotify.Create;
MyNotify.recvd_block := WaveFormSample;
MyNotify.Notify;
end;
end;
procedure TMyNotify.DoNotify;
begin
// use recvd_block as needed...
end;