Send command to all connected clients - delphi

I have a TIdHttpServer i must keep the connection open in order to send some commands back to the clients. I want to iterate when i press a button and send a command to all connected clients.
How can i do this ?

You can use the Contexts property to get the clients and then using the IOHandler of each client you can send a message.
Var
Clients : TList;
i : integer;
begin
if not Assigned(IdTCPServer1.Contexts) then exit;
Clients:=IdTCPServer1.Contexts.LockList;
try
for i := 0 to Clients.Count-1 do
try
TIdContext(Clients[i]).Connection.IOHandler.Write(LBuffer);//LBuffer is a TBytes with the data to send
except
...
end;
finally
IdTCPServer1.Contexts.UnlockList;
end;
end;

Related

Indy UDP sending and responding simple strings

I am using Delphi 10.0 Seattle.
I'd like to send requests to a UDP server and then read the server response, which is a simple string:
Client side:send('12345')
server side(onread event or whatever):if received string = ('12345') then
send ('jhon|zack|randy')
else disconnect;
The length of the response string is variable.
The server is running on a well opened network with open connection (dedicated vps).
The client is not the same, it is behind routers and secure networks (not forwarded).
So far, I can only send the request from the client:
(uc=idUDPclient)
procedure TForm1.Button1Click(Sender: TObject);
var
s:string;
begin
if uc.Connected =False then
Uc.Connect;
uc.Send('12345');
uc.ReceiveTimeout := 2000;
s:=uc.ReceiveString() ;
ShowMessage(s);
uc.Disconnect
end;
Server side (us=idUDPserver)
procedure TForm1.usUDPRead(AThread:TIdUDPListenerThread;const AData: TIdBytes;ABinding: TIdSocketHandle);
begin
ShowMessage(us.ReceiveString());
if us.ReceiveString() = '12345' then
begin
ShowMessage(us.ReceiveString());
//respond with a string to the client immediately (behind a routers) how ?
end;
I don't know if TCP is better, and how to use it.
Android will be involved.
You are not using the TIdUDPServer.OnUDPRead event correctly. You need to get rid of the calls to ReceiveString(), they do not belong in there. Use the AData parameter instead, it contains the raw bytes of the client's request. TIdUDPServer has already read the client's data before firing the event handler.
If you need the bytes in a string, you can use Indy's BytesToString() function, or IIdTextEncoding.GetString() method.
To send a response back to the client, use the ABindingparameter.
Try this:
procedure TForm1.usUDPRead(AThread: TIdUDPListenerThread;
const AData: TIdBytes; ABinding: TIdSocketHandle);
var
s: string;
begin
s := BytesToString(AData);
//ShowMessage(s);
if s = '12345' then begin
ABinding.SendTo(ABinding.PeerIP, ABinding.PeerPort, 'jhon|zack|randy', ABinding.IPVersion);
end;
end;

Unable to connect IdPop3 to IdPop3Server via SSL

I have a TIdPop3Server in one application that has a IdServerIOHandlerSSLOpenSSL1 attached to it and retrieves emails and sends them to a TIdPop3 client in another application (having TIdSSLIOHandlerSocketOpenSSL attached to it). Everything's fine when the connections are made insecure using port 110. But when I try to use SSL connection through port 995 I get error Connection Closed Gracefully after connect attemp from the client fails. This is my Pop3SeverOnConnect event :
procedure TMainForm.Pop3ServerConnect(AContext: TIdContext);
begin
if (AContext.Connection.IOHandler is TIdSSLIOHandlerSocketBase) then
TIdSSLIOHandlerSocketBase(AContext.Connection.IOHandler).PassThrough :=
(AContext.Binding.Port <> 995);
showmessage('SSL connection made!');
end;
And this is the client-side :
procedure TMainForm.btnCheckMailBoxClick(Sender: TObject);
begin
IdSSLIOHandlerSocketOpenSSL1.PassThrough := False;
POP3Client.IOHandler := IdSSLIOHandlerSocketOpenSSL1;
with POP3Client do begin
AuthType := patUserPass;
Host := myHost;
UserName := myUserName;
Password := myPass;
Port := myPort;
end;
try
POP3Client.Connect;
Except on e : Exception do
showmessage('error=' + e.Message);
end;
// code for retrieving message data
end;
And I always get an exception from Pop3Client.Connect like I've already mentioned above (The message SSL connection made! in the server application never shows up). If I use however another mail client like for example Mozilla Thunderbird I achieve a successful SSL connection for port 995. So the problem should be somewhere in the client's procedure but who knows - that's why I'm asking you guys for help.
In your client code, you need to set the TIdPOP3.UseTLS property instead of the TIdSSLIOHandlerSocketOpenSSL.PassThrough property directly, eg:
procedure TMainForm.btnCheckMailBoxClick(Sender: TObject);
begin
with POP3Client do
begin
IOHandler := IdSSLIOHandlerSocketOpenSSL1;
AuthType := patUserPass;
UseTLS := utUseImplicitTLS; // <-- here
Host := myHost;
UserName := myUserName;
Password := myPass;
Port := myPort;
end;
try
POP3Client.Connect;
try
// code for retrieving message data
finally
POP3Client.Disconnect;
end;
except
on e : Exception do
ShowMessage('error=' + e.Message);
end;
end;
In your server code, you need to get rid of the ShowMessage(). TIdPOP3Server is multi-threaded, the OnConnect event is fired in the context of a worker thread, and ShowMessage() is not thread-safe. If you must display a popup message, use Windows.MessageBox() instead.

Indy 10 Broadcast and AData

I'm trying to make a text chat through indy udp component and here is the codes for server and client
udp Client:
procedure TForm1.SendClick(Sender: TObject);
begin
sendtocl.Broadcast(usertype.Text, 12000);
usertype.Clear;
end;
onread Server :
procedure TForm1.UDPReceiverUDPRead(AThread: TIdUDPListenerThread; const AData: TIdBytes; ABinding: TIdSocketHandle);
var
AudioDataSize: Integer;
AudioData : Pointer;
begin
try
EnterCriticalSection(Section);
try
AudioDataSize := Length(AData);
if AudioDataSize > 10 then
begin
try
if not Player.Active then
begin
Player.Active := True;
Player.WaitForStart;
end;
except
end;
if BlockAlign > 1 then Dec(AudioDataSize, AudioDataSize mod BlockAlign);
AudioData := AudioBuffer.BeginUpdate(AudioDataSize);
try
BytesToRaw(AData, AudioData^, AudioDataSize);
finally
AudioBuffer.EndUpdate;
end;
end else
begin
Player.Active := False;
Player.WaitForStop;
end;
finally
LeaveCriticalSection(Section);
end;
except
end;
begin
chatboxmsg.Lines.Add(BytesToString(AData));
end;
end;
its working good but i had problem if i use the udp client with other purpose like send buffer "To send audio " the chatboxmsg.line shows flooded data of audio buffer any way to make the server read separated Adata ?
In UDP, every send (Broadcast(), Send(), SendBuffer(), etc) transmits a distinct datagram. The OnUDPRead event is triggered for every datagram that is received. AData contains the data of one distinct datagram at a time.
So, you have two choices:
format your datagrams in such a way (such as putting a header at the front of the data) so that they identify the type of data they carry. That way, your OnUDPRead handler can read the identifier/header and know whether to put the remaining data to ChatBoxMsg or pass it to the sound system.
if you do not want to (or cannot) change your datagram formats, then you will have to send text and audio datagrams to different ports. You can use a single TIdUDPServer object listening on multiple ports at the same time (that is what its Bindings collection is for), in which case the ABinding parameter of the OnUDPServer event will tell you which port AData was received on. Or, just use two separate TIdUDPServer objects, each one listening on a different port, and assign different OnUDPRead handlers to each one.

Unable to receive response from TIdTCPServer using TIdTCPClient

I want to establish a communication between TIdTCPServer and TIdTCPClient in delphi and this is how my procedures look :
1.Server side :
procedure TMainForm.IdTCPServer1Execute(AContext: TIdContext);
var
clientReq, clientName : String;
begin
clientReq := AContext.Connection.IOHandler.ReadLn(); // client sends request
clientName := extractClientName(clientReq);
AContext.Connection.IOHandler.WriteLn('Hello ' + clientName);
end;
2.Client side :
procedure TMainForm.btnTestClientClick(Sender: TObject);
var
testTCP : TIdTCPClient;
clientReq, serverResponse : String;
begin
testTCP := TIdTCPClient.Create;
try
testTCP.Host := wantedHost;
testTCP.Port := wantedPort;
testTCP.Connect;
clientReq := 'Hello, my Name is user1.';
testTCP.IOHandler.WriteLn(clientReq);
try
serverResponse := testTCP.IOHandler.ReadLn();
except on e : Exception do begin
ShowMessage('Error reading response =' + e.Message);
end;
end;
finally
FreeAndNil(testTCP);
end;
end;
I connect to the server but than my application freezes when I try to receive the response from the server OnExecute event with my TCPClient.IOHandler.ReadLn method. Can anyone help me fix my code or show me a working example of what I'm trying to do (with Indy's TIdTCPClient and TIdTCPServer) ?
There is nothing wrong with the code you have shown, so the problem has to be in the code you have not shown. The way I see it, there are two possibilities:
If you are not setting wantedHost and/or wantedPort to the correct values, you would not actually be connecting to your expected server.
If extractClientName() is getting stuck internally and not exiting, the server would not be sending any response. One way that could happen is if you are running the client and server in the same process, and extractClientName() syncs with the main thread, but the main thread is blocked waiting on the client and cannot process the sync, so a deadlock occurs.

Indy10 TCP and asynchronous data exchange

Good morning to all.I am building a Delphi TCP server/client application using Indy 10.0.52,with TIdTCPClient and TIdTCPServer. I have problem with receiving asynchronous responses from server. Here's my part of sample code:
Client:
procedure TfrmMain.ClientSend();
begin
tcpClient.IOHandler.WriteLn('100|HelloServer');
if tcpClient.IOHandler.ReadLn() = '1100' then //Here I get 1100
begin
tcpClient.IOHandler.WriteLn('200|Are_you_ready_for_data?');
if tcpClient.IOHandler.ReadLn() = '1200' then
begin
end;
end;
end;
Server:
procedure TfrmMain.tcpServerExecute(AContext: TIdContext);
var command:Integer;
var received,value:String;
begin
received := AContext.Connection.IOHandler.ReadLn;
command := StrToInt(SomeSplitFunction(received,'first_part')); //Here I get 100
value := SomeSplitFunction(received,'second_part'); //Here I get 'HelloServer'
case command of
100:begin
//Do something with value...
AContext.Connection.IOHandler.WriteLn('1100');
end;
200:begin
//Do something with value...
AContext.Connection.IOHandler.WriteLn('1200');
end;
end;
end;
The problem is that the case 200 on tcpServerExecute is never executed, therefore the second ReadLn on client site is never read.Is multiple asynchronous data sending in single procedure supported?I have came across several examples with simple Indy TCP Server/Client applications, but I'm little stuck here.Just to mention that connection is working and I connect to server without problems.

Resources