12. Sieť
Domovská stránka Programovanie v C++ OOP a Windows Ročníkový projekt Princípy počítačov Princípy databáz Všeličo Kontakt

 

Na prednáške:


TCP/IP

Na posielanie údajov použijeme dva komponenty zo záložky Internet:
  TServerSocket
  TClientSocket

Socket

Klient-server - spôsob komunikácie :


Nadviazanie spojenia

1. Vytvoríme aplikáciu, ktorá sa bude správať ako server.

Program vypisuje do Mema1 správu o pripojení alebo odpojení klienta. Ďalej umožní prijímať jednoduché textové správy od klientov a posielať jednoduché textové správy napísané v komponente Edit1 všetkým klientom.

procedure TForm1.ServerClientConnect      // OnClientConnect
  (Sender: TObject; Socket: TCustomWinSocket);
begin
  Memo1.Lines.Add('- Client connected - '+Socket.RemoteHost);
end;

procedure TForm1.ServerClientDisconnect   // OnClientDisconnect
  (Sender: TObject; Socket: TCustomWinSocket);
begin
  Memo1.Lines.Add('- Client disconnected - '+Socket.RemoteHost);
end;

procedure TForm1.Edit1KeyDown(Sender: TObject;
  var Key: Word; Shift: TShiftState);
var
  Index: Integer;
begin
  if Key<>13 then Exit;
  for Index:=0 to Server.Socket.ActiveConnections-1 do
    Server.Socket.Connections[Index].SendText(Edit1.Text);
end;

procedure TForm1.ServerClientRead         // OnClientRead
  (Sender: TObject; Socket: TCustomWinSocket);
begin
  Memo1.Lines.Add(Socket.RemoteHost+': '+Socket.ReceiveText);
end;

 2. Vytvoríme klientskú aplikáciu:

procedure TForm1.Edit1KeyDown(Sender: TObject;
  var Key: Word; Shift: TShiftState);
begin
  if Key<>13 then Exit;
  Client.Socket.SendText(Edit1.Text);
end;

procedure TForm1.ClientRead (Sender: TObject; // OnRead
  Socket: TCustomWinSocket);
begin
  Memo1.Lines.Add(Socket.RemoteHost+': '+Socket.ReceiveText);
end;

3. Najskôr spustíme aplikáciu servera a až potom môžeme pospúšťať aplikácie klientov.


Jednoduchá sieťová hra

Motorky - známa hra pre niekoľkých hráčov po sieti. Každý hráč ovláda svoju motorku, ktorá za sebou zanecháva stopu, do ktorej nesmú ostatní hráči naraziť. Vyhráva ten, kto dokáže jazdiť najdlhšie na svojej motorke.

Server sa bude starať o:

Hráč bude klient, ktorý:

Pomocou triedy TPlayer si bude evidovanie informácii o každom hráčovi:

type
  TPlayer=class
  private
    FX: Integer;               //
poloha a smer pohybu
    FY: Integer;
    FdX: Integer;
    FdY: Integer;   
    FColor: TColor;            //
farba
    FSocket: TCustomWinSocket; //
zabezpečí komunikáciu so serverom
  public
    constructor Create(Socket: TCustomWinSocket);
    procedure Move(dX, dY: Integer);
    procedure Step;
    property X: Integer read FX;
    property Y: Integer read FY;
    property Color: TColor read FColor;
    property Socket: TCustomWinSocket read FSocket;
  end;

constructor TPlayer.Create(Socket: TCustomWinSocket);
begin
  FX:=Form1.Image.Width div 4+Random(Form1.Image.Width div 2);
  FY:=Form1.Image.Height div 4+Random(Form1.Image.Height div 2);
  FColor:=RGB(Random(200), Random(200), Random(200));
  FdX:=0;
  FdY:=-1;
  FSocket:=Socket;
end;

procedure TPlayer.Move(dX,dY: Integer);
begin
  FdX:=dX;
  FdY:=dY;
end;

procedure TPlayer.Step;
begin
  FX:=FX+FdX;
  FY:=FY+FdY;
end;

Aplikáciu naprogramujeme tak, aby sa vedela správať aj ako server:

type
  TForm1 = class(TForm)
    Client: TClientSocket;
    Server: TServerSocket;
    Image: TImage;
    Timer: TTimer;
   
...
  private
    IsServer: Boolean;
    Player: array of TPlayer;
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

type
  TMsg=record
    Kind: (mkEnd, mkPaint);
    X, Y: Integer;
    Color: TColor;
  end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  IsServer:=False;
  DoubleBuffered:=True;
  Timer.Enabled:=False;
  Image.Canvas.Brush.Color:=$00FFFFFF;
  Image.Canvas.FillRect(Image.ClientRect);
  Image.Canvas.Font.Name:='Arial CE';
  Image.Canvas.Font.Height:=32;
  try
    Server.Active:=True;
  except
  end;
end;

procedure TForm1.FormDestroy(Sender: TObject);
var
  I: Integer;
begin
  for I:=0 to Length(Player)-1 do begin
    Player[I].Free;
    Player[I]:=nil;
  end;
end;

procedure TForm1.FormKeyDown(Sender: TObject;
  var Key: Word; Shift: TShiftState);
begin
  if IsServer then Timer.Enabled:=True;
  case Key of
    37: Client.Socket.SendText('L');
    38: Client.Socket.SendText('H');
    39: Client.Socket.SendText('P');
    40: Client.Socket.SendText('D');
  end;
end;

procedure TForm1.ServerClientConnect(Sender: TObject;
  Socket: TCustomWinSocket);
var
  M: TMsg;
  I: Integer;
begin
  if Timer.Enabled then Exit;
  IsServer:=True;
  I:=Length(Player);
  SetLength(Player, I+1);
  Player[I]:=TPlayer.Create(Socket);
  M.Kind:=mkPaint;
  M.X:=Player[I].X;
  M.Y:=Player[I].Y;
  M.Color:=Player[I].Color;
  for I:=0 to Length(Player)-1 do
    Player[I].Socket.SendBuf(M, SizeOf(M));
  for I:=0 to Length(Player)-1 do
    if Player[I].Socket<>Socket then begin
      M.X:=Player[I].X;
      M.Y:=Player[I].Y;
      M.Color:=Player[I].Color;
      Socket.SendBuf(M, SizeOf(M));
    end;
  Caption:='Server - pocet hracov: '+IntToStr(Length(Player));
end;

procedure TForm1.ServerClientDisconnect(Sender: TObject;
  Socket: TCustomWinSocket);
var
  I: Integer;
begin
  I:=Length(Player)-1;
  while (I>=0) and (Player[I].Socket<>Socket) do Dec(I);
  if I<0 then Exit;
  Player[I].Free;
  Player[I]:=Player[Length(Player)-1];
  SetLength(Player, Length(Player)-1);
  Caption:='Server - pocet hracov: '+IntToStr(Length(Player));
end;

procedure TForm1.ServerClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var
  I: Integer;
  St: string;
begin
  St:=Socket.ReceiveText;
  if St='' then Exit;
  I:=Length(Player)-1;
  while (I>=0) and (Player[I].Socket<>Socket) do Dec(I);
  if I<0 then Exit;
  case Upcase(St[1]) of
    'H': Player[I].Move(0, -1);
    'D': Player[I].Move(0, +1);
    'L': Player[I].Move(-1, 0);
    'P': Player[I].Move(+1, 0);
  end;
end;

procedure TForm1.TimerTimer(Sender: TObject);
var
  M: TMsg;
  I, J: Integer;
begin
  I:=Length(Player)-1;
  while I>=0 do begin
    Player[I].Step;
    if Image.Canvas.Pixels[Player[I].X, Player[I].Y]<>$FFFFFF then begin
      M.Kind:=mkEnd;
      Player[I].Socket.SendBuf(M, SizeOf(M));
      Player[I].Free;
      Player[I]:=Player[Length(Player)-1];
      SetLength(Player, Length(Player)-1);
      if Length(Player)=0 then I:=-1;
    end else begin
      M.Kind:=mkPaint;
      M.X:=Player[I].X;
      M.Y:=Player[I].Y;
      M.Color:=Player[I].Color;
      for J:=0 to Length(Player)-1 do
        Player[J].Socket.SendBuf(M, SizeOf(M));
      Dec(I);
    end;
  end;
end;

procedure TForm1.ClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var
  M: TMsg;
begin
  Socket.ReceiveBuf(M, SizeOf(M));
  case M.Kind of
    mkEnd: Image.Canvas.TextOut(0, 0, 'Game over');
    mkPaint: Image.Canvas.Pixels[M.X, M.Y]:=M.Color;
  end;
end;

Celý program

©  2003 Ľubomír SALANCI