小弟我用TIdTcpClient和TIdTcpServer传递XML数据,在TIdTcpClient向TIdTcpServer传递时没有问题,但是TIdTcpServer向TIdTcpClient 传递时,如果XML中节点的属性过多时,TIdTcpClient只接收了一部分数据,就会报错;还有就是因为XML不能传递中文字符,我就用Base64Encoder进行了编码,但是编码后的字符串比较长,TIdTcpClient也只能接收了一部分数据。不知道是为什么~~!有那位大哥知道的告诉一下,因为我没有长时间上这个,没有积分相送,不好意思~~!谢谢
解决方案 »
- 请教:ADOQuery1 的使用,谢谢~!
- 有关ADOquery的问题
- ★★★★★祝大家春节快乐,新年快乐[大散分]★★★★★
- 请问高手怎么实现 ADO+DbGrid实现数据的统一提交?
- 高手请帮忙,窗体调用问题!谢了~
- 怎样通过adoquery向listbox加入字段名?
- DBGrid中一个字段的一行记录的长度太长,在Qreport用QRDBText自动换行不理想?
- ACCESS97和ACCESS2000的问题??急,敬请关注!!
- 在线等待,写条SQL语句
- 第一次连接InterBase时特别的慢(5-10分钟)
- 这个复杂的sql语句怎么写呢?
- delphi 实现报表打印问题 不能调用QuickRep
看看这个demo吧
我已经转换的是TMemoryStream。而且client to server 时没有问题~~!
To:hihihi
文件也不大的~~~!
下面是自己的XML编码。是登录的数据,没有参数,数据返回,只有登录结果在SwapData 的rstint和rststr中返回结果
tmpXml.XML.Add('<?xml version="1.0"?>');
tmpXml.XML.Add('<SwapData CommandID="1000" ReturnType="" RstInt="1" RstStr="Success!">');
tmpXml.XML.Add(' <BaseParam>');
tmpXml.XML.Add(' <WaitingFormHandle Value=""/>');
tmpXml.XML.Add(' <WaitFormHandle Value=""/>');
tmpXml.XML.Add(' </BaseParam>');
tmpXml.XML.Add(' <SubmitParam>');
tmpXml.XML.Add(' <UserID Value="" ParamType="ftstring"/>');
tmpXml.XML.Add(' <Password Value=""/>');
tmpXml.XML.Add(' <UserType Value=""/>');
tmpXml.XML.Add(' </SubmitParam>');
tmpXml.XML.Add(' <ReturnParam>');
tmpXml.XML.Add(' </ReturnParam>');
tmpXml.XML.Add(' <ReturnData>');
tmpXml.XML.Add(' </ReturnData>');
tmpXml.XML.Add('</SwapData>');
这是我以前写过的一个为idtcpclient添加接收数据线程的一个组件,你新建一个package,把这个文件加入进去,然后编译安装,在你的组件面板里面会出现一个
ldx组件页,使用里面的TLdxTCPClient组件里的DataAvailable事件,看看效果吧,good luck!
unit LdxTCPClient;interfaceuses
Classes, SysUtils, IdGlobal, IdStack, IdTCPClient, IdTCPConnection;type
TTCPClientReader = class; TLdxTCPClient = class(TIdTCPClient)
private
FTCPClientReader: TTCPClientReader;
FOnDataAvailable: TNotifyEvent;
procedure DoDataAvailableEvent;
public
procedure Connect(const ATimeout: Integer = IdTimeoutDefault); override;
procedure Disconnect; override;
published
property OnDataAvailable: TNotifyEvent read FOnDataAvailable write FOnDataAvailable;
end; TTCPClientReader = class(TThread)
protected
FTCPClient: TLdxTCPClient;
InpLastSize: Integer;
public
constructor Create(LdxTCPClient: TLdxTCPClient);
procedure Execute; override;
end;
procedure Register;
implementation{ TTCPClient }procedure TLdxTCPClient.Connect(const ATimeout: Integer);
begin
inherited Connect(ATimeout);
if Connected then
FTCPClientReader := TTCPClientReader.Create(Self);
end;procedure TLdxTCPClient.Disconnect;
begin
if Assigned(FTCPClientReader) then FTCPClientReader.Terminate;
inherited Disconnect;
end;procedure TLdxTCPClient.DoDataAvailableEvent;
begin
if Assigned(FOnDataAvailable) then FOnDataAvailable(Self);
end;{ TTCPClientReader }constructor TTCPClientReader.Create(LdxTCPClient: TLdxTCPClient);
begin
inherited Create(False);
InpLastSize := 0;
FTCPClient := LdxTCPClient;
FreeOnTerminate := True;
end;procedure TTCPClientReader.Execute;
var
InpSize: Integer;
begin
while (not Terminated) and (FTCPClient.Connected) do
begin
try
InpSize := FTCPClient.InputBuffer.Size;
if (InpSize = 0) or (InpSize = InpLastSize) then
InpLastSize := InpSize + FTCPClient.ReadFromStack(False, -1, False);
FTCPClient.CheckForDisconnect(False, True);
if FTCPClient.Connected then
Synchronize(FTCPClient.DoDataAvailableEvent);
except
if FTCPClient.Connected then FTCPClient.Disconnect;
Terminate;
end;
end;
end;
procedure Register;
BEGIN
RegisterComponents('LDX',[TLdxTCPClient]);
END;end.
我自己写好了接收线程,可以接收数据的,如果XML中节点的属性不多时,或是值的字符串不长时是没有问题的,比如我的XML编码中password用Base64Encoder编码后比较长时 ,从server to client 时,client接收时就会有问题,好像整个memorystream数据只接收到一部分,但是password值不长的时候是没有问题的,可以接收。To:unsigned
我也不知道是为什么啊,要是因为线程的编码问题我也知道怎么处理了。
上面5楼说过了,是你发送接收方面的问题,和XML什么的没关系。
可能你的网络不顺畅或者文件稍大一点,一次性发送出去,接收可能产生几次,每次都是不完整的,要自己处理一下接收的包,合并成一个完整的才行。
也有可能,你发送端发送几次数据,接收端只产生一次,一次就接收了几包,同样要处理,分解成几个包来处理。
下面的文件我想被传回不用被分成二次以上回传吧?tmpXml.XML.Add(' <?xml version="1.0"?>');
tmpXml.XML.Add(' <SwapData CommandID="1000" ReturnType="" RstInt="1" RstStr="Success!">');
tmpXml.XML.Add(' <BaseParam>');
tmpXml.XML.Add(' <WaitingFormHandle Value=""/>');
tmpXml.XML.Add(' <WaitFormHandle Value=""/>');
tmpXml.XML.Add(' </BaseParam>');
tmpXml.XML.Add(' <SubmitParam>');
tmpXml.XML.Add(' <UserID Value="" ParamType="ftstring"/>');
tmpXml.XML.Add(' <Password Value=""/>');
tmpXml.XML.Add(' <UserType Value=""/>');
tmpXml.XML.Add(' </SubmitParam>');
tmpXml.XML.Add(' <ReturnParam>');
tmpXml.XML.Add(' </ReturnParam>');
tmpXml.XML.Add(' <ReturnData>');
tmpXml.XML.Add(' </ReturnData>');
tmpXml.XML.Add(' </SwapData>');
不要这么肯定,被不被二次以上回传是看不出的,和网络状况有关系,你无法确定会不会。
Tcp/ip连接,不会丢失数据的。既然少数据肯定是接收的问题,不关XML啥事。要么就是接收到了,你处理的问题,用了String方式处理,把password的转换后的#0当成了结尾。
if not AThread.Terminated and AThread.Connection.Connected then
begin
DataStream := TMemoryStream.Create ;
try
AThread.Connection.ReadStream(DataStream,AThread.Connection.ReadInteger,false);
DataStream.Seek(0,soBeginning);
except
exit;
end;
FillList1 := TFillListView.Create ;
FillList2 := TFillListView.Create ;
HostName := AThread.Connection.LocalName ;
HostIP := AThread.Connection.Binding.IP;
if DataStream.Size >0 then
begin
rstint :=1;
OpenXML := true;
CoInitialize(nil);
XmlData := TXMLDocument.Create(nil);
XmlData.xml.LoadFromStream(DataStream);
try
XmlData.Active := true ;
except
XmlData.XML.Clear;
XmlData.XML.Add('<?xml version="1.0"?>');
XmlData.XML.Add('<SwapData CommandID="0000" ReturnType="0" RstInt="" RstStr="">');
XmlData.XML.Add('</SwapData>');
XmlData.Active := true;
rstint := 0;
rststr := Base64Encoder('接收网络数据错误,请重试所有操作!'); ;
end;
if rstint = 1 then
begin
UserID := XmlData.DocumentElement.Attributes['UserID'];
CommandID := XmlData.DocumentElement.Attributes['CommandID'];
end;
if rstint = 1 then
begin
i:= Clients.LockList.IndexOf( PClient(AThread.Data ) );
Clients.UnlockList ;
if (i < 0) and (CommandID<> '1000') then
begin
rstint := 0;
rststr := Base64Encoder('请先登录后再进行其他操作!');
end;
end ;
if (rstint=1) then
begin
try
tmpStoredProcude1 := TADOStoredProc.Create(nil);
tmpStoredProcude1.Connection := acConn;
tmpStoredProcude1.ProcedureName := 'usp_GetProcedureName';
tmpStoredProcude1.Parameters.Refresh;
tmpStoredProcude1.Parameters[1].Value := CommandID;
tmpStoredProcude1.open;
ProcedureName := trim(tmpStoredProcude1.Fields[0].AsString ) ;
ReturnType := tmpStoredProcude1.Fields[1].AsInteger ;
tmpStoredProcude1.Close;
tmpStoredProcude1.Free;
XmlData.DocumentElement.Attributes['ReturnType']:= ReturnType;
tmpStoredProcude2 := TADOStoredProc.Create(nil);
tmpStoredProcude2.Connection := acConn;
except
rstint :=0;
rststr := Base64Encoder('数据连接错误!');
end;
end;
if (rstint=1) then begin
if FillSubmitParam( XmlData, tmpStoredProcude2,ProcedureName, ReturnType) then
begin
rstint := tmpStoredProcude2.Parameters.parambyname('@rstint').Value ;
rststr := tmpStoredProcude2.Parameters.parambyname('@rststr').Value;
end
else
begin
rstint := 0 ;
rststr := Base64Encoder('提交的参数错误,请重试!');
end ;
end;
if ((returntype = 1 ) or (returntype = 3 )) and (rstint=1) then
if not FillReturnParam(XmlData, tmpStoredProcude2) then
begin
rstint := 0;
rststr := Base64Encoder('返回的参数错误,请重试!');
end; if ((returntype = 2 ) or (returntype = 3 )) and (rstint=1) then
if not FillReturnData(XmlData, tmpStoredProcude2) then
begin
rstint := 0;
rststr := Base64Encoder('返回的数据错误,请重试!');
end;
// rststr := 'Success!';
if (commandid ='1000') and (rstint=1) then
begin
Addclient(AThread,Userid);
FillList2.Thread := AThread;
FillList2.VData := vararrayof([userid,HostName+'('+HostIP+')',inttostr(port),datetimetostr(now),inttostr(AThread.ThreadID ),'连接登录']);
FillList2.FListView := ConnectionList;
FillList2.Resume ;
end;
XmlData.DocumentElement.ChildNodes.Delete('SubmitParam');
XmlData.DocumentElement.Attributes['RstInt'] := rstint;
XmlData.DocumentElement.Attributes['RstStr'] := Base64Encoder(rstStr);
DataStream.SetSize(0);
XmlData.XML.SaveToStream(DataStream);
AThread.Connection.OpenWriteBuffer;
AThread.Connection.WriteStream(DataStream,true,true);
AThread.Connection.CloseWriteBuffer;
XmlData.Active := false;
CoUnInitialize;
end
else
begin
rstint := 0;
rststr := Base64Encoder('无命令!');
CommandID :='Error!';
end;
FillList1.VData := vararrayof([userid,HostName+'('+HostIP+')',datetimetostr(now),CommandID , inttostr(rstint) +','+ rststr]);
FillList1.FListView := ListView1;
FillList1.Resume ;
FreeAndNil(DataStream);
end;
while (not Terminated) do
begin
rstint := 0;
if not FrmMain.tcConn.Connected then
begin
Terminate ;
exit;
end;
try
i:=2;
StreamData.SetSize(0);
FrmMain.tcConn.ReadStream(GetStreamData,FrmMain.tcConn.ReadInteger ,false);
GetStreamData.Seek(0,soBeginning);
GetStreamData.SaveToFile('asdf.xml');
if GetStreamData.Size =TotalSize then
begin
CoInitialize(nil);
tmpXml := TXMLDocument.Create(nil);
tmpXml.XML.LoadFromStream(GetStreamData);
try
tmpXml.Active := true;
rstint := tmpXml.DocumentElement.Attributes['RstInt'] ;
commandid := tmpXml.DocumentElement.Attributes['CommandID'];
// rststr := Base64Decoder(tmpXml.DocumentElement.Attributes['RstStr']);
rststr := tmpXml.DocumentElement.Attributes['RstStr'];
WaitingFormHandle := tmpXml.DocumentElement.ChildNodes[0].ChildNodes[0].Attributes['Value'];
WaitFormHandle := tmpXml.DocumentElement.ChildNodes[0].ChildNodes[1].Attributes['Value'];
PostMessage(WaitingFormHandle,wm_Result,rstint,WaitFormHandle);
finally
tmpXml.Active := false;
end;
CoUnInitialize;
GetStreamData.SetSize(0);
end;
except
end;
end;