现在的位置: 首页 > 综合 > 正文

关于idtcpserver收包错位的问题

2013年08月25日 ⁄ 综合 ⁄ 共 2259字 ⁄ 字号 评论关闭
想用idtcpserver做一个主站软件,接受远程终端通过GPRS功能发送的报文。
在IdTCPServerExecute里用AThread.connection.ReadLn读接收到的报文,发现收包全部错位了,相当于是上一条报文的一半和下一条报文的一半被组成一个包收。每条报文都被分割成两半然后分别和上下条报文的一半再去组成新包。
是不是因为ReadLn用回车符判断包的结尾,所以报文里一旦出现0D 0A就会认为这个包已经收完?可能这种更适合于ASCII的传输而不适合这种报文的传输。
应该怎样解决这个问题呢?还是不能用ReadLn而要用其他方法来收?菜鸟刚接触Delphi,急盼指教,多谢!
 
 回复内容
【belllab】:
readln确实是判断是否有0D 0A,有就是一行结束了
如果你的数据内有0D 0A出现,那就建议用SendBuf这种方式来发送(packed)

【Kalibu】:
很感谢你的解答。
现在的关键问题是接受,如果发送你说建议用sendbuffer,那么接受用readbuffer么?请问你知道有什么相关的例子程序么?因为以前没用过这个,不清楚它的机制和用法,自己用了一下readbuffer发现会把每个长帧分成几个短帧了,不知道这个是什么原因呢?
因为任务急,我又初次用这个很茫然,希望各位不吝赐教,谢谢啦!^_^

【belllab】:
一般的发送包体的这种方式,都是有包头的,包头很简单,一般就是需要读取的包的大小,取了包头之后,就按包头里面的大小来取包体。
例如:
THeader=record(
    Total_Length:UInt;         //消息总长度(含消息头及消息体)
    Command_ID  :UInt;           //命令标识
    Sequence_ID :UInt;          //消息流水号,顺序累加,步长为1,循环使用
  end;
)
ReadBuffer(Header,SizeOf(THeader))//取包头,
ReadBuffer(Body,Header.Total_Length-SizeOf(THeader));//根据包头取包体

【Kalibu】:
多谢解答!
请问那个包头THeader是自己定义的么?是不是要像你例举的Theader那样根据自己报文的协议定义这么一个record,每次先读包头,然后从包头里找出长度再读到我要的缓冲区里?
我现在的程序是:
procedure TTCP_Client.IdTCPServerExecute(AThread: TIdPeerThread);
var
  connected: boolean;
  aIn:array[0..2047] of Byte;
  i,ilen: integer;
begin
      connected:= true;
      for i:=0 to 2047 do
        aIn[i]:=0;
      AThread.Connection.ReadFromStack;
      ilen := AThread.Connection.InputBuffer.Size;

      if   ilen<>0   then
      begin
        AThread.Connection.ReadBuffer(aIn,ilen);
      end;
end;
这种根据AThread.Connection.InputBuffer.Size来读是不是不对?
另外在这个IdTCPServerExecute在ReadBuffer之前还要作其他动作么?我查help里的ReadBuffer他说要用ReadFromStack从而保证读到的buufer里至少有已经定义的size长度的数据,可是我用了上面写的程序很容易死在那里,出现错误,是不是我的用法还是不对呢?

太菜了,不好意思这么多疑问。

【belllab】:
你之种读法不是太好,很容易出现合包
THeader是自定义的,里面就包含这个包有多大,
然后再读取指定的大小,这样,就不会读多或读少

【sanmaotuo】:
其实你定义好你的传送包数据结构(通常定义为Record),然后直接传送记录就可以了.给你一个我的实例.

注意,在定义RECORD的域类型是STRING时,设计定长为最大长度255, 如果不够就用定义ARRAY STRING.

TArrayString = array[0..99] of String[255]

TClient = packed record
    Name: string[50];
    Time: string[50];
    Host: string[50];
    IP: string[50];
    MAC: string[50];
    Msg: TArrayString;
  end;
  PTClient = ^TClient;

......写
  IdTCPClient.WriteBuffer(FClientSend, SizeOf(FClientSend), True);

......读
  AThread.Connection.ReadBuffer(Client, SizeOf(Client));

【Kalibu】:
那么ReadFromStack该怎么用呢?是否可以用它的返回值来判断是不是已经收到我需要的字节数,比如先判断是不是有收到足够字节的包头,然后再把包头读到buffer里?

 

抱歉!评论已关闭.