Hi guys,
I am definitely not a networking guru either, but I have whipped up a quick example of a possible way to do the packets which should be very flexible too.
see the code below:
Code:
Unit packet_types;
{$IFDEF fpc}
{$MODE DELPHI} {$H+}
{$ENDIF}
Interface
Type
{..............................................................................}
TPacketType = (
ePacketType_Login,
ePacketType_Logoff,
ePacketType_Chat
);
TPacket = Packed Record
PacketType : TPacketType;
End;
TPacket_Login = Packed Record
PacketType : TPacketType;
Username : String[15];
Password : String[15];
End;
TPacket_Logoff = Packed Record
PacketType : TPacketType;
Username : String[15];
Password : String[15];
End;
TPacket_Chat = Packed Record
PacketType : TPacketType;
Msg : ShortString;
End;
PPacket = ^TPacket;
PPacket_Login = ^TPacket_Login;
PPacket_Logoff = ^TPacket_Logoff;
PPacket_Chat = ^TPacket_Chat;
{..............................................................................}
Implementation
End.
Code:
Unit packet_classes;
{$IFDEF fpc}
{$MODE DELPHI} {$H+}
{$ENDIF}
Interface
Uses
packet_types;
Type
{..............................................................................}
TPacketReader = Class
Private
Protected
Function ReadData(Const AData : Pointer; Const ADataSize : LongInt) : Boolean; Virtual;
Public
Function ReadPacket(Var APacket : Pointer) : Boolean;
Procedure FreePacket(Var APacket : Pointer);
End;
{..............................................................................}
{..............................................................................}
TPacketWriter = Class
Private
Function WritePacket(Const APacket : PPacket) : Boolean;
Protected
Function WriteData(Const AData : Pointer; Const ADataSize : LongInt) : Boolean; Virtual;
Public
Function WriteLoginPacket (Const AUserName,APassWord : AnsiString) : Boolean;
Function WriteLogoffPacket(Const AUserName,APassWord : AnsiString) : Boolean;
Function WriteChatPacket (Const AMsg : AnsiString) : Boolean;
End;
{..............................................................................}
Implementation
{..............................................................................}
{..............................................................................}
Function TPacketWriter.WriteData(Const AData : Pointer; Const ADataSize : LongInt) : Boolean;
Begin
Result := False;
{Write ADataASize bytes from AData to the network and return true if successfull}
{override this in descendent classes}
End;
{..............................................................................}
{..............................................................................}
Function TPacketReader.ReadData(Const AData : Pointer; Const ADataSize : LongInt) : Boolean;
Begin
Result := False;
{fill AData with ADataSize bytes from the network and return true if successfull}
{override this in descendent classes}
End;
{..............................................................................}
{..............................................................................}
Function TPacketReader.ReadPacket(Var APacket : Pointer) : Boolean;
Var
DataSize : LongInt;
Packet : Pointer;
Begin
Result := False;
If Not ReadData(@DataSize,SizeOf(DataSize)) Then Exit;
GetMem(Packet,DataSize);
If Not ReadData(Packet,DataSize) Then
Begin
FreeMem(Packet);
Exit;
End;
APacket := Packet;
Result := True;
End;
{..............................................................................}
{..............................................................................}
Procedure TPacketReader.FreePacket(Var APacket : Pointer);
Begin
If APacket = Nil Then Exit;
FreeMem(APacket);
APacket := Nil;
End;
{..............................................................................}
{..............................................................................}
Function TPacketWriter.WritePacket(Const APacket : PPacket) : Boolean;
Var
DataSize : LongInt;
Begin
Result := False;
Case APacket^.PacketType Of
ePacketType_Login : DataSize := SizeOf(TPacket_Login);
ePacketType_Logoff : DataSize := SizeOf(TPacket_Logoff);
ePacketType_Chat : DataSize := SizeOf(TPacket_Chat);
Else
Exit;
End;
If Not WriteData(@DataSize,SizeOf(DataSize)) Then Exit;
If Not WriteData(APacket,DataSize) Then Exit;
Result := True;
End;
{..............................................................................}
{..............................................................................}
Function TPacketWriter.WriteLoginPacket(Const AUserName,APassWord : AnsiString) : Boolean;
Var
LoginPacket : TPacket_Login;
Begin
LoginPacket.PacketType := ePacketType_Login;
LoginPacket.Username := AUserName;
LoginPacket.PassWord := APassWord;
Result := WritePacket(@LoginPacket);
End;
{..............................................................................}
{..............................................................................}
Function TPacketWriter.WriteLogoffPacket(Const AUserName,APassWord : AnsiString) : Boolean;
Var
LogoffPacket : TPacket_Logoff;
Begin
LogoffPacket.PacketType := ePacketType_Logoff;
LogoffPacket.Username := AUserName;
LogoffPacket.PassWord := APassWord;
Result := WritePacket(@LogoffPacket);
End;
{..............................................................................}
{..............................................................................}
Function TPacketWriter.WriteChatPacket(Const AMsg : AnsiString) : Boolean;
Var
ChatPacket : TPacket_Chat;
Begin
ChatPacket.PacketType := ePacketType_Chat;
ChatPacket.Msg := AMsg;
Result := WritePacket(@ChatPacket);
End;
{..............................................................................}
{..............................................................................}
End.
Example usage:
Code:
Type
{..............................................................................}
TPacketReader_Stream = Class(TPacketReader)
Private
FStream : TStream;
Protected
Function ReadData(Const AData : Pointer; Const ADataSize : LongInt) : Boolean; Override;
Public
Constructor Create(Const AStream : TStream);
End;
{..............................................................................}
{..............................................................................}
TPacketWriter_Stream = Class(TPacketWriter)
Private
FStream : TStream;
Protected
Function WriteData(Const AData : Pointer; Const ADataSize : LongInt) : Boolean; Override;
Public
Constructor Create(Const AStream : TStream);
End;
{..............................................................................}
Constructor TPacketReader_Stream.Create(Const AStream : TStream);
Begin
Inherited Create;
FStream := AStream;
End;
{..............................................................................}
{..............................................................................}
Function TPacketReader_Stream.ReadData(Const AData : Pointer; Const ADataSize : LongInt) : Boolean;
Type
PByte = ^Byte;
Begin
Result := FStream.Read(PByte(AData)^,ADataSize) = ADataSize;
End;
{..............................................................................}
{..............................................................................}
Constructor TPacketWriter_Stream.Create(Const AStream : TStream);
Begin
Inherited Create;
FStream := AStream;
End;
{..............................................................................}
{..............................................................................}
Function TPacketWriter_Stream.WriteData(Const AData : Pointer; Const ADataSize : LongInt) : Boolean;
Type
PByte = ^Byte;
Begin
Result := FStream.Write(PByte(AData)^,ADataSize) = ADataSize;
End;
{..............................................................................}
{..............................................................................}
Procedure WritePackets(Const APacketWriter : TPacketWriter);
Begin
APacketWriter.WriteLoginPacket ('UserName','PassWord');
APacketWriter.WriteChatPacket ('Message#1');
APacketWriter.WriteChatPacket ('Message#2');
APacketWriter.WriteChatPacket ('Message#3');
APacketWriter.WriteChatPacket ('Message#4');
APacketWriter.WriteChatPacket ('Message#5');
APacketWriter.WriteChatPacket ('Message#6');
APacketWriter.WriteLogoffPacket('UserName','PassWord');
End;
{..............................................................................}
{..............................................................................}
Procedure ProcessLoginPacket(Const APacket : PPacket_Login);
Begin
WriteLn('Login Packet:');
WriteLn(' ',APacket^.UserName);
WriteLn(' ',APacket^.PassWord);
End;
{..............................................................................}
{..............................................................................}
Procedure ProcessLogoffPacket(Const APacket : PPacket_Logoff);
Begin
WriteLn('Logoff Packet:');
WriteLn(' ',APacket^.UserName);
WriteLn(' ',APacket^.PassWord);
End;
{..............................................................................}
{..............................................................................}
Procedure ProcessChatPacket(Const APacket : PPacket_Chat);
Begin
WriteLn('Chat Packet: ');
WriteLn(' ',APacket^.Msg);
End;
{..............................................................................}
{..............................................................................}
Procedure ReadPackets(Const APacketReader : TPacketReader);
Var
Packet : Pointer;
Begin
While APacketReader.ReadPacket(Packet) Do
Begin
Case PPacket(Packet)^.PacketType Of
ePacketType_Login : ProcessLoginPacket (Packet);
ePacketType_Logoff : ProcessLogoffPacket(Packet);
ePacketType_Chat : ProcessChatPacket (Packet);
Else
{unknown packet so do error or something}
End;
APacketReader.FreePacket(Packet);
End;
End;
{..............................................................................}
{..............................................................................}
Var
PacketReader : TPacketReader;
PacketWriter : TpacketWriter;
MemoryStream : TMemoryStream;
begin
MemoryStream := TMemoryStream.Create;
PacketWriter := TPacketWriter_Stream.Create(MemoryStream);
PacketReader := TPacketReader_Stream.Create(MemoryStream);
WritePackets(PacketWriter);
MemoryStream.Position := 0;
ReadPackets(PacketReader);
MemoryStream.Free;
WriteLn('Finished!');
ReadLn;
End.
It does work (I tried it on a Stream packet reader writer descendants as a test), and should be easy to modify.
It should be fairly easy to make TPacketReader/Writer descendants to read and write from sockets too (synapse, indy, etc).
cheers,
Paul
Bookmarks