我的idTcpClient收到的数据是混乱的数据。麻烦各位富翁来看一看(200分)

  • 主题发起人 主题发起人 libra01
  • 开始时间 开始时间
L

libra01

Unregistered / Unconfirmed
GUEST, unregistred user!
我的idTcpClient收到的数据是混乱的数据。
怎么解决?
我只能应用流读写,因为包大小是不同的。

麻烦大家看一下,代码比较长。。谢谢了。。。
代码:

I'm sorry .The code is long.Thank you ....
The detail :
type definition:

代码:
T_PPTP_HEAD_tag = packed record
    Version: LongWord; 
    P_Type: LongWord; 
    Total_Length: LongWord; 
    Command_ID: LongWord; 
    Sequence_ID: LongWord;
end;//the packet head record

T_empty=record
end;//empty record

T_PPTP_Connect_tag = TEmpty; //the connect packet body is Empty

T_PPTP_Connect_REP_tag = TEmpty;//the connect reply packet body is empty too,

T_PPTP_Connect=packed record
    head:T_PPTP_Head_tag;
    body:T_PPTP_Connect_tag;
end;//the connect packet

T_PPTP_Connect_REP=packed record
    head:T_PPTP_head_tag;
    body:T_PPTP_Connect_REP_tag;
end;//the connect reply packet
***************************************
The server code:
OnConnect:
代码:
var
  pkt: T_PPTP_Connect;
  pktREP: T_PPTP_Connect_REP;
begin
    AThread.Connection.ReadBuffer(pkt, sizeof(pkt));
    if pkt.head.Command_ID = PPTP_Connect then //PPTP_connect is a integer number in my protocol,like PPTP_Connect_REP
        begin
         pktREp:=createPPTP_Connect_REP();//a function to create a pptp_connect_rep packet .just fill the command_id.
         AThread.Connection.WriteBuffer(pktREP, sizeof(pktREP));
        //Showmessage('a client connected!');
       end;
end;

//////////////////////////////////////
OnExecute:
代码:
var
  Adata: TmemoryStream;
  iCmd: integer;
  Head: T_PPTP_Head_tag;
  pktConnectREP:T_PPTP_Connect_REP;
begin
    while AThread.Connection.Connected do
    begin
      Adata := TmemoryStream.Create;
      try
        Adata.Clear;
        Adata.Position := 0;
        AThread.Connection.ReadStream(Adata, -1, false);
        Adata.Position := 0;
        Adata.Read(Head, sizeof(head));//I have many packets in my protocol,so I can't readbuffer..
        iCmd := Head.Command_ID;//Get the command_id
        Adata.Position := 0;
        if iCmd=PPTP_Connect then//PPTP_connect is a integer number in my protocol,like PPTP_Connect_REP
            begin
                pktConnectREP:=createPPTP_Connect_REP();
                AThread.Connection.WriteBuffer(pktConnectREP, sizeof(pktConnectREP), false);
            end;
      finally
        Adata.Free;
      end;
    end;    
end;

*******************************************
The Client Code:
//////////////////////
The "Connect" button OnClick(Sender:TObject);
代码:
var
pktConnect:T_PPTP_Connect;
begin
      TcpClient.Connect();
      pktConnect := createPPTP_Connect;//create a packet the command_id is PPTP_Connect;
      TcpClient.WriteBuffer(pktConnect, sizeof(pktConnect));
      TcpClient.ReadBuffer(pktConnectREP, sizeof(pktConnectREP));
      if pktConnectREp.head.Command_ID = PPTP_Connect_REP then
       Showmessage('Receive Connect REp packet');//////////////////the data is True, I can get the reply and I can 
                                                 //////////////////know the connection is established and OK.
end;

///////////////////////
The "Send PPTP_Connect" button OnClick(Sender:TObject);
代码:
var
  pktConnect, pktTemp: T_PPTP_Connect;
  pktConnectREP: T_PPTP_CONNECT_REP;
  Adata: TmemoryStream;
  Head: T_PPTP_HEAD_tag;
  iCmd: LongWord;
begin
  if not TCPClient.Connected then exit;//if not connected then exit;

  pktConnect := createPPTP_Connect();//create a pptp_connect packet...and the command_id is PPTP_Connect
  Adata := TmemoryStream.Create;
  try
    try
      Adata.Position := 0;
      Adata.Write(pktConnect, sizeof(pktConnect));
      Adata.Position := 0;
      TcpClient.WriteStream(Adata, true, true, 0);//write the packet ,
      Adata.Position := 0;
      ////////////////////////////////////////
      TCPClient.ReadStream(Adata, -1, false);     //////Read a stream....or Readbuffer ...both methods didn't work well.
//      tcpClient.ReadBuffer(Head, sizeof(Head));///////////but receive not a packet ,I'm sure that the server send a PPTP_Connect_REP packet but client didn't receive it correctly....

      Adata.Position := 0;
      Adata.Read(Head, sizeof(head));
      iCmd := Head.Command_ID;
      Adata.Position := 0;
      ShowMessage(format('Protocol:%s%sVersion:%d%sP_Type:%d%sTotal_length:%d%sCommand_id:%d%ssequence_id:%d',
        [ResultCommandString(iCmd), Char(13), Head.Version, Char(13), Head.P_Type, Char(13), Head.Total_Length, Char(13), Head.Command_ID, Char(13), Head.Sequence_ID]));//the message is not correct........I 'm puzzled......Help!!!
    except
      on e: exception do
      begin
        Showmessage('OnExecute Exception: [' + E.ClassName + ']: ' + E.Message);
      end;
    end;
  finally
    Adata.Free;
  end;
end;    
end;


*******************************That's all.thank you ....I'm pleasure you reply and I need your help ..Thank you very much..
 
服務器端Execute過程中使了AThread.Connection.ReadStream(Adata, -1, false);
你的AReadUntilDisconnect參數為False,那麼服務器一定要先發送字節數(Integer型)
你確實也發送了節字數,但是你在
Adata.Position := 0;
TcpClient.WriteStream(Adata, true, true, 0);//write the packet
這里面第三個參數設為True,實際上又發送了一次字節數,呵呵,設為False吧,
或者將
Adata.Position := 0;
Adata.Write(pktConnect, sizeof(pktConnect));
這兩句去掉.
祝你好運~~
 
你好。谢谢smokingroom,的回复。
我按照你的方法试了。还是不行。
但我在发送的时候(服务器)不用writebuffer
改用Athread.Connection.Writestream(Adata,true,true,0);(前面用write把pktconnectrep写入)
客户收改用ReadStream(Adata,-1,false);(然后再判断head部分)
这样呢。。。。
可是可以。。。但出现新问题,第一次请求pptp_connect,得到的是一个不正确的包,第一个字节是随机数。后面的依次排开。。
第二次请求及以后请求均得到正确结果。。。。。

请问这种情况如何避免?
即第一次请求不正确,以后却正确了。。。。
 
对不起,经过测试,第一个字节是该包的长度。
我想这是因为您说的writestream第三个参数是true的原因。
因此先发长度,再发包的内容。

但是第二次我调试跟踪收到的信息里并没有这个长度了。。请问这是什么原因。
 
用一问一答方式好了,效率跟流一样,但控制更方便!
 
对,一问一答


根据第一个包定义的长度,取第二个包


 
如果不能用 buffer,那也就不能用流了
你读一个 stream,其实和读一个buffer是一样的
也要规定好大小,否则就无法读的正确

另外,我在用的时候,发现除了TStringStream,其他的流都
无法正常发收,不知道是怎么回事。
 
我用的一切正常,读写流的操作。
发送
try
FStream:=TMemoryStream.Create;
FSTream.Position:=0;
DYZP(StrToInt(SelPNum(ZPCommand,1,';')),StrToInt(SelPNum(ZPCommand,2,';')),StrToInt(SelPNum(ZPCommand,3,';')),FStream);
AThread.Connection.OpenWriteBuffer;
AThread.Connection.WriteStream(FStream);
AThread.Connection.CloseWriteBuffer;
finally
FreeAndNil(FStream);
AThread.Connection.Disconnect;
idTCPLog.Lines.Append('正在传送图片W='+SelPNum(ZPCommand,1,';')+'H='+SelPNum(ZPCommand,2,';')+'CQ='+SelPNum(ZPCommand,3,';')+'.....');
end;

接收
try
FStream:=TMemoryStream.Create;
while connected do
begin
ReadStream(FStream,-1,True);
// Memo1.Lines.Add('已经收到数据:'+IntToStr(FStream.Size));
end;
finally
FSTream.Position:=0;
Memo1.Lines.Add('接收数据大小为:'+IntToStr(FStream.Size));
if FStream.Size<>0 then
begin
Form1.ZPScrImage.Picture.Graphic.LoadFromStream(FStream);
// Form1.ZPScrImage.Picture.Graphic.LoadFromFile(ExtractFileDir(ParamStr(0)) + '/ServerScreen.bmp');
end;
FreeAndNil(FStream);
Disconnect;

end;
 
to libra01:
應該還是ReadStream與WriteStream對應問題.
TCPClient.ReadStream(Adata, -1, false);
服務器應該對應發送字節數.
 
直接幫你改代碼
****************Server端***************
OnExecute:

var
Adata: TmemoryStream;
iCmd: integer;
Head: T_PPTP_Head_tag;
pktConnectREP:T_PPTP_Connect_REP;
begin
while AThread.Connection.Connected do
begin
Adata := TmemoryStream.Create;
try
AThread.Connection.ReadStream(Adata, -1, false);
Adata.Position := 0;
Adata.Read(Head, sizeof(head));
iCmd := Head.Command_ID;
Adata.Position := 0;
if iCmd=PPTP_Connect then
begin
pktConnectREP:=createPPTP_Connect_REP();
//以下這句發送數據長度,以便客戶端使用ReadStream讀取
AThread.Connection.WriteInteger(SizeO(pktConnectREP),True); //AConvert為True
AThread.Connection.WriteBuffer(pktConnectREP, sizeof(pktConnectREP), false);
end;
finally
Adata.Free;
end;
end;
end;

***************Client端*************

The "Send PPTP_Connect" button OnClick(Sender:TObject);

var
pktConnect, pktTemp: T_PPTP_Connect;
pktConnectREP: T_PPTP_CONNECT_REP;
Adata: TmemoryStream;
Head: T_PPTP_HEAD_tag;
iCmd: LongWord;
begin
if not TCPClient.Connected then exit;//if not connected then exit;
pktConnect := createPPTP_Connect();
Adata := TmemoryStream.Create;
try
try
Adata.Position := 0;
Adata.Write(pktConnect, sizeof(pktConnect));
Adata.Position := 0;
TcpClient.WriteStream(Adata, true,true,0);
AData.Clear; //應該有必要
TCPClient.ReadStream(Adata, -1, false);
Adata.Position := 0;
Adata.Read(Head, sizeof(head));
iCmd := Head.Command_ID;
Adata.Position := 0;
ShowMessage(format('Protocol:%s%sVersion:%d%sP_Type:%d%sTotal_length:%d%sCommand_id:%d%ssequence_id:%d',
[ResultCommandString(iCmd), Char(13), Head.Version, Char(13), Head.P_Type, Char(13), Head.Total_Length, Char(13), Head.Command_ID, Char(13), Head.Sequence_ID]));
except
on e: exception do
begin
Showmessage('OnExecute Exception: [' + E.ClassName + ']: ' + E.Message);
end;
end;
finally
Adata.Free;
end;
end;
end;
 
感谢各位的关注。。。。。
刚才打了许多。但由于五笔加加的问题,都不见了。妈的。

感谢smokingroom的提醒。
感谢PIAO40993470提供的代码。

我已解决此问题,问题出现在协议定义部分,在客户端有一个没有贴上来的变量
pktConnectREp的类型变成了T_PPTP_connect,而正确的T_PPTP_Connect_REP恰比pktconnect多了一个字节。。。因此收发后,剩下一个不正常的数。。。因此呢。。造成了失误。。

我证明了:我的服务端代码完全正确。。。客户端excute,send_pptp_)connect代码正常。
唯一错误的是客户的connect.类型定义错误(这里没有粘出来)

这个问题搞了我一天一晚。今天弄了半天的PHP系统,晚上才拿出来看,终于看出眉目。。。。

谢谢各位,希望看这篇贴子的人不要重复我的错误。。
做网络程序一定要小心你的数据类型,少一个字节,多一个字节会造成特别大的错误。。
 
多人接受答案了。
 
呵呵。。我写程序时也经常被 点小错误,搞得折腾N多时间。
昨天在用indy9的FTP控件写个上传的断点续传的程序时就被一个简单的属性问题,写了N种方案的代码。最后又研究自己写的第一种方案时,改了个属性就一切OK了,而且不到10行代码,自己坐在电脑前都哭笑不得,自己否决了自己想出的最好的方案,只因一个小小的错误而浪费时间写了N个又臭又长的方案。。((当时真有一种拿头撞墙的冲动
 
后退
顶部