unit Unit1;interfaceuses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, DB, Grids, DBGrids, StdCtrls, ADODB, IdTCPServer,
  IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient;type
  Tuser = record
  s_id:array[0..50] of string;
  s_name:array[0..50] of string;
  s_age:array[0..50] of string;
  s_text:array[0..50] of string;
  dt_date:array[0..50] of TDateTime;
end;  TForm1 = class(TForm)
    ADOConnection1: TADOConnection;
    Button1: TButton;
    DBGrid1: TDBGrid;
    DataSource1: TDataSource;
    Memo1: TMemo;
    IdTCPClient1: TIdTCPClient;
    IdTCPServer1: TIdTCPServer;
    ADOQuery1: TADOQuery;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure IdTCPServer1Execute(AThread: TIdPeerThread);
  private
    { Private declarations }
  public
    { Public declarations }
  end;var
  Form1: TForm1;
  strm: TMemoryStream;
  //user:Tuser;
implementation{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);
  var i:integer; user:Tuser;
begin
  strm:= TMemoryStream.Create;  ADOQuery1.First;
  while not ADOQuery1.Eof do
  begin
    for i:= 1 to ADOQuery1.RecordCount do
    begin
      user.s_id[i-1]:= ADOQuery1.FieldByName('i_id').AsString;
      user.s_name[i-1]:= ADOQuery1.FieldByName('vc_name').AsString;
      user.s_age[i-1]:= ADOQuery1.FieldByName('vc_age').AsString;
      user.s_text[i-1]:= ADOQuery1.FieldByName('vc_text').AsString;
      user.dt_date[i-1]:= ADOQuery1.FieldByName('dt_date').AsDateTime;
      ADOQuery1.Next;
    end;
  end;  strm.WriteBuffer(user,sizeof(Tuser));  self.IdTCPClient1.Host:='127.0.0.1';
  self.IdTCPClient1.Port:=9999;
  try
    self.IdTCPClient1.Connect(5000);
    //self.IdTCPClient1.Writebuffer(strm,sizeof(strm));
    self.IdTCPClient1.WriteStream(strm,true,False);
    self.IdTCPClient1.Disconnect;
  except
    on e:exception do
      memo1.Lines.Add(e.Message);
  end;  strm.Free;
end;procedure TForm1.FormCreate(Sender: TObject);
begin
  with ADOQuery1 do
  begin
    Close;
    SQL.Clear;
    SQL.Add('select * from sy');
    Open;
  end;
  
  self.IdTCPServer1.DefaultPort:=9999;
  self.IdTCPServer1.Active:= true;
end;procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread);
var
  i:integer; user:TUser;
begin
  strm:= TMemoryStream.Create;  with AThread.Connection do
  begin
    AThread.Connection.ReadStream(strm,-1,FALSE);// 跟踪:strm显示为strm(),证明数据没过来
    strm.ReadBuffer(user,sizeof(TUser));
    memo1.Lines.Add(user.s_id[1]); //没有看到user.s_id[1]的数据
  end;
end;end.不知道具体应该怎么改,谢谢大家。

解决方案 »

  1.   

    Server端ReadStream前先Read四个字节,比如使用ReadInteger之类的,然后再根据这四个字节ReadStream.接着又是Read四个字节,ReadStream...依此类推.
      

  2.   

    那我是不是可以直接设置strm.Position:= 4;挪到第4个字节然后开始读,可是还是没效果。你说的用 readinteger 能再具体一些么?
    或者会不会是我写的时候哪里出错了?没有写进去。
      

  3.   

    我试验了 如果中间不用TMemoryStream的话 client端直接用self.IdTCPClient1.Writebuffer(user,sizeof(Tuser)); server端用AThread.Connection.ReadBuffer(user,sizeof(TUser)); 这样的话数据是可以读出来的。但是老是报AV的错误,实在是头疼
      

  4.   

    当然不是.
    WriteStream(Stream,true,true (*注意这个参数,它实际了先发送四个字节作为后续Stream的实际长度,就形成了一个简单的网络协议*))因此,你只需要在接收端先接收4个字节作为长度,然后再根据这个长度来接收后续数据即可.个人建议楼主加深点网络编程方面的基础知识,先了解什么是TCP流协议.
      

  5.   

    你在传送string的时候,服务器端无法知道你传送的总字节数是多少。
    楼上说的是一个办法。
    另外可以将string改为固定长度,比如string[200]。另外Tdatetime也是传不了的,也用字符串传送吧
      

  6.   

    谢谢unsigned 和 supertitan001 的帮助和指点。我理解后编译如下代码,不知是否正确 还请指点。unit Unit1;interface uses 
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
      Dialogs, DB, Grids, DBGrids, StdCtrls, ADODB, IdTCPServer, 
      IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient; type 
      Tuser = record 
      s_id:array[0..50] of string; 
      s_name:array[0..50] of string; 
      s_age:array[0..50] of string; 
      s_text:array[0..50] of string; 
      //dt_date:array[0..50] of TDateTime;
    end;   TForm1 = class(TForm) 
        ADOConnection1: TADOConnection; 
        Button1: TButton; 
        DBGrid1: TDBGrid; 
        DataSource1: TDataSource; 
        Memo1: TMemo; 
        IdTCPClient1: TIdTCPClient; 
        IdTCPServer1: TIdTCPServer; 
        ADOQuery1: TADOQuery; 
        Button2: TButton; 
        procedure Button1Click(Sender: TObject); 
        procedure FormCreate(Sender: TObject); 
        procedure IdTCPServer1Execute(AThread: TIdPeerThread); 
      private 
        { Private declarations } 
      public 
        { Public declarations } 
      end; var 
      Form1: TForm1; 
      strm: TMemoryStream; 
      //user:Tuser; 
    implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); 
      var i:integer; user:Tuser; cmd:string;
    begin
      ADOQuery1.First;
     
      //赋值
      while not ADOQuery1.Eof do 
      begin 
        for i:= 1 to ADOQuery1.RecordCount do 
        begin 
          user.s_id[i-1]:= ADOQuery1.FieldByName('i_id').AsString; 
          user.s_name[i-1]:= ADOQuery1.FieldByName('vc_name').AsString;
          user.s_age[i-1]:= ADOQuery1.FieldByName('vc_age').AsString;
          user.s_text[i-1]:= ADOQuery1.FieldByName('vc_text').AsString;
          //user.dt_date[i-1]:= ADOQuery1.FieldByName('dt_date').AsDateTime;
          ADOQuery1.Next; 
        end; 
      end;
      strm:= TMemoryStream.Create;
      strm.WriteBuffer(user,sizeof(Tuser));  IdTCPClient1.Host:='127.0.0.1';
      IdTCPClient1.Port:=9999;
      try
        self.IdTCPClient1.Connect(5000);
        IdTCPClient1.WriteLn(IntToStr(strm.Size)); //向服务器发送流的大小,此时跳到服务器端
        cmd:= IdTCPClient1.ReadLn; //接受服务器端的命令字符,在这里我暂时设置为空
        IdTCPClient1.OpenWriteBuffer; //准备发送缓冲
        IdTCPClient1.WriteStream(strm,true,true,strm.Size);
        IdTCPClient1.CloseWriteBuffer; //结束发送缓冲    IdTCPClient1.Disconnect;
      except
        on e:exception do
          memo1.Lines.Add(e.Message);
      end;   strm.Free; 
    end;procedure TForm1.FormCreate(Sender: TObject); 
    begin 
      with ADOQuery1 do 
      begin 
        Close; 
        SQL.Clear; 
        SQL.Add('select * from sy'); 
        Open;
      end; 
      
      self.IdTCPServer1.DefaultPort:=9999;
      self.IdTCPServer1.Active:= true; 
    end; procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread); 
    var 
      i:integer; user:TUser; cmd:string;
    begin
      strm:= TMemoryStream.Create;  with AThread.Connection do
      begin
        cmd:= Readln();//接收到client端传来的流长度
        strm.Size:= StrToInt(cmd);//设置要接收的流的大小
        WriteLn('BEGIN');//返回client端开始传输数据,此时跳转到client端    ReadStream(strm,-1,True); //这里报错 AV错误    strm.ReadBuffer(user,sizeof(TUser));
        memo1.Lines.Add(user.s_id[1]);
      end; 
    end; end.
      

  7.   

    还有个问题 我在跟踪的时候发现cmd:= Readln();//接收到client端传来的流长度 为0, 是不是strm.WriteBuffer(user,sizeof(Tuser));根本就没有写入进去啊? 
      

  8.   

    type 
      Tuser = record 
      s_id:array[0..50] of string; 
      s_name:array[0..50] of string; 
      s_age:array[0..50] of string; 
      s_text:array[0..50] of string; 
    end;改成
    Tuser = record 
      s_id:array[0..50] of string[100]; 
      s_name:array[0..50] of string[100]; 
      s_age:array[0..50] of string[100]; 
      s_text:array[0..50] of string[100]; 中间就不要用什么MemoryStream了
    发送就是IdTCPClient1.WriteBuffer(user,sizeof(user),true);接收用AThread.Connection.ReadBuffer(user,sizeof(user));我试过是可以的
      

  9.   

    刚刚试了试
    客户端:procedure TForm1.BitBtn1Click(Sender: TObject);
    var
      i:integer;
      user:Tuser;
    begin
      IdTCPClient1.Host:='127.0.0.1';
      IdTCPClient1.Port:=9999;
      try
        self.IdTCPClient1.Connect(5000);
        for i:= 0 to 50 do
        begin
          user.s_id[i]:= inttostr(i);
          user.s_name[i]:= 'name'+inttostr(i);
          user.s_age[i]:= 'age'+inttostr(i);
          user.s_text[i]:= 'text'+inttostr(i);    end;
        IdTCPClient1.WriteBuffer(user,sizeof(user),true);
      except
        on e:exception do
          memo1.Lines.Add(e.Message);
      end;
      IdTCPClient1.Disconnect;
    end;服务端:procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread);
    var
      user:Tuser;
      i:integer;
    begin
        AThread.Connection.ReadBuffer(user,sizeof(user));
        for i:=0 to 50 do
          memo1.Lines.Add(user.s_name[i]);
    end;
    关键是服务端要知道数据包的大小
      

  10.   

    啊 明白了 原来是这样。谢谢SuperTitan001,最后一个问题s_name:array[0..50] of string[100]中  string[100]的意思是说 s_name的最大字符长度为100么?
      

  11.   

    固定长度100,这样sizeof(user)就有了准确的值了