Unconfigured Ad Widget

Collapse

Anúncio

Collapse
No announcement yet.

Enviando dados via socket's

Collapse
X
 
  • Filter
  • Tempo
  • Show
Clear All
new posts

  • Font Size
    #1

    Tutorial Enviando dados via socket's

    Bom, neste tópico prentendo explicar, de forma bem simples, como enviar diversos tipos de dados via socket. Os dados que eu vou citar aqui serão: arquivos e blocos de memória. Não vou comentar sobre texto pois não é esse o foco, considerando que texto é mais facil de ser tratado...

    1) O QUE É STREAM?

    Stream, como o próprio nome sugere, é um fluxo de dados. Esse fluxo é linear, portanto contém um início e um fim e, a partir que o pc o lê, ele "navega" entre esse fluxo, mudando sua posição nessa "linha" de dados. Existem alguns tipos específicos de streams, mas os que iremos utilizar é o TMemoryStream. Poderíamos utilizar também o TFileStream, mas como o TMemoryStream é mais genérico acho que ele está de bom tamanho para aprendizagem ;D


    2) ENTENDENDO A LÓGICA DE ENVIO

    Bom, antes de começar a por a mão na massa vamos tentar entender por cima COMO vai funcionar esse envio. É capaz que algumas pessoas se percam nessa explicação por ser muito abstrata, mas não pulem essa parte, mesmo que não entendam por completo, pois senão, na hora do código vocês podem se deparar com uma lógica e não entender o por quê dela.

    Primeiramente, o socket não envia toda a informação de uma vez, portanto para enviar um único stream, o evento onRead será ativado diversas vezes. Mas se tudo isso não será constante, como escrever tudo num stream só?? Como saber quando ja acabou um stream e começou o outro??

    Como vocês podem imaginar, será necessário declarar uma variavel global TMemoryStream para que se junte toda a informação que vem dividida num stream só. Para saber quando acaba um stream é necessário o seguinte procedimento: primeiro é enviado o TAMANHO desse stream (em bytes) e só depois se envia o stream em si. Logo, no onRead, será necessário apenas checar o tamanho do stream que ja está escrito na memória com o tamanho recebido... Usaremos também uma variável global BOOLEAN, para verificar se o socket ja está recebendo o stream ou não, justamente para saber se vai receber o tamanho dele ou ele em si...

    Bom, é basicamente assim que vamos transferir dados via socket... Neste exemplo eu vou mandar uma foto do ServerSocket para o ClientSocket... Adivinhem que foto será essa... Exato, uma screenshot da tela. Esse procedimento é utilizado em remote desktop, mas o foco aqui é apenas o envio de informação...


    3) BOTANDO A MÃO NA MASSA

    Bom, primeiro vamos fazer o Server que vai enviar a foto, que é mais simples... No Form coloquem apenas um ServerSocket. Vamos adicionar uma variável global TMemoryStream chamada Stream, para ser utilizada no envio.

    Agora temos que colocar a função que tira a foto em si... Reparem que eu vou convertê-la para jpg para ficar menor e o envio demorar menos, portanto ponham no USES "jpeg"...

    Código PHP:
    function GetScreenShotTJPEGImage;
    var
    DesktopHDC;
    bmpTBitmap;
    begin
    Result
    :=TJPEGImage.Create;
    bmp := TBitmap.Create;
    Desktop := GetDC(0);
    try
    try
    bmp.PixelFormat := pf32bit;
    bmp.Width := Screen.Width;
    bmp.Height := Screen.Height;
    BitBlt(bmp.Canvas.Handle00bmp.Widthbmp.HeightDesktop00SRCCOPY);
    bmp.Modified := True;
    Result.Assign(bmp);
    finally
    ReleaseDC(0Desktop);
    end;
    except
    bmp
    .Free;
    bmp := nil;
    Result.Free;
    Result:=nil;
    end;
    end
    **código adaptado do torry.net**

    Agora temos que especificar QUANDO o server vai começar a enviar a foto né? Vamos fazê-lo enviar quando o cliente pedir pelo comando "mandafoto". Portanto temos que adicionar uma rotina de verificação no onClientRead e, se o texto recebido for "mandafoto", ele cria o Stream, salva a foto numa variavel TJpegImage, salva essa TJpegImage pro stream, envia o tamanho do stream e, finalmente, envia o stream...

    Código: Selecionar tudo

    Código PHP:
    procedure TForm1.ServerSocket1ClientRead(SenderTObject;
    SocketTCustomWinSocket);
    var
    sstring;
    StreamTMemoryStream;
    jpgTJPEGImage;
    begin
    s
    :=Socket.ReceiveText;
    if 
    'mandafoto' then
    begin
    Stream
    :=TMemoryStream.Create;
    jpg:=TJPEGImage.Create;
    jpg:=GetScreenShot;
    jpg.SaveToStream(Stream);
    Stream.Position:=0;
    Socket.SendText(inttostr(Stream.Size) + #0);
    Socket.SendStream(Stream);
    end;
    end
    Notem que eu usei o null-terminator (#0) ao fim do tamanho do stream apenas como um controle para o Client, pois mesmo os textos podem ir cortados por socket...

    Pronto, o Server ja está pronto, agora vamos aprender a fazer o Cliente.

    Criem uma nova aplicação e coloque no form um ScrollBox (na aba Additional), uma Image DENTRO desse Scrollbox, um ClientSocket e um botão. Agora declares as seguintes variáveis globais:

    Código PHP:
    stSizeinteger;
    StreamTMemoryStream;
    Receivingboolean;
    jpgTJpegImage
    Como ja expliquei pra que elas servem ali emcima, não vou ficar me detendo aqui... Agora, vamos fazer o Botao pedir a imagem pro Server. Para isso o Cliente deve mandar o comando "mandafoto", como já foi pré-estabelecido no Server...

    Código PHP:
    procedure TForm1.Button1Click(SenderTObject);
    begin
    ClientSocket1
    .Socket.SendText('mandafoto');
    end
    Agora só falta o onRead do cliente... Antes de postar o código gostaria de que o stream, para ser utilizado corretamente, sua Position deve estar 0 (pois como disse antes, a leitura do fluxo de dados vai começar do começo). Agora, já explicado como funciona o cliente, vamos ao código:

    Código PHP:
    procedure TForm1.ClientSocket1Read(SenderTObject;
    SocketTCustomWinSocket);
    var
    sstring;
    begin
    s
    :=Socket.ReceiveText;
    if 
    not Receiving then
    begin
    if pos(#0,s) > 0 then
    stSize:=strtoint(copy(s,1,pos(#0,s)-1))
    else
    exit;
    Stream:=TMemoryStream.Create;
    Receiving:=True;
    delete(s,1,pos(#0,s));
    end;
    try
    Stream.Write(s[1],length(s));
    if 
    Stream.Size stSize then
    begin
    Stream
    .Position:=0;
    Receiving:=False;
    jpg:=TJPEGImage.Create;
    jpg.LoadFromStream(Stream);
    Image1.Picture.Assign(jpg);
    Stream.Free;
    end;
    except
    Stream
    .Free;
    end;
    end
    Pronto!! Rodem os programas e testem... Qualquer dúvida postem aqui!!

    PS: Lembrando que ao invés de uma imagem, poderia ser utilizado qualquer outro tipo de dados, como um arquivo, apenas utilizem Stream.LoadFromFile('ashdauhsdua.exe'); E lembrem-se que para poder abrir o arquivo é necessário liberar o stream da memória!!
    ~# Criado pela [IN]Segurança #~

  • Font Size
    #2
    fiz esse código no meu projeto más não acontece nada. como faço pra saber se o servidor está enviando a imagem?

    analisei bastante o código e descobri que o comando jpg.LoadFromStream(Stream); está com erro.

    estou usando delphi xe3. no delphi 7 funciona perfeito!
    Last edited by NullS3c; 05-11-2013, 16:32.

    Comment


    • Font Size
      #3
      O destino da imagem coloco onde?
      Scorpion

      Comment

      X
      Working...
      X