Solved

Data Structures | advice with example please

Posted on 2004-07-30
20
419 Views
Last Modified: 2010-04-05
Hello there,

I am needing an advice on how to implement a data structure for my project
Here's the deal,
I have two apps, Server and Client.
I need the users on the clients to give an username and a password, that information will be sent to the server and if there is no one with that username, the server will accept the user, no database needed since the system is public (Users of a lab) and the time and opeations are short.

So, I need to manage the active users in the server. The information of each is sent in two parts, first: Username and Password. Second: Type of MicroController to use (Integer value) and an Array. all of that reside in a record as follows

  TMicroC = (AT51,AT52,PICF84);

  TUserRec = Record
    Username,
    Password: String;
    Case MicroC:TMicroC of
      AT51   : (progmem51:TPMem51);     //51
      AT52   : (progmem52:TPMem52);     //52
      PICF84 : (progmemPic:TPMemPic);   //PIC
  end;

Now, I know that there are A LOT of new stuff in delphi that I don't know, and different ways of doing things that's why I'm asking for help.

What I think is better for this is to have somehow, a list of unique identifiers (usernames more likely) pointing to each dinamically created record, as new clients connect, and have records deleted (disposed?) when clients disconnect.

I don't know how to implement this or even if it's the best approach so I am open to comments.

Thanks in advance.
Q is urgent too.

0
Comment
Question by:Cerf
  • 9
  • 7
  • 3
  • +1
20 Comments
 
LVL 7

Expert Comment

by:sftweng
Comment Utility
When you first create a record for each user, assign a GUID. This could be a unique identifier, a "key" for a database. See Delphi help for TGUID.  You can see an example of a GUID by entering Ctrl-Alt-G in the Delphi editor.

It is generally accepted practice to use a one-way hash on the password to ensure that the password information stored on disk cannot be compromised.

I don't know what your primary concern is. That you need rapid access to a previously stored user profile through a unique key derived, possibly, from thje userid and password entered at logon? Or that there merely be a unique database record for each user?
0
 
LVL 7

Expert Comment

by:sftweng
Comment Utility
Re-reading your original question, I'm not sure I have responded to your real concern. I'm not sure about your phrase "if there is no one with that username, the server will accept the user". This implies that you are not relying on this to authenticate the user but merely to record the access. If this is the case, how would you know the MicroC data? It seems to me you need some kind of persistent storage and user logon authentication.  A hash on the entered userid/password pair could serve as the unique identifier. Do you need such a hash?
0
 
LVL 7

Expert Comment

by:sftweng
Comment Utility
Is the identifier intended only for the current session?
0
 
LVL 7

Expert Comment

by:sftweng
Comment Utility
Sorry, it should be CTRL-Shift-G. E.g., the generated result ['{2F2DCD6C-4497-4771-A7DB-8219CB230F7D}']
0
 
LVL 8

Author Comment

by:Cerf
Comment Utility
Hello sftweng,
I don't really need to authenticate users on the system.
This is what happen,
There is a programmer connected to the PC where the server program is, the server's main job is to burn the µ's, but since it is on a lab, users should be able to send data trough the network. Therefore, there is no need to authenticate users because it would be a pain to maintain the users database. So what I need is basically some sort of dynamic structure to create and delete records and still know where they are.
About >how would you know the MicroC data? when the users have programmed and fixed their code and assembled it, they should load the hex file and hit "send" to actually send it to the server, since they have previously logged on, the server should know where the incoming data should be loaded. At the time, I use a couple of simple TStringlist to record the username and use a plain StringList.IndexOf(incomingUser) to verify it :-)
I guess I'll need another one with the same order but containing the addresses of the records.
by the way, How can I create those records dinamically?

Do you think it is a good Idea? Am I totally off?

Cërf.
0
 
LVL 7

Accepted Solution

by:
sftweng earned 300 total points
Comment Utility
No, you're not "totally off". Thank you for responding to my questions.

It appears to me that you need a "session" record. If you control everything about the session, you might create a "TGUID" as a unique identifier. If It depends on the userid/password pair, perhaps a hash would suffice.

A TObjectList would be a good place to start.

To create dynamically, use the Create method for each class, e.g.,

var
  myList : TObjectlist;
begin
  try
    myList := TObjectList.Create(True);
    { do what you would like to do here }
  finally
    Free(myList);
  end {try};
0
 
LVL 8

Author Comment

by:Cerf
Comment Utility
I don't think I need a GUID, since there won't be two users with the same username, now the TObjectList seems interesting to me...
The name of the class pretty much speaks for itself, but can I add the records to it? is there any data preparation to do it or it would be as simple as myList.Add()...
I was looking to the three lines that are on the delphi help about the TObjectList :-) So I think it could work but how can I add my records to it?
Should I change the declaration of them somehow?
0
 
LVL 8

Author Comment

by:Cerf
Comment Utility
New and Improved methods...
I was right, there are, as you mentioned, better ways to do the things in delphi. See this guy: http:Q_20986795.html I'm sure he only knew the good ol Pascal and started doing his thing when someone told him... "hey dude, you don't need to worry about all that stuff, borland already took care of it, just program your thing" :-)
And that's what I want, to take advantage of the new stuff... I think I'm going to implement a TObjectList, but I am VERY short on time, so any help will be greatly appreciated
0
 
LVL 7

Expert Comment

by:sftweng
Comment Utility
A TObjectlist is a good place to start. Be careful, though, if you send items (objects) of different types into the list. A dangerous C-ism is to do a strong typecast for the items. A better construct is the "as" casting, which might give you compile-time errors rather than execution exceptions.

If you know that only objects of a certain type will enter the TObjectList, you might decide to create a subclass inherited with a property of name and type of your choosing that does the type enforcement. You might also consider wrapping some thread-safe exclusions around the methods, though, I believe Delphi v7 has that covered with a new class (TThreadObjectList?).

0
 
LVL 8

Author Comment

by:Cerf
Comment Utility
Sorry, but you left me on the road...
I am kind of new to delphi, so subclassing and typecasting is a little of unknown to me
0
Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

 
LVL 7

Expert Comment

by:sftweng
Comment Utility
OK. Don't worry about it. The road is good but it has a few bumps ahead, especially if any "C" buddies try to tell yu how to navigate.
0
 
LVL 8

Author Comment

by:Cerf
Comment Utility
Question...
I create several instances(?) of an object called User, for testing purposes I have

  TUsuario = class    //TUser
   Usuario,Contrasena : STring; //Username, Password
   Datos: Array [0..4] of Byte; //Data Array
  end;

In a button, I create the instance...
 Prueba:= TUsuario.Create;  //Test:=TUser.Create

then assign data to it from labeledits.text and then

myList.add(Test)

Now, how's the deal? if I free the TObjectList (onFormDestroy) will free the instances of all TUSer? or should I first do something like

  For I:=0 to myList.Count-1 do
    TUsuario(myList).Free;

Cause that doesn't work... it raises an exception "Privileged..."
0
 
LVL 33

Assisted Solution

by:Slick812
Slick812 earned 50 total points
Comment Utility
hello Cerf , I have used dynamic arrays of Records to store information for various amounts of input (like user info for as many users that may be using my platform). Here is some code for a single button click ,sbut_DoDynamArrayClick, that creates a dynamic array and adds users to it, and then deletes a single user record from the array, it also does a Name search to get an Index for that user.


type
  TMicroC = (AT51,AT52,PICF84);

  TUserRec = Record
    Username,
    Password: String;
    Case MicroC:TMicroC of
      AT51   : (progmem51: pointer);     //51
      AT52   : (progmem52: pointer);     //52
      PICF84 : (progmemPic: pointer);   //PIC
  end;

  TAryUserRec = Array of TUserRec;
  // I declare a TAryUserRec type so I can pass this in function parameters




function deleteUserRec(Index: Integer; var aryUser: TAryUserRec): Boolean;
var
i: Integer;
begin
Result := False;
if (Index < 0) or (Index > High(aryUser)) then Exit;
if Index = High(aryUser) then
  begin
  SetLength(aryUser, Length(aryUser)-1);
  Result := True;
  Exit;
  end;

for i := Index to High(aryUser)-1 do
  aryUser[i] := aryUser[i+1];
SetLength(aryUser, Length(aryUser)-1);
Result := True;
end;



function GetIndex(const UserName: String; var aryUser: TAryUserRec): Integer;
var
i: Integer;
begin
Result := -1;
for i := 0 to High(aryUser) do
  if aryUser[i].UserName = Username then
  begin
  Result := i;
  Break;
  end;
end;

// BUTTON Click

procedure TForm1.sbut_DoDynamArrayClick(Sender: TObject);
var
aryRec1: TAryUserRec;
i: Integer;
begin
setLength(aryRec1, 4);
for i := 0 to High(aryRec1) do
  with aryRec1[i] do
  begin
  Username := 'Name '+IntToStr(i);
  Password := '****** '+IntToStr(i);
  MicroC := AT52;
  progmem52 := nil;
  end;

ShowMessage(IntToStr(Length(aryRec1))+' '+aryRec1[1].Username);

if not deleteUserRec(1, aryRec1) then
  ShowMessage('Index Out of Range');

ShowMessage(IntToStr(Length(aryRec1))+' '+aryRec1[1].Username);


// add a user
SetLength(aryRec1, Length(aryRec1)+1);
with aryRec1[High(aryRec1)] do
  begin
  Username := 'Name '+IntToStr(High(aryRec1));
  Password := '****** '+IntToStr(High(aryRec1));
  MicroC := AT52;
  progmem52 := nil;
  end;

i := getIndex('Name 2', aryRec1);
if i < 0 then
  ShowMessage('User Name is NOT in this array of Records')
  else
  ShowMessage('User "Name 2" PassWord is  '+aryRec1[i].PassWord);
end;

 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  --

although dynamic arrays are not so new, I find that they are effective and relativly fast, as for the Object creation, that's certanly something to consider, but for me I usually do not use objects if there are no functions or procedures I need to use in the object, if your object is just going to be a record kind of info (no functions or procedures), then a dynamic array of records may be more efficient?
0
 
LVL 8

Author Comment

by:Cerf
Comment Utility
Hello Slick
I am actually having a hard time with dynamic arrays...
I have this
   type
     TPMem51= Array [0..$1FFF] of word;

    var
      _tData: Array of Word;

then in the code...
      if MicroC=AT51 then
      Setlength(_tData, SizeOf(TPMem51));

if I ask for a sizeof _tData, returns 4

I don't know what's happening
0
 
LVL 33

Expert Comment

by:Slick812
Comment Utility
????
I am puzzled by your comment, but I guess you have missed what the SizeOf function does,
the sizeOf function will get what the compilier uses for the bytes for a type or a variable, so if you use
SizeOf(TPMem51) it will return   ($1FFF+1) * 2
because it knows that the TPMem51 is an array of word and word is 2 bytes

however, a SizeOf( ) for ANY TObject, or dynamic array (a String type is a dynamic array) it will ALWAYS return 4 , because these Objects and dynamic arrays are Pointers, because objects and dyn arrays are ReAllocated memory blocks,

for Strings and dynamic arrays, you will need to calculate the size of the memory used

memSize := Length(_tData) * SizeOf(Word);
0
 
LVL 8

Author Comment

by:Cerf
Comment Utility
Sorry about that,
I really didn't know and I still don't know a lot of important things of delphi (or other programming languages).
Shame on me, but I am willing to learn!

Thanks for the explanation, THAT, I won't forget.... ever!
0
 
LVL 33

Expert Comment

by:Slick812
Comment Utility
and
I will guess that you need the sizeOf for some kind of memory copy of array data?
if you have used fixed arrays you can get the array Data by the array variable's pointer address

var
aryFixed: TPMem51;

begin
CopyMemoy(@aryFixed, pPointer, SizeOf(aryFixed));
 - - - - - - - - -

but this will NOT work with dynamic arrays because the variable is jus a pointer to a delphi reference that handles the dynamic array, to use a pointer location for a dynamic arrat, I use the address of the first element

var
 _tData: Array of Word;

begin
// setlength and whatever
 pData := @_tData[0]; // first element of array for memory address od the array data
0
 
LVL 8

Author Comment

by:Cerf
Comment Utility
This is Certainly vital information, but it is a little offtopic because I am already working with TOBject, so I am posting a follow up of this question to make points fair to you and to sftweng.

Q is at http:Q_21078615.html

Would you please copy what's refering to Arrays there?

Thanks you very much!

Cerf
0
 
LVL 14

Assisted Solution

by:DragonSlayer
DragonSlayer earned 150 total points
Comment Utility
or perhaps instead of TObjectList, you can work with TStringList,...

You still create the record (or object), and add to the stringlist with the username as the key, so that it makes operations such as find/delete much easier...

e.g.

var
  ActiveUsers: TStringList; // <-- instantiate this in the beginning of your programme


procedure AddToActiveUsers(const sUserName, sPassword: string; iType: Integer);
var
  UserRec: TUserRec;
begin
  UserRec := TUserRec.Create(sUserName, sPassword, iType);
  ActiveUsers.AddObject(sUserName, UserRec);
end;

function IsUserActive(const sUserName: string): Boolean;
begin
  Result := ActiveUsers.IndexOf(sUserName) <> -1;
end;

etc. etc. etc.
0
 
LVL 8

Author Comment

by:Cerf
Comment Utility
THAT Would've been the solution for ALL my problems!!!

It is late now, since it is already implemented and I have to present my work next friday and still have quite some things to do but
I really feel that it is the best solution.

However, I am going to split the points. I hope you all feel i'm being fair...

Thank you VERY MUCH to all!

Cërf.
0

Featured Post

6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

Join & Write a Comment

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…

728 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

Need Help in Real-Time?

Connect with top rated Experts

14 Experts available now in Live!

Get 1:1 Help Now