IDUDPSERVER communicate with spicfic client

Delphi'de kod yazma ile ilgili sorularınızı bu foruma yazabilirsiniz.
Cevapla
Kullanıcı avatarı
mia
Üye
Mesajlar: 239
Kayıt: 17 Nis 2015 01:18

IDUDPSERVER communicate with spicfic client

Mesaj gönderen mia » 09 Ara 2017 01:37

Hey forum long time to be here , i have a question for experts sense i did not find a true example of what i needed

i have written this UDPserver and client


Client

Kod: Tümünü seç


unit udpfrm;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, IdBaseComponent, IdComponent, IdUDPBase,
  IdUDPClient, Vcl.StdCtrls, Vcl.ExtCtrls, IdUDPServer, IdGlobal, IdSocketHandle;

type
  TUDPClient = class(TForm)
    Button1: TButton;
    tmr1: TTimer;
    Memo1: TMemo;
    udpreciver: TIdUDPServer;
    Edit1: TEdit;
    procedure Button1Click(Sender: TObject);
    procedure tmr1Timer(Sender: TObject);
    procedure udpreciverStatus(ASender: TObject; const AStatus: TIdStatus;
      const AStatusText: string);
    procedure udpreciverUDPRead(AThread: TIdUDPListenerThread;
      const AData: TIdBytes; ABinding: TIdSocketHandle);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  UDPClient: TUDPClient;

implementation

{$R *.dfm}

procedure TUDPClient.Button1Click(Sender: TObject);
var
Binding: TIdSocketHandle;
begin

 if not udpreciver.Active then
  begin
    udpreciver.Active := True;

    udpreciver.Send('127.0.0.1',6754,edit1.Text);
  tmr1.Enabled := True;
  end;
end;

procedure TUDPClient.tmr1Timer(Sender: TObject);
begin
  try if udpreciver.Active then

   udpreciver.Send('127.0.0.1',6754,edit1.Text);

   except end;
end;

procedure TUDPClient.udpreciverStatus(ASender: TObject;
  const AStatus: TIdStatus; const AStatusText: string);
begin

memo1.Lines.Add(AStatusText);

end;

procedure TUDPClient.udpreciverUDPRead(AThread: TIdUDPListenerThread;
  const AData: TIdBytes; ABinding: TIdSocketHandle);
begin
memo1.Lines.Add(bytestostring(AData) + Abinding.IP);
end;

end.

Server

Kod: Tümünü seç


unit UDPSRV;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, IdBaseComponent, IdComponent, IdUDPBase,
  IdUDPServer, IdGlobal, IdSocketHandle, Vcl.StdCtrls;

type
  Tudpservfrm = class(TForm)
    udpserver: TIdUDPServer;
    Button1: TButton;
    Button2: TButton;
    Edit1: TEdit;
    Memo1: TMemo;
    procedure udpserverUDPRead(AThread: TIdUDPListenerThread;
      const AData: TIdBytes; ABinding: TIdSocketHandle);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
    procedure UpdateBindings;
  public
    { Public declarations }
  end;

var
  udpservfrm: Tudpservfrm;

implementation

{$R *.dfm}

procedure Tudpservfrm.Button1Click(Sender: TObject);
begin
 UpdateBindings;

 udpserver.Active := true;
end;

procedure Tudpservfrm.udpserverUDPRead(AThread: TIdUDPListenerThread;
  const AData: TIdBytes; ABinding: TIdSocketHandle);
begin
//
//memo1.Lines.Add(bytestostring(AData) + ABinding.PeerIP + ' : ' + intTostr(ABinding.PeerPort));
Athread.Server.Send(ABinding.PeerIP, ABinding.PeerPort, bytestostring(AData));





end;

procedure Tudpservfrm.UpdateBindings;
var
Binding: TIdSocketHandle;
begin
udpserver.DefaultPort := StrToInt(Edit1.Text);
udpserver.Bindings.Clear;
Binding := udpserver.Bindings.Add;
Binding.IP := '0.0.0.0';
Binding.Port := StrToInt(Edit1.Text);
end;

end.


i communicate with the server and send and recive data for 1 client only. i wanted to know how to send/orsend buffer to all connected clients ?
بِسْمِ اللهِ الرَّحْمنِ الرَّحِيمِ
in god i trust with every movement i do
graduated student and looking for knowledge

ertank
Üye
Mesajlar: 1161
Kayıt: 11 Eyl 2015 11:45

Re: IDUDPSERVER communicate with spicfic client

Mesaj gönderen ertank » 09 Ara 2017 12:56

Hello,

Try below code on server side:

Kod: Tümünü seç

procedure TForm1.IdUDPServer1UDPRead(AThread: TIdUDPListenerThread;
  const AData: TIdBytes; ABinding: TIdSocketHandle);
var
  I: Integer;
begin
  for I := 0 to Pred(AThread.Server.Bindings.Count) do
  begin
    AThread.Server.Send(AThread.Server.Bindings[I].PeerIP, AThread.Server.Bindings[I].PeerPort, BytesToString(AData));
  end;
end;

Kullanıcı avatarı
mia
Üye
Mesajlar: 239
Kayıt: 17 Nis 2015 01:18

Re: IDUDPSERVER communicate with spicfic client

Mesaj gönderen mia » 09 Ara 2017 01:20

i have try this sadly it send only to the sender
بِسْمِ اللهِ الرَّحْمنِ الرَّحِيمِ
in god i trust with every movement i do
graduated student and looking for knowledge

ertank
Üye
Mesajlar: 1161
Kayıt: 11 Eyl 2015 11:45

Re: IDUDPSERVER communicate with spicfic client

Mesaj gönderen ertank » 09 Ara 2017 01:53

Try below code and confirm back that you actually have more than a single connection to server, please.

Kod: Tümünü seç

procedure TForm1.IdUDPServer1UDPRead(AThread: TIdUDPListenerThread;
  const AData: TIdBytes; ABinding: TIdSocketHandle);
var
  SR: TStreamWriter;
begin
  SR := TStreamWriter.Create('log.txt', True);
  try
    SR.WriteLine(FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz    ', Now()) + AThread.Server.Bindings.Count.ToString());
  finally
    SR.Free();
  end;
end;
P.S.: Code is for recent Delphi versions. You need to adapt it if you are using an old version like Delphi 7.

Kullanıcı avatarı
mia
Üye
Mesajlar: 239
Kayıt: 17 Nis 2015 01:18

Re: IDUDPSERVER communicate with spicfic client

Mesaj gönderen mia » 10 Ara 2017 12:36

running 4 client app and the count remains 1

Kod: Tümünü seç

2017-12-10 00:33:12.230    1
2017-12-10 00:33:15.218    1
2017-12-10 00:33:18.230    1
2017-12-10 00:33:21.218    1
2017-12-10 00:33:24.217    1
2017-12-10 00:33:27.215    1
2017-12-10 00:34:17.575    1
2017-12-10 00:34:20.578    1
2017-12-10 00:34:21.150    1
2017-12-10 00:34:23.578    1
2017-12-10 00:34:24.143    1
2017-12-10 00:34:26.582    1
2017-12-10 00:34:27.151    1
2017-12-10 00:34:29.575    1
2017-12-10 00:34:30.137    1
2017-12-10 00:34:32.582    1
2017-12-10 00:34:33.151    1
2017-12-10 00:34:35.580    1
2017-12-10 00:34:36.136    1
2017-12-10 00:34:37.341    1
2017-12-10 00:34:38.578    1
2017-12-10 00:34:39.137    1
2017-12-10 00:34:40.344    1
2017-12-10 00:34:41.575    1
2017-12-10 00:34:42.143    1
2017-12-10 00:34:43.346    1
2017-12-10 00:34:44.577    1
2017-12-10 00:34:45.141    1
2017-12-10 00:34:46.346    1
2017-12-10 00:34:48.149    1
2017-12-10 00:34:49.341    1
بِسْمِ اللهِ الرَّحْمنِ الرَّحِيمِ
in god i trust with every movement i do
graduated student and looking for knowledge

Kullanıcı avatarı
SimaWB
Üye
Mesajlar: 1299
Kayıt: 07 May 2009 09:42
Konum: İstanbul
İletişim:

Re: IDUDPSERVER communicate with spicfic client

Mesaj gönderen SimaWB » 11 Ara 2017 08:28

"all connected clients" ???
UDP is connectionless protocol. So you really don't have connected clients. Or you don't know the client is really connected...
There's no place like 127.0.0.1

Kullanıcı avatarı
mia
Üye
Mesajlar: 239
Kayıt: 17 Nis 2015 01:18

Re: IDUDPSERVER communicate with spicfic client

Mesaj gönderen mia » 13 Ara 2017 06:04

i know that udp is connection-less ,what i mean about CONNECTED CLIENTS is the Client who subscribed to that port .
بِسْمِ اللهِ الرَّحْمنِ الرَّحِيمِ
in god i trust with every movement i do
graduated student and looking for knowledge

ertank
Üye
Mesajlar: 1161
Kayıt: 11 Eyl 2015 11:45

Re: IDUDPSERVER communicate with spicfic client

Mesaj gönderen ertank » 13 Ara 2017 08:20

mia yazdı:
13 Ara 2017 06:04
i know that udp is connection-less ,what i mean about CONNECTED CLIENTS is the Client who subscribed to that port .
I did not look deep into code. Most likely, TIdUDPServer is not keeping connection list because of the protocol. My guess is properties are available as most of the Indy components use same code base.

It seems that you should implement your own connected client list. There are a lot of different ways to do this:
1- When new connection arrive, add it into your list with the connection details and timestamp. Have a TTimer or similar to check clients status. Use TIdUDPClient to send a "ping" message to client and wait for a reply for a certain period of time. This kind of communication require you to have TIdUDPServer component on your client.
2- Keep same connection list as in number one. However, have your client send "I am alive" packets to server in constant intervals. If you do not receive a packet after certain period of time, remove client from your list of connected clients.

If you have your own list you can send back messages when required. However, as you are using UDP protocol there will be no way to know for sure that if your client actually receiving these messages.

Kullanıcı avatarı
mia
Üye
Mesajlar: 239
Kayıt: 17 Nis 2015 01:18

Re: IDUDPSERVER communicate with spicfic client

Mesaj gönderen mia » 17 Ara 2017 04:54

ertank yazdı:
13 Ara 2017 08:20
If you have your own list you can send back messages when required. However, as you are using UDP protocol there will be no way to know for sure that if your client actually receiving these messages.
i will update with new code shortly this code is disaster not recomended
En son mia tarafından 18 Ara 2017 06:32 tarihinde düzenlendi, toplamda 1 kere düzenlendi.
بِسْمِ اللهِ الرَّحْمنِ الرَّحِيمِ
in god i trust with every movement i do
graduated student and looking for knowledge

ertank
Üye
Mesajlar: 1161
Kayıt: 11 Eyl 2015 11:45

Re: IDUDPSERVER communicate with spicfic client

Mesaj gönderen ertank » 17 Ara 2017 05:32

I would suggest to use something like below for simplicity

Kod: Tümünü seç

type
  TConnectionList = record
    IP: string;
    LastActivity: TDateTime;
    Active: Boolean;
  end;
  TClients = TArray<TConnectionList>;

var
  Clients: TClients;

implementation
In order to add new client:

Kod: Tümünü seç

  SetLength(Clients, Succ(Length(Clients)));
  Clients[Pred(Length(Clients))].IP := NewIncomingIPNumber;
  Clients[Pred(Length(Clients))].LastActivity := Now();
  Clients[Pred(Length(Clients))].Active := True;
When your internally defined timeout reaches, you can simply set Active flag of a client to False.
If your application will be 24/7, you should define yourself a cleanup time or a client max number before cleanup. Meaning, you do something like below in order to not to have too many records in your available application memory:

Kod: Tümünü seç

procedure VacuumArrayMemory();
var
  I: Integer;
  TempClients: TClients;
  Counter: Integer;
begin
  if Length(Clients) = 0 then Exit();

  SetLength(TempClients, Length(Clients));
  Counter := 0;
  for I := 0 to Pred(Length(Clients)) do
  begin
    if Clients[I].Active then
    begin
      TempClients[Counter].IP := Clients[I].IP;
      TempClients[Counter].LastActivity := Clients[I].LastActivity;
      TempClients[Counter].Active := True;
      Inc(Counter);
    end;
  end;
  SetLength(TempClients, Counter);  
  Clients := TempClients;  // Reduce memory usage down to active client count
end;
When you need to send broadcast message from your server to your clients, you should already know the port you should be contacting at your client application. Because client incoming port is TIdUDPClient on client application. In other words, your client is not accepting incoming calls from that port. Instead, you will have TIdUDPServer on your client with a pre-defined port listening for any UDP messages.

P.S. All above code is written from memory and is not tested.

Cevapla