Link to home
Start Free TrialLog in
Avatar of ItsMe
ItsMe

asked on

JPEG transmission in Ethernet

I'd like to develop a Software which is able to view the content of one Screen on all others in a network.
I know how to take a screenshot and I can compress it with JPEG (takes too much time) but how do I
transmit it in a fast way without using a network drive ? (Delphi 3 Standard)
Avatar of ItsMe
ItsMe

ASKER

Edited text of question
ASKER CERTIFIED SOLUTION
Avatar of williams2
williams2

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of ItsMe

ASKER

Dear williams2,
I guess that your program will work beautifully. I wasn't able to test it because my compiler couldn't
find the ScktComp.dcu. Why this ?
Haven't you got the C/S version of Delphi 2/3? If not, I will have to provide some freeware socket-components (TCP/IP transmission) ..If so, I may have to look once more at the code, and change these components (TClientSocket and TServerSocket) with some free ones.

I'll go look up some suitable components for you now, so I'll be back to you. Basically they all work and act the same way, so that should not be a problem.

Regards
Williams
Avatar of ItsMe

ASKER

I've already downloaded Francois Piettes TWinSocket Component. You can find it on the Delphi Super Page.
Perhaps your program works with that, too ? Another Question: Does this program works with Novell ?
Yes it does, I have testet this on Novell workstations, connecting from one to another. Of cause it needs the workstations to have the TCP/IP protocol installed in their network configurations, but yes, it works!

I will now change the program to use Francois Piettes winsock components, I just need a little time to fix this!

See you later

Cheers
Williams
Avatar of ItsMe

ASKER

Does it work only with 2 PC's or with more, too ?
Avatar of ItsMe

ASKER

Hi Williams ! Did you find out, how it works with TWSocket ?
Sorry ItsMe! ..I have been on a weekend with my friends, and when I was about to tell people, my modem got ****ed up. So I have switched it here today :-((( ..But everything is possible, and I'm 100% convinced, that I will solve this problem with or wihtout F.Piettes components; I know some friends who has made them work fairly good! ..But I'll solve your problem, trust me!

Cheers
Williams
Avatar of ItsMe

ASKER

OK that's very fine.
cu
Philip
I really needed to make an example using F.Piettes components. He actually makes it a lot cheaper developing client/server applications, due to the price of a Delphi C/S developer license.

But here you go. You should replace the contents of the existing example:

Server:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ExtCtrls, StdCtrls, ExtDlgs, WSocket, Winsock;

Const
  //You may set this to False if you would like the whole image!
  STRETCH = True;
  STRETCH_WIDTH = 200;
  STRETCH_HEIGHT = 150;

type
  TForm1 = class(TForm)
    WSocket1: TWSocket;
    procedure FormCreate(Sender: TObject);
  private
//    ServerSocket1: TServerSocket;
    SrvSocket,
    CliSocket: TWSocket;
//    procedure ServerSocket1ClientRead(Sender: TObject;
//      Socket: TCustomWinSocket);
    procedure SrvSocketSessionAvailable(Sender: TObject; Error: Word);
    procedure SocketDataAvailable(Sender: TObject; Error: Word);
  private
    { Private declarations }
    Stream: TMemoryStream;
//    procedure SendNextPart(Socket: TCustomWinSocket);
    procedure SendNextPart(Socket: TWSocket);
  public
    { Public declarations }
    Timer: TTimer;
    procedure OnTime(Sender: TObject);
//    procedure SendScreen(Socket: TCustomWinSocket);
    procedure SendScreen(Socket: TWSocket);
  protected
    Bitmap: TBitmap;
  end;

var
  Form1: TForm1;


implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
  Bitmap:= TBitmap.Create;
  if STRETCH then
  begin
    Bitmap.Width:= STRETCH_WIDTH;
    Bitmap.height:= STRETCH_HEIGHT;
  End else
  begin
    Bitmap.Width:= Screen.Width;
    Bitmap.Height:= Screen.Height;
  End;
  Timer:= TTimer.Create(Self);
  Timer.Interval:= 1000;
  Timer.OnTimer:= OnTime;
  Timer.Enabled:= True;
{  ServerSocket1:= TServerSocket.Create(Self);
  With ServerSocket1 do
  begin
    Port:= 2500;
    Active:= True;
    ServerType:= stNonBlocking;
    OnClientRead:= ServerSocket1ClientRead;
  End;}
  CliSocket:= TWSocket.Create(self);
  CliSocket.OnDataAvailable:= SocketDataAvailable;
  SrvSocket:= TWSocket.Create(Self);
  With SrvSocket do
  begin
    Addr              := '127.0.0.1';      { Accept local clients }
    Port              := '2500';
    OnSessionAvailable:= SrvSocketSessionAvailable;
    Listen;                                { Start listening for client }
  End;
  Stream:= TMemoryStream.Create;
end;

procedure TForm1.SrvSocketSessionAvailable(Sender: TObject; Error: Word);
var
    NewHSocket : TSocket;
begin
    { We need to accept the client connection }
    NewHSocket := SrvSocket.Accept;

    { And then associate this connection with our client socket }
    CliSocket.Dup(NewHSocket);
end;

procedure TForm1.SocketDataAvailable(Sender: TObject; Error: Word);
//procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
//  Socket: TCustomWinSocket);
var
  S: String;
  Socket: TWSocket;
Begin
  Socket:= TWSocket(Sender);
//  S:= Socket.ReceiveText;
  S:= Socket.ReceiveStr;
  If S='Get me the screen' then SendScreen(Socket) else
  If S='Send next' then SendNextPart(Socket) else
  If S='Done' then Socket.Close;
End;

//procedure TForm1.SendScreen(Socket: TCustomWinSocket);
procedure TForm1.SendScreen(Socket: TWSocket);
var
  Size: Integer;
Begin
  Bitmap.SaveToStream(Stream);
  Size:= Stream.Size;
  Stream.Position:= 0;
//  Socket.SendBuf(Size,SizeOf(Size));
  Socket.Send(@Size,SizeOf(Size));
End;

//procedure TForm1.SendNextPart(Socket: TCustomWinSocket);
procedure TForm1.SendNextPart(Socket: TWSocket);
const
  MaxChunkSize = 8192; { copy in 8K chunks }
var
  ChunkSize: Integer;
  CopyBuffer: Array[0..MaxChunkSize] of Byte;
Begin
  Chunksize:= Stream.Size-Stream.Position;
  If ChunkSize>0 then
  begin
    If ChunkSize > MaxChunkSize then ChunkSize:= MaxChunkSize;
    Stream.Read(CopyBuffer,ChunkSize);
    Socket.Send(@CopyBuffer,ChunkSize);
//    Socket.SendBuf(CopyBuffer,ChunkSize);
  End else
    Stream.Clear; //The final
End;

procedure TForm1.OnTime(Sender: TObject);
var
  dwRop: DWord;
  DC: hDC;
begin
  dwRop:= SRCCOPY;
  DC:= GetDC(0);
  If STRETCH then
    StretchBlt(
      Bitmap.Canvas.Handle, // handle to destination device context
      0, // x-coordinate of destination rectangle's upper-left corner
      0, // y-coordinate of destination rectangle's upper-left corner
      Bitmap.Width, // width of destination rectangle
      Bitmap.Height, // height of destination rectangle
      DC, // handle to source device context
      0, // x-coordinate of source rectangle's upper-left corner
      0, // y-coordinate of source rectangle's upper-left corner
      Screen.Width,      // width of source rectangle
      Screen.Height,      // height of source rectangle
      dwRop        // raster operation code (See below)
    )
  else
    BitBlt(
      Bitmap.Canvas.Handle, // handle to destination device context
      0, // x-coordinate of destination rectangle's upper-left corner
      0, // y-coordinate of destination rectangle's upper-left corner
      Bitmap.Width, // width of destination rectangle
      Bitmap.Height, // height of destination rectangle
      DC, // handle to source device context
      0, // x-coordinate of source rectangle's upper-left corner
      0, // y-coordinate of source rectangle's upper-left corner
      dwRop        // raster operation code (See below)
    );
  ReleaseDC(0,DC)
{
BLACKNESS Fills the destination rectangle using the color associated with
index 0 in the physical palette. (This color is black for the
                default physical palette.)
DSTINVERT Inverts the destination rectangle.
MERGECOPY Merges the colors of the source rectangle with the specified
pattern by using the Boolean AND operator.
MERGEPAINT Merges the colors of the inverted source rectangle with the
colors of the destination rectangle by using the Boolean OR
                operator.
NOTSRCCOPY Copies the inverted source rectangle to the destination.
NOTSRCERASE Combines the colors of the source and destination rectangles
by using the Boolean OR operator and then inverts the resultant
                color.
PATCOPY Copies the specified pattern into the destination bitmap.
PATINVERT Combines the colors of the specified pattern with the colors of
the destination rectangle by using the Boolean XOR operator.
PATPAINT Combines the colors of the pattern with the colors of the
inverted source rectangle by using the Boolean OR operator. The
                result of this operation is combined with the colors of the
                destination rectangle by using the Boolean OR operator.
SRCAND Combines the colors of the source and destination rectangles
by using the Boolean AND operator.
SRCCOPY Copies the source rectangle directly to the destination
rectangle.
SRCERASE Combines the inverted colors of the destination rectangle with
the colors of the source rectangle by using the Boolean AND operator.
SRCINVERT Combines the colors of the source and destination rectangles
by using the Boolean XOR operator.
SRCPAINT Combines the colors of the source and destination rectangles by
using the Boolean OR operator.
WHITENESS Fills the destination rectangle using the color associated with
index 1 in the physical palette. (This color is white for the
                default physical palette.)
}
End;

end.


Client:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ExtCtrls, ComCtrls, WSocket;

type
  TForm1 = class(TForm)
    WSocket1: TWSocket;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    ProgressBar: TProgressBar;
    Button1: TButton;
    Button2: TButton;
//    ClientSocket1: TClientSocket;
    Image1: TImage;
    Label1: TLabel;
    CliSocket: TWSocket;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
{    procedure ClientSocket1Connect(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ClientSocket1Error(Sender: TObject; Socket: TCustomWinSocket;
      ErrorEvent: TErrorEvent; var ErrorCode: Integer);
    procedure ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);
    procedure ClientSocket1Disconnect(Sender: TObject;
      Socket: TCustomWinSocket);}
    procedure CliSocketSessionConnected(Sender: TObject; Error: Word);
    procedure CliSocketSessionClosed(Sender: TObject; Error: Word);
    procedure CliSocketDataAvailable(Sender: TObject; Error: Word);
    procedure CliSocketError(Sender: TObject);
  private
    Stream: TMemoryStream;
  public
    Procedure UpdateProgressBar;
  protected
    Bitmap: TBitmap;
    Receiving: Boolean;
    FSize: Integer;
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
begin
  Label1.Caption:= 'Connecting..';
//  ClientSocket1.Open;
  CliSocket.Addr   := 'localhost';        { Server host name              }
  CliSocket.Proto  := 'tcp';              { Protocol we wants to use      }
  CliSocket.Port   := '2500';             { The port we wants to connect  }
  CliSocket.Connect;                      { Let's connect !               }
  { Connect is just a request, it returns immediately. We eventually gets }
  { gets connected later. At that time we will receive the event          }
  { SessionConnected. If you need a timeout, you have to start a TTimer.  }
end;

//procedure TForm1.ClientSocket1Connect(Sender: TObject;
//  Socket: TCustomWinSocket);
procedure TForm1.CliSocketSessionConnected(Sender: TObject; Error: Word);
begin
  Label1.Caption:= 'Connected';
  Receiving:= False;
  FSize:= 0;
end;

//procedure TForm1.ClientSocket1Error(Sender: TObject;
//  Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
//  var ErrorCode: Integer);
procedure TForm1.CliSocketError(Sender: TObject);
begin
  ShowMessage('Did you startup the server? I cannot find it!');
end;


procedure TForm1.Button2Click(Sender: TObject);
begin
//  if ClientSocket1.Active then
//    ClientSocket1.Socket.SendText('Get me the screen');
  CliSocket.SendStr('Get me the screen');
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Label1:= TLabel.Create(Self);
  Label1.SetBounds(32,72,32,13);
  Label1.Parent:= Self;
  Label1.Caption:= 'Idle..';
  Button1:= TButton.Create(Self);
  Button1.SetBounds(8,8,75,25);
  Button1.Parent:= Self;
  Button1.Caption:= 'Connect';
  Button1.OnClick:= Button1Click;
  Button2:= TButton.Create(Self);
  Button2.SetBounds(8,40,75,25);
  Button2.Parent:= Self;
  Button2.Caption:= 'Get screen';
  Button2.OnClick:= Button2Click;
{  ClientSocket1:= TClientSocket.Create(Self);
  With ClientSocket1 do
  begin
    Active := False;
    ClientType := ctNonBlocking;
    Port := 2500;
    Address := '127.0.0.1';
    OnConnect := ClientSocket1Connect;
    OnDisconnect := ClientSocket1Disconnect;
    OnRead := ClientSocket1Read;
    OnError := ClientSocket1Error;
  end;}
  CliSocket:= TWSocket.Create(Self);
  With CliSocket do
  begin
    OnSessionConnected:= CliSocketSessionConnected;
    OnSessionClosed:= CliSocketSessionClosed;
    OnDataAvailable:= CliSocketDataAvailable;
    OnError:= CliSocketError;
  //  CliSocket.
  End;
  Image1:= TImage.Create(Self);
  Image1.SetBounds(100,0,0,0);
  Image1.AutoSize:= true;
  Image1.Parent:= Self;

  Stream:= TMemoryStream.Create;
  ProgressBar:= TProgressBar.Create(Self);
  ProgressBar.Min:= 0;
  ProgressBar.Align:= alBottom;
  ProgressBar.Parent:= Self;
end;

Procedure TForm1.UpdateprogressBar;
Begin
  ProgressBar.Position:= ProgressBar.Max-FSize;
  progressBar.Update;
End;

//procedure TForm1.ClientSocket1Read(Sender: TObject;
//  Socket: TCustomWinSocket);
procedure TForm1.CliSocketDataAvailable(Sender: TObject; Error: Word);
const
  MaxChunkSize = 8192; { copy in 8K chunks }
var
  BytesReceived: Longint;
  CopyBuffer: Array[0..MaxChunkSize] of Byte; { buffer for copying }
  ChunkSize: Integer;
  TempSize: Integer;
begin
  If FSize=0 then
  begin
//    If Socket.ReceiveLength>=SizeOf(TempSize) then
    If CliSocket.RcvdCount>=SizeOf(TempSize) then
    begin
//      Socket.ReceiveBuf(TempSize,SizeOf(TempSize)); //get the size
      CliSocket.Receive(@TempSize,SizeOf(TempSize));
//      Socket.ReceiveBuf(TempSize,SizeOf(TempSize)); //get the size
      Stream.SetSize(TempSize);
      Stream.Position:= 0;
      ProgressBar.Max:= TempSize;
      FSize:= TempSize; //Threadsafe code!
    End;
  End;
  If (FSize>0) and not(Receiving) then
  begin
    Receiving:= True;
//    While Socket.ReceiveLength>0 do
    While CliSocket.RcvdCount>0 do
    Begin
//      ChunkSize:= Socket.ReceiveLength;
      ChunkSize:= CliSocket.RcvdCount;
      If ChunkSize > MaxChunkSize then ChunkSize:= MaxChunkSize;
//      BytesReceived:= Socket.ReceiveBuf(CopyBuffer,ChunkSize);
      BytesReceived:= CliSocket.Receive(@CopyBuffer,ChunkSize);
      Stream.Write(CopyBuffer, BytesReceived); { ...write chunk }
      Dec(FSize,BytesReceived);
      UpdateProgressBar;
    End;
    //This is called "to Syncronize trasnsmissions"
//    Socket.SendText('Send next');
    CliSocket.SendStr('Send next');
    If FSize=0 then
    begin
//      Socket.SendText('Done');
      CliSocket.SendStr('Done');
      Stream.Position:= 0;
      Image1.Picture.Bitmap.LoadFromStream(Stream);
      FSize:= 0;
      ProgressBar.Position:= 0;
      Stream.Clear;
    End;
    Receiving:= False;
  End;
end;


//procedure TForm1.ClientSocket1Disconnect(Sender: TObject;
//  Socket: TCustomWinSocket);
procedure TForm1.CliSocketSessionClosed(Sender: TObject; Error: Word);
begin
  Label1.Caption:= 'Disconnected';
end;

end.

Regards,
Williams
..By the way. Please remove the line:

    WSocket1: TWSocket;

in the beginning at the Client app. It is never to be used, and will just cause you an error compiling it!

Regards,
Williams
Avatar of ItsMe

ASKER

Hi williams2,
I've compiled your program (I'd to remove the WSocket1: TWSocket;  in the Server part, too).
Must I change some vars ? The program doesn't work. I'm using a peer to peer Win95 TCP/IP
Network. I wanted to use the software for 13 clients and 1 Server together in our Novell Network.
I guess that isn't possible ? Is there a possibility that all 13 PC's receive the Screen of the Server
at the same time and to do this in near real time (1-2 sec. delay is ok) ? I think taht must be possible
with UDP Protocol ?
This sounds very weird!!! ..I have tried this on a Novell network, and it sure did work.

I might have some solutions to your problem.

1. Have you tried out both the client and server running on the same machine? (local
2. You should change the clients IP-address to the address of the server machine.
3. Are you sure the TCP/IP protocols is both setup on both server and clients?
4. I could try to send you an example of my compilations, then you should go try them and report to me if any of those didn't work?

Regards,
Williams
Avatar of ItsMe

ASKER

Hi Williams,
now your program is working very fine. I made a mistake with the IP Adress. This was the first step.
I need a software for presentating the screen of one PC on ALL other PC's of the LAN. The client must
work automatically. I thought of using the UDP protocol. This makes possible to send the picture to all
PC's at once. If one PC doesn't get it, the pciture will be shown wrong but this doesn't matter --- when this
doesn't happen to often. Is there another way to solve this problem ? Or do you know how to solve it ?

On all PC's of the LAN (12 PC's (clients)) the picture of the server must be shown in a interval of 1-2 seconds.

The only :-) problem is to transmit this silly picture to all PC's at the same time.
Hi ItsMe, I have been working a little with UDP (User Datagram Protocol) I never got it to work. I was able to send the UDP packets, but never to catch them again, have you any knowledge to some working UDP components?

Regards,
Williams
Avatar of ItsMe

ASKER

That's my problem. I know nothing about it and I don't know how to solve my problem with TCP/IP.
I'm sorry, then I cannot help you at the time beeing. I will not wait until I have build YOUR project, in my oppinion, I answered your question. Go ask another question about how to use UDP, because you cannot expect me to solve your problem without your help. You can now choose 3 things:

1. Reject the answer, you are just wasting my time.
2. Leave a comment on where you have found some components that suits your current Delphi installation and project.
3. Give the credits, and go ask another question about UDP and how to solve it. I'll be there to support your project.

Regards,
Williams
Avatar of ItsMe

ASKER

I will ask a new question but you were very helpful for me because I can use your code in a part, too.
Regards
ItsMe

PS: The new qestion Subject is "Screen-presentating software"
Avatar of ItsMe

ASKER

I gave this question 100 points not ten ! What's that ???
That's the value of the question, if another user comes here to seek an answer to his/her question.

I'll be there ItsMe, I hope I didn't offend you, I just did use more that 2 days solving your problem. :-))

Regards,
Williams