[Webinar] Streamline your web hosting managementRegister Today

x
?
Solved

sending record through sockets

Posted on 2007-10-04
5
Medium Priority
?
462 Views
Last Modified: 2010-08-05
Hi, I'm trying to send a record through sockets.

I have a record TLogin:

type
  TStatus=(online,cacona,offline,busy,passedout);

  PLogin=^TLogin;
  TLogin=record
    Login:string;
    Pass:string;
    Status:TStatus;
    Display:TPicture;
  end;

and I want to Send a var of this record using SendBuf but when the server recive the buffer...

First I tried to do this:

Client:
  var log:TLogin;
  log.Login:='jojo'
  Client.Socket.SendBuff(log, SIzeof(log));

Server

   var Buffer:TLogin;
    while socket.ReceiveLength>0 do begin
     Socket.ReceiveBuf(Buffer, Sizeof(Buffer));
    end;

but it didnt work, then I found a code like this:

   procedure SendDataStruct(Socket: TCustomWinSocket);
    var
        joy: TLogin;
       
    begin
        Client.socket.SendBuf(@joy, sizeof(joy));
    end;

Server:
  var Log:PLogin;
        Socket.ReceiveBuf(Log^, sizeof(TLogin));
    end;

but I got an error at this line: Client.socket.SendBuf(@joy, sizeof(joy)); it says that Im passing a constant object as a parameter.

Anyone know how to solve this problem?
0
Comment
Question by:manganzon
  • 3
5 Comments
 
LVL 17

Expert Comment

by:TheRealLoki
ID: 20019672
try changing it to
procedure SendDataStruct(Socket: TCustomWinSocket);
    var
        joy: TLogin;
        joyp: PLogin;
    begin
        ...
        joyp := @joy;
        Client.socket.SendBuf(joyp^, sizeof(joy));
    end;

0
 
LVL 19

Expert Comment

by:MerijnB
ID: 20019926
you cannot sent this record since there is an object in there (TPicture).
You cannot just sent an object.
0
 

Author Comment

by:manganzon
ID: 20025549
I've tried both solution, but still have errors. When the server try to use the buffer I got a Read Memory error.

server:

procedure TfrmServer.ServerMainClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var
  log:PLogin;
  vildoso:TLogin;
begin
  while socket.ReceiveLength>0 do begin
    Socket.ReceiveBuf(Log^, sizeof(TLogin));
  end;
    Showmessage(Log^.Login);//Error here
    vildoso:=log^;//Error here
    Showmessage(vildoso.Login);//Error Here
end;
0
 
LVL 17

Accepted Solution

by:
TheRealLoki earned 500 total points
ID: 20031426
I've made a very basic demo for you.
because the TGraphic is dynamic, yoyu need to tell it the classname so it can create the appropriate image type (TBitmap, TIcon, etc)

hope this helps
as I said.. it's a really basic demo, I only had a few mins to write it up :-(

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ScktComp, WinSock, ExtCtrls, math;

type
  TClientStage=(csLogin, csCommand);


  TStatus=(online,cacona,offline,busy,passedout);

  PLogin=^TLogin;
  TLogin=record
    Login:string;
    Pass:string;
    Status:TStatus;
    Display:TPicture;
  end;



  type
  TSpecificClientConnection = class(TServerClientWinSocket)
  private
//
  public
    ClientStage: TClientStage;
    ID: string; // just the unique id we create for each connection
    MS: TMemoryStream; // used for receiving data
    ExpectedStreamSize: integer;
    Joy: TLogin;
    Buffer: array [0..4095] of char;
    constructor Create(Socket: TSocket; ServerWinSocket: TServerWinSocket); virtual;
    destructor Destroy; override;
    procedure Do_Command(Sender: TObject);
    procedure Do_Login(Sender: TObject);
    procedure DecodeLoginStream;
  end;

type
  TForm1 = class(TForm)
    ServerSocket1: TServerSocket;
    ClientSocket1: TClientSocket;
    bListen: TButton;
    bOffline: TButton;
    Edit1: TEdit;
    Image1: TImage;
    Memo1: TMemo;
    bConnect: TButton;
    eAddress: TEdit;
    ePort: TEdit;
    eCommand: TEdit;
    bDisconnect: TButton;
    bLogin: TButton;
    procedure bListenClick(Sender: TObject);
    procedure bOfflineClick(Sender: TObject);
    procedure bConnectClick(Sender: TObject);
    procedure ServerSocket1ClientConnect(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ServerSocket1GetSocket(Sender: TObject; Socket: Integer;
      var ClientSocket: TServerClientWinSocket);
    procedure ServerSocket1ClientDisconnect(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ServerSocket1ClientRead(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure bDisconnectClick(Sender: TObject);
    procedure eCommandKeyPress(Sender: TObject; var Key: Char);
    procedure ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);
    procedure ClientSocket1Connect(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure bLoginClick(Sender: TObject);
  private
    procedure logmessage(s: string);
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.bListenClick(Sender: TObject);
begin
  ServerSocket1.Port := StrToIntDef(edit1.text, 2000);
  ServerSocket1.Active := true;
end;

procedure TForm1.bOfflineClick(Sender: TObject);
begin
  ServerSocket1.Active := false;
end;

procedure TForm1.bConnectClick(Sender: TObject);
begin
  ClientSocket1.Address := eAddress.Text;
  ClientSocket1.Port := StrTointDef(ePort.Text, 2000);
  ClientSocket1.Active := true;
end;

procedure TForm1.ClientSocket1Connect(Sender: TObject; Socket: TCustomWinSocket);
begin
  Form1.LogMessage('Connected');
end;

procedure TForm1.bLoginClick(Sender: TObject);
var
  joy: TLogin;
  ms: TMemoryStream;
  strlen, i: integer;
  s: string;
begin
  joy.Display := TPicture.Create;
  joy.Display.LoadFromFile('c:\windows\Coffee Bean.bmp');
  joy.Login := 'joy';
  joy.Pass := 'pass';
  joy.Status := offline;
  ms := TMemoryStream.Create;
  try
    strlen := length(joy.Login);
// write the length of the login string
    ms.Write(strlen, sizeof(strlen));
// write the actual login string
    ms.Write(joy.Login[1], strlen);

    strlen := length(joy.Pass);
// write the length of the pass string
    ms.Write(strlen, sizeof(strlen));
// write the actual login string
    ms.Write(joy.Pass[1], strlen);

// write the status
    i := integer(joy.Status); // cast status as a number
    ms.write(i, sizeof(i));

    s := joy.Display.Graphic.ClassName;
    strlen := length(s);
// write the length of the Graphic class name string
    ms.Write(strlen, sizeof(strlen));
// write the actual Graphic clas name string
    ms.Write(s[1], strlen);

// write the graphic
    joy.Display.Graphic.SaveToStream(ms);

    i := ms.size;
// send the size of our stream to the server
    ClientSocket1.Socket.SendBuf(i, sizeof(i));
// move our stream pointer abck to the start
    ms.Seek(0, soFrombeginning);
// send the actual stream
    ClientSocket1.Socket.SendStream(ms);
  finally
//    ms.Free;
//    joy.Display.Free;
  end;
end;

procedure TForm1.bDisconnectClick(Sender: TObject);
begin
  ClientSocket1.Active := false;
end;

procedure TForm1.logmessage(s: string);
begin
  memo1.lines.add(s);
  while memo1.Lines.count > 100 do memo1.lines.delete(0);
end;

procedure TForm1.ServerSocket1GetSocket(Sender: TObject; Socket: Integer;
  var ClientSocket: TServerClientWinSocket);
begin
  ClientSocket := TSpecificClientConnection.Create( Socket, (sender as tserverwinsocket));
end;

procedure TForm1.ServerSocket1ClientConnect(Sender: TObject; Socket: TCustomWinSocket);
begin
  logmessage(format('connect: %s:%d', [socket.RemoteAddress, socket.RemotePort]));
  (Socket as TSpecificClientConnection).ID := format('connect: %s:%d', [socket.RemoteAddress, socket.RemotePort]);
end;

procedure TForm1.ServerSocket1ClientDisconnect(Sender: TObject; Socket: TCustomWinSocket);
begin
  logmessage(format('disconnect: %s:%d', [socket.RemoteAddress, socket.RemotePort]));
end;

procedure TForm1.ServerSocket1ClientRead(Sender: TObject; Socket: TCustomWinSocket);
begin
  Form1.LogMessage('read');
  case (Socket as TSpecificClientConnection).ClientStage of
    csLogin: (Socket as TSpecificClientConnection).Do_Login(sender);
    csCommand: (Socket as TSpecificClientConnection).Do_Command(sender);
  end;
end;

{ TSpecificClientConnection }

constructor TSpecificClientConnection.Create(Socket: TSocket; ServerWinSocket: TServerWinSocket);
begin
  ID := '';
  ClientStage := csLogin;
  ExpectedStreamSize := -1;
  joy.Display := TPicture.Create;
  inherited Create(Socket, ServerWinSocket);
end;

destructor TSpecificClientConnection.Destroy;
begin
  inherited;
end;

procedure TSpecificClientConnection.Do_Login(Sender: TObject);
var
  rlen: integer;
  HowMuchDoWeNeed, HowMuchWillWeRead, HowMuchDidWeRead: integer;
begin
  rlen := self.ReceiveLength;
  if (self.ExpectedStreamSize = -1) and (rlen < sizeof(self.ExpectedStreamSize) ) then
  begin
    Form1.LogMessage('not enough bytes for stream size');
    // Do Nothing. we have not received enough bytes for the "stream size" yet, so wait until we have more
  end
  else if (self.ExpectedStreamSize = -1) then
  begin // we have not received anything yet, but we have enough data for the "stream size"
    Form1.LogMessage('receiving stream size');
    self.ReceiveBuf(self.ExpectedStreamSize, sizeof(self.ExpectedStreamSize));
    self.MS := TMemoryStream.Create;
    rlen := rlen - sizeof(self.ExpectedStreamSize);
  end;
  if rlen > 0 then
  begin // read the data
    HowMuchDoWeNeed := self.ExpectedStreamSize - self.MS.Size;
    HowMuchWillWeRead := min(HowMuchDoWeNeed, rlen);
    HowMuchWillWeRead := min(HowMuchWillWeRead, 4096);

    HowMuchDidWeRead := self.ReceiveBuf(Buffer, HowMuchWillWeRead);
    if (HowMuchDidWeRead > 0) then
    begin
      MS.Write(Buffer, HowMuchDidWeRead);
      Form1.LogMessage(Format('receiving stream data %d bytes (%d/%d)', [HowMuchDidWeRead, self.MS.Size, self.ExpectedStreamSize]) );
      if (self.MS.Size = self.ExpectedStreamSize) then
      try // we have received the entire stream, decode it now
        self.DecodeLoginStream;
        self.ExpectedStreamSize := -1;
        FreeAndNil(ms); // we no longer need the memorystream
        self.ClientStage := csCommand;
        self.SendText('OK'+#13#10);
      except
        on e: exception do
        begin
          self.SendText('ERROR '+ E.Message + #13#10);
        end;
      end;
    end;
  end;
end;

procedure TSpecificClientConnection.Do_Command(Sender: TObject);
var
  s: string;
begin
  s := self.ReceiveText;
  if uppercase(s) = 'JUMP'#13#10 then
    self.SendText('Whee!!');
end;

procedure TSpecificClientConnection.DecodeLoginStream;
var
  strlen, i: integer;
  s: string;
begin
    ms.Seek(0, soFromBeginning);
// read the length of the login string
    ms.Read(strlen, sizeof(strlen));
    SetLength(Joy.Login, strlen);
// read the actual login string
    ms.Read(Joy.Login[1], strlen);

// read the length of the pass string
    ms.Read(strlen, sizeof(strlen));
    SetLength(Joy.Pass, strlen);
// read the actual pass string
    ms.Read(Joy.Pass[1], strlen);

// read the status (as an integer)
    ms.read(i, sizeof(i));
// read the status
    Joy.Status := TStatus(i); // cast number as a status

// read the length of the Graphic class name string
    ms.Read(strlen, sizeof(strlen));
    SetLength(s, strlen);
// read the actual Graphic class name string
    ms.Read(s[1], strlen);
// Create the graphic of the appropriate type
    s := uppercase(s);
    if s = 'TBITMAP' then joy.Display.Graphic := TBitmap.Create
    else ShowMessage(s + ' not yet supported in DecodeLoginStream');

// read the graphic
    joy.Display.Graphic.LoadFromStream(ms);

// display it (just for a test)
    Form1.Image1.Picture.Assign(Joy.Display.Graphic);
end;

procedure TForm1.eCommandKeyPress(Sender: TObject; var Key: Char);
begin
  if (not ClientSocket1.Active) then exit;
  if ( ord(Key) = vk_Return) then
  begin
    ClientSocket1.Socket.SendText(eCommand.Text + #13#10);
    eCommand.Text := #0;
    Key := #0;
  end;
end;

procedure TForm1.ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);
var
  s: string;
begin
  s := Socket.ReceiveText;
  memo1.lines.add(s);
end;

end.

**** Form Follows

object Form1: TForm1
  Left = 249
  Top = 107
  Width = 603
  Height = 467
  Caption = 'Form1'
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object Image1: TImage
    Left = 284
    Top = 68
    Width = 105
    Height = 105
  end
  object bListen: TButton
    Left = 164
    Top = 32
    Width = 75
    Height = 25
    Caption = 'bListen'
    TabOrder = 0
    OnClick = bListenClick
  end
  object bOffline: TButton
    Left = 244
    Top = 32
    Width = 75
    Height = 25
    Caption = 'bOffline'
    TabOrder = 1
    OnClick = bOfflineClick
  end
  object Edit1: TEdit
    Left = 96
    Top = 76
    Width = 121
    Height = 21
    TabOrder = 2
    Text = '2000'
  end
  object Memo1: TMemo
    Left = 284
    Top = 184
    Width = 297
    Height = 101
    Lines.Strings = (
      'Memo1')
    TabOrder = 3
  end
  object bConnect: TButton
    Left = 104
    Top = 352
    Width = 101
    Height = 25
    Caption = 'bConnect'
    TabOrder = 4
    OnClick = bConnectClick
  end
  object eAddress: TEdit
    Left = 164
    Top = 300
    Width = 121
    Height = 21
    TabOrder = 5
    Text = '127.0.0.1'
  end
  object ePort: TEdit
    Left = 164
    Top = 324
    Width = 121
    Height = 21
    TabOrder = 6
    Text = '2000'
  end
  object eCommand: TEdit
    Left = 104
    Top = 384
    Width = 121
    Height = 21
    TabOrder = 7
    Text = 'jump'
    OnKeyPress = eCommandKeyPress
  end
  object bDisconnect: TButton
    Left = 216
    Top = 352
    Width = 75
    Height = 25
    Caption = 'bDisconnect'
    TabOrder = 8
    OnClick = bDisconnectClick
  end
  object bLogin: TButton
    Left = 300
    Top = 352
    Width = 75
    Height = 25
    Caption = 'bLogin'
    TabOrder = 9
    OnClick = bLoginClick
  end
  object ServerSocket1: TServerSocket
    Active = False
    Port = 2000
    ServerType = stNonBlocking
    OnGetSocket = ServerSocket1GetSocket
    OnClientConnect = ServerSocket1ClientConnect
    OnClientDisconnect = ServerSocket1ClientDisconnect
    OnClientRead = ServerSocket1ClientRead
    Left = 104
    Top = 32
  end
  object ClientSocket1: TClientSocket
    Active = False
    ClientType = ctNonBlocking
    Port = 0
    OnConnect = ClientSocket1Connect
    OnRead = ClientSocket1Read
    Left = 108
    Top = 300
  end
end

0
 
LVL 17

Expert Comment

by:TheRealLoki
ID: 20031428
btw, there are many ways to do this, this is just one method.
excuse typos, etc
Loki
0

Featured Post

Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
How to fix display issue, screen flickering issue when I plug in power cord to the machine. Before I start explaining the solution lets check out once the issue how it looks like after I connect the power cord. most of you also have faced this…
There may be issues when you are trying to access Outlook or send & receive emails or due to Outlook crash which leads to corrupt or damaged PST file. To eliminate the corruption from your PST file, you need to repair the corrupt Outlook PST file. U…
Suggested Courses
Course of the Month8 days, 5 hours left to enroll

607 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question