我想在客户端捕获屏幕,保存为流,压缩后将流传送到服务器端,在将流解压缩后还原成图象.(程序见上传的文件)我用indy的tcp控件的writestream和readstream能实现,但通过udp的sendbuffer发送的数据流在服务器端解压缩时却报错,不知为什么。代码如下,请各位高手指教:    GetScreen(True,BmpStream);//获取屏幕图象
    BmpStream.Position:=0;
    Compress(BmpStream,clDefault);//压缩     IdUDPClient1.SendBuffer(BmpStream,BmpStream.Size);//udp发送
     IdTCPClient1.WriteStream(BmpStream));//tcp发送tcp的接收——可正确执行
procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread);
var
src,res:TMemoryStream;
Bmp: TBitmap ;
begin
src:= TMemoryStream.Create;
res:= TMemoryStream.Create;
Bmp:= TBitmap.Create;
AThread.Connection.ReadStream(src,-1,true);
UnCompress(src,res);
bmp.LoadFromStream(res);
image1.Picture.Bitmap:=bmp;
src.Free;
res.Free;
Bmp.Free;
end;
udp的接收——有错
procedure TForm1.IdUDPServer1UDPRead(Sender: TObject; AData: TStream;
  ABinding: TIdSocketHandle);
var
Bmp:TBitMap;
srcStream,CurStream:TMemoryStream;
begin
Bmp:=TBitMap.Create;
CurStream:=TMemoryStream.Create;
srcStream:=TMemoryStream.Create;
  srcStream.CopyFrom(AData,AData.Size);
  srcStream.Position:=0;
  UnCompress(srcStream,CurStream);//在该过程中报错
Bmp.LoadFromStream(CurStream);
Image1.Picture.Bitmap:=Bmp;
Bmp.Free;
CurStream.Free;
srcStream.Free;
end;相关函数如下:Function Compress(CompressedStream: TMemoryStream;const CompressionLevel: TCompressionLevel):boolean;
//其中的CompressionLevel表示压缩级别,可以更改,值是下列参数之一:clNone, clFastest, clDefault, clMax
var
SourceStream: TCompressionStream;
DestStream: TMemoryStream;
Count: Integer;
Begin
  //获得数据流的原始尺寸
  Count := CompressedStream.Size;
  DestStream := TMemoryStream.Create;
  SourceStream:=TCompressionStream.Create(CompressionLevel, DestStream);
  Try
    //SourceStream中保存着原始的数据流
    CompressedStream.SaveToStream(SourceStream);
    //将原始数据流进行压缩, DestStream中保存着压缩后的数据流
    SourceStream.Free;
    CompressedStream.Clear;
    //写入原始数据流尺寸
    CompressedStream.WriteBuffer(Count, SizeOf(Count));
    //写入经过压缩的数据流
    CompressedStream.CopyFrom(DestStream, 0);
    result:=true;
  finally
    DestStream.Free;
  end;
end;
function  UnCompress(src,res:  TMemoryStream):boolean;
  //解压缩文件数据流
  var
      SourceStream:  TDecompressionStream;
      Buffer:  PChar;
      Count:  Integer;
  Begin
      result:=false;
      //从被压缩的数据流中读出原始数据流尺寸
      src.Position:=0;
      src.ReadBuffer(Count,  SizeOf(Count));
      //根据数据流尺寸大小为将要读入的原始数据流分配内存块
      GetMem(Buffer,  Count);
      SourceStream  :=  TDecompressionStream.Create(src);
      Try
          //将被压缩的数据流解压缩,然后存入  Buffer内存块中
          SourceStream.readBuffer(Buffer^,  Count);        //通过udp接收的数据解压时在此出错
          //将原始数据流保存至res流中
          res.writeBuffer(Buffer^,  Count);
          res.Position  :=  0;//复位流指针
          result:=true;
      finally
          FreeMem(Buffer);
      end;
  end;
procedure GetScreen(DrawCur:Boolean ; BmpStream: TMemoryStream);
var
  Dc: HDC;
  MyCanvas: TCanvas;
  MyRect: TRect;
  Bmp: TBitmap;  DrawPos: TPoint;
  MyCursor: TIcon;
  hld: hwnd;
  Threadld: dword;
  mp: tpoint;
  pIconInf TIconInfo;
  Cursorx, Cursory: integer;
begin
    Dc := GetWindowDC(0);
    MyCanvas := TCanvas.Create;
    Bmp:=TBitmap.Create;
    try
        MyCanvas.Handle := Dc;
        MyRect:=Rect(0,0,Screen.Width, Screen.Height);
    //图像为 24位真彩色,也可根据实际需要调整 pf24bit:24色 ; pf8bit:256色 ; pf4bit:256色
        Bmp.PixelFormat := pf24bit;
        Bmp.Width := MyRect.Right;
        Bmp.Height := MyRect.Bottom;
        //捕捉整个屏幕图像
        Bmp.Canvas.CopyRect(MyRect, MyCanvas, MyRect);
    finally
        MyCanvas.Handle := 0;
        MyCanvas.Free;
        ReleaseDC(0, Dc);
    end;
if DrawCur then //画上鼠标图象
begin
  GetCursorPos(DrawPos);
  MyCursor := TIcon.Create;
  getcursorpos(mp);
  hld := WindowFromPoint(mp);
  Threadld := GetWindowThreadProcessId(hld, nil);
  AttachThreadInput(GetCurrentThreadId, Threadld, True);
  MyCursor.Handle := Getcursor();
  AttachThreadInput(GetCurrentThreadId, threadld, False);
  GetIconInfo(Mycursor.Handle, pIconInfo);
  cursorx := DrawPos.x - round(pIconInfo.xHotspot);
  cursory := DrawPos.y - round(pIconInfo.yHotspot);
  Bmp.Canvas.Draw(cursorx, cursory, MyCursor); //画上鼠标
  DeleteObject(pIconInfo.hbmColor);//GetIconInfo 使用时创建了两个bitmap对象. 需要手工释放这两个对象
  DeleteObject(pIconInfo.hbmMask);//否则,调用他后,他会创建一个bitmap,多次调用会产生多个,直至资源耗尽
  Mycursor.ReleaseHandle; //释放数组内存
  MyCursor.Free;
end;      
  Bmp.SaveToStream(BmpStream);
  Bmp.Free;
end;

解决方案 »

  1.   

    UDP发送数据时甚至后发的数据有可能比先发的还早到服务器~~~~~~没有什么顺序来保证~~~~~服务器端要自己再重新组合顺序才行~~~~~~``再说,你只有一个客户机吗?如果同时受到两个客户的信息怎么办????UDP服务端使用流是不行的~~~~~~~~~``
      

  2.   

    udp和tcp如果这个数据包能收到的话是没有区别的,你的udp发送指令写错了
    IdUDPClient1.SendBuffer(BmpStream,BmpStream.Size);//udp发送(你给出的地址是BmpStream对象的地址)
    正确的是IdUDPClient1.SendBuffer(BmpStream.Memory ,BmpStream.Size);//udp发送
      

  3.   

    不同意 IdUDPClient1.SendBuffer(BmpStream.Memory ,BmpStream.Size);的说法
    我用IdUDPClient1.SendBuffer(BmpStream,BmpStream.Size);在服务器端已收到数据,且大小正确.
      

  4.   

    udp发送后是不会管接收方是否收到的,最好用TCP
      

  5.   

    老大,包的大小是由第二个参数决定,不相信的话,你可以把你udp和tcp发送的在服务器接收到的数据存成文件,然后用UltraEdit打开比较看看就知道了
      

  6.   

    fj_abin() ( ) 信誉:100  2005-03-31 16:17:00  得分: 0  
     
     
       老大,包的大小是由第二个参数决定,不相信的话,你可以把你udp和tcp发送的在服务器接收到的数据存成文件,然后用UltraEdit打开比较看看就知道了
    ------------------
    同意,你发送的时候最好把包的序号包括进去,然后接受之后在还原
      

  7.   

    上面两位的意思是用
    IdUDPClient1.SendBuffer(BmpStream,BmpStream.Size);//udp发送
    IdTCPClient1.WriteStream(BmpStream));//tcp发送
    两次发送的包大小不一样了?但我在数据发送前、发送后、对方接收后的大小都没变(我是通过BmpStream.Size来看的)。
    假如是用udp发送时数据大小发生了变化,那我该怎么写代码?
      

  8.   

    IdUDPClient1.SendBuffer(BmpStream,BmpStream.Size);//udp发送
    IdTCPClient1.WriteStream(BmpStream));//tcp发送
    这两次发送的数据当然是一样大了,大小都是BmpStream.Size,但是数据内容却完全不同
    如果要发送数据不管你调用什么样的类方法,发送函数都得知道你要发送数据的内存首地址,数据块多大。
    你调用的方法IdUDPClient1.SendBuffer(BmpStream,BmpStream.Size);//udp发送
    方法本身就是要求你指定这两个参数
    虽然你调用tcp发送的方法只有一个参数,但是这个参数是TStream类的实例,TStream类的属性Size,就被用来定义你所要发送数据的大小,所以你才不要在调用方法时指定。
    也因此你两种方式发送的数据,接收到的时候大小完全一致问题关键是你没有看清楚方法的定义,面向对象的概念不清晰
    你可以两种方式验证一下我的说法:
    方式一:修改udp发送数据调用方法:IdUDPClient1.SendBuffer(BmpStream.Memory ,BmpStream.Size);如果你接收数据解析无误,说明我的说法正确
    方式二:
    修改你tcp发送数据调用方法,不用WriteStream,改用 WriteBuffer实现你发送
    参照你udp的方法调用你应该会写成IdTCPClient1.WriteBuffer(BmpStream,BmpStream.Size);//tcp发送
    如果你接收到的数据解析能正确,说明我的说法错误
      

  9.   

    我是用indy9做的
    关键是 IdUDPClient1.SendBuffer(BmpStream.Memory ,BmpStream.Size); 这条语句连编译都不能通过,我当然不同意这个写法了。
    BmpStream.Memory这个位置应当是一个buffer变量,而我放了BmpStream这个MemoryStream类型的变量,这应当是错误的所在,但我不知道怎么解决。
      

  10.   

    建议用TCP/IP, 我这样做的,一直在用:
    var
      fbuf1:TMemoryStream;
    begin
              try 
                SourceBmp := TBitmap.Create;
                SourceBmp.PixelFormat := pf24bit;
                SourceBmp.LoadFromFile(MyRec.ServerPath);
                jpg := TJPEGImage.Create;
                jpg.Assign(SourceBmp);
                //jpg.SaveToFile(JpgPath);
                //===================================================================
                fbuf1:=TMemoryStream.Create;
                //===================================================================
                jpg.SaveToStream(fbuf1);
                SourceBmp.FreeImage;
                FreeAndNil(SourceBmp);
                FreeAndNil(jpg);
                AThread.Connection.OpenWriteBuffer;
                AThread.Connection.Writestream(fbuf1,true,false);
              finally
                AThread.Connection.CloseWriteBuffer;
              end; 
    end;
      

  11.   

    tcp我做成了
    我就想试试udp怎么做
      

  12.   

    正确的语句: 
    IdUDPClient1.SendBuffer(BmpStream.Memory^ ,BmpStream.Size); 
    pf你的学习态度:)我最近接手一个私活就是用udp实现的c/s通信的,所以我才能这么确信的指出你的错误所在。