您正在ClientDataSet1变量中创建一个新实例,但表单上的其他组件都不会引用该实例。
这不是“缺少数据提供程序或数据包”错误消息的原因:为了找到该问题,您应该发布一个可重现的案例。
最简单的方式来获得可重现的情况下将会将是:
- 留两个TClientDataSets您的服务器上(ClientDataSet1和ClientDataSet2)
- 负荷使用提供的数据转换成ClientDataSet1在设计时这样
- 保存从ClientDataSet1到.CDS数据文件
- 装入.CDS文件到ClientDataSet2在设计时
- ClientDataSet2发送到您的客户端
如果它仍然重现,那么在某处发布该.pas/.dfm。 如果不能复制,则开始剪切部分,直到复制。
祝你好运!
--jeroen
编辑:我下载了你的源代码,并得到了他们在2009年德尔福
它包含的几个问题的工作,和突触库包含的问题为好。
大部分问题归结为不准确。 我已经有了一个模糊的感觉,基于你的源代码格式,你为你的东西使用的命名约定的组合,以及缺乏释放分配的对象。
之前我忘了:我做的第一件事是确保我能使用调试的DCU和禁用优化的编译器选项。这些是深入挖掘问题的宝贵设置。 我没有添加任何清理到您现有的代码,因为我希望它尽可能接近。 但我确实运行过一个源代码格式化程序,因此至少,然后块分别位于不同的行上。
让我们从发送代码开始。
我摆脱你的数据库的连接,复制ClientDataSet1从客户到服务器,并重构你的SServer单位,无论TTCPSocketDaemon和TTCPSocketThrd现在可以访问FClientDataSet:TClientDataSet
这让我有一种可重复的情况下,我以前问。
然后我开始运行客户端。 看来,LogThis(strmReply.Size);正在输出0(零!),所以它没有收到任何东西。
这让我再次查看服务器。 看来你使用分隔文本拆分传入的参数,但在那之后你在代替[0]指的sl.Names如果SL [0]。这在Delphi 2009中失败了,也可能在其他Delphi版本中出现。 除此之外,你不检查一个空小号,所以它每次出去后与列表索引不能越界的。
然后我添加了一些调试代码:我想看看实际发送了什么。 这使我使用XML流代替使用S_CLIENT.SaveToStream(strm,dfXMLUTF8);并将缓冲区复制到本地文件,以便我可以观看该文件。 该文件正常:它似乎是ClientDataSet的有效XML表示。
最后,我注意到,你在服务器客户端使用SendBuffer,并RecvStream。那些不匹配:你必须选择,所以要么在连接的两端使用缓冲区或流!我选择了流。
所以发送代码变成这样:
procedure TTCPSocketThrd.Execute;
var
s: string;
strm: TMemoryStream;
ADO_QUERY: TADOQuery;
DS_PROV: TDataSetProvider;
DS_CLIENT: TClientDataSet;
sl: TStringList;
adoconnstr: string;
CDSStream: TFileStream;
begin
CoInitialize(nil);
Sock := TTCPBlockSocket.Create;
adoconnstr := 'POST YOUR CONNECTION STRING HERE, IF TOO LONG adoconnstr := adoconnstr + ''nwestring''';
try
Sock.Socket := CSock;
sl := TStringList.Create;
Sock.GetSins;
with Sock do
begin
repeat
if terminated then
break;
s := RecvTerminated(60000, '|');
if s = '' then
Exit;
//Den Text mit Leerzeichen splitten zur besseren Verarbeitung
sl.Delimiter := ' ';
sl.DelimitedText := s;
LogThis(sl.Names[0]);
if sl[0] = 'getBENUds' then // jpl: not sl.Names[0] !!!!
begin
// //ini ADO_QUERY
// ADO_QUERY := TADOQuery.Create(Form1);
// ADO_QUERY.ConnectionString := adoconnstr;
// ADO_QUERY.SQL.Clear;
// ADO_QUERY.SQL.Add('SELECT * FROM BENU');
// ADO_QUERY.Open;
// LogThis('ADO_QUERY fertig');
// //ini DS_PROV
// DS_PROV := TDataSetProvider.Create(ADO_QUERY);
// DS_PROV.DataSet := ADO_QUERY;
// LogThis('DS_DSPROV fertig');
// //ini DS_CLIENT
// DS_CLIENT := TClientDataSet.Create(ADO_QUERY);
// DS_CLIENT.ProviderName := 'DS_PROV';
// DS_CLIENT.SetProvider(DS_PROV);
DS_CLIENT := FClientDataSet;
LogThis('DS_CLIENT fertig');
//DSCLIENTDATASET bauen
strm := TMemoryStream.Create;
DS_CLIENT.Open;
//DS_CLIENT.Open;
DS_CLIENT.SaveToStream(strm, dfXMLUTF8); // jpl: easier debugging than binary
strm.Seek(0, soBeginning);
SendStream(strm); // jpl: not SendBuffer(strm.Memory, strm.Size); !!!
strm.Seek(0, soBeginning);
CDSStream := TFileStream.Create('Server.cds', fmCreate);
CDSStream.CopyFrom(strm, strm.Size);
CDSStream.Free();
LogThis('gesendet');
end
else if sl[0] = 'validuser' then // jpl: not sl.Names[0] !!!!
begin
//do stuff
end;
if lastError <> 0 then
break;
until false;
Form1.Memo1.Lines.Add('down');
end;
finally
Sock.Free;
end;
end;
所以我去重温接收代码。 既然你已经登录strmReply。大小,我想知道你为什么没有在0(零)的特殊情况下它的反应,所以我加了它:LogThis(“收到空流”)
然后我开始调试,并发现那strmReply.Size仍然是0(零)每次。 所以我开始深入研究我最近一直在使用的Synapse代码(我拿了我已经包含在Habari组件中的副本)。 有我发现了两两件事:
- 在发送的流,它被编码在第一个4个字节
- 编码是在一个不同的字节顺序进行比解码的流的长度
这无疑是Synapse中的一个错误,所以请随时向他们报告。 结果是RecvStream不是的对应SendStream,但RecvStreamIndy是。
经过所有这些更改,它仍然无法正常工作。 原因是ClientDataSet1.LoadFromStream(strmReply);正在开始读取流中的当前位置(您可以自己检查;核心加载逻辑位于TCustomClientDataSet.ReadDataPacket)。 所以你似乎忘了加入strmReply.Seek(0,soBeginning);,我补充说,它突然工作。
所以接收代码是这样的:
procedure TForm1.btnConnectClick(Sender: TObject);
var
CDSStream: TFileStream;
begin
CSocket := TTCPBlockSocket.Create;
strmReply := TMemoryStream.Create;
ClientDataSet1 := TClientDataSet.Create(Form1);
try
// CSocket.Connect('10.100.105.174', '12345');
CSocket.Connect('127.0.0.1', '12345');
if CSocket.LastError = 0 then
begin
LogThis('verbunden');
CSocket.SendString('getBENUds|');
LogThis('''getBENUds|'' gesendet');
if CSocket.LastError = 0 then
begin
CSocket.RecvStreamIndy(strmReply, 50000); // jpl: this fails, because SendStream defaults to Indy: CSocket.RecvStream(strmReply, 50000);
LogThis(strmReply.Size);
if strmReply.Size = 0 then
LogThis('empty stream received')
else
begin
strmReply.Seek(0, soBeginning);
CDSStream := TFileStream.Create('Client.cds', fmCreate);
CDSStream.CopyFrom(strmReply, strmReply.Size);
CDSStream.Free();
strmReply.Seek(0, soBeginning); // jpl: always make sure that the stream position is right!
ClientDataSet1.LoadFromStream(strmReply);
ClientDataSet1.Open;
end;
end;
end;
except
on E: Exception do
ShowMessage(E.Message);
end;
CSocket.Free;
end;
到底这是不难解决您的问题。 最难的部分是发现约RecvStreamIndy,其余的只是清理你的代码,并精确地发生在什么时候:大部分时间都是这样。 在这种情况下,流处理需要您仔细观察流位置。
的问候,你的服务器源没有做它的
--jeroen
一部分。 – 2009-08-14 10:40:01
下载代码并解决了您的问题 – 2009-08-16 12:30:46