views:

73

answers:

2

Hello. I'm trying to use the TUdpSocket in Delphi. What I want to do is connect to a UDP server, send some data and wait for answer. Data is sent correctly, but the control does not receive anything. I don't know why. I've been struggling with this problem for many hours now and I'm going to give up :-(.

I tried to use TIdUDPClient, but the situation is the same. Data is sent properly, but none is received.

Only does TIdUDPServer work more or less properly for it both sends and receives data. Unfortunately data reception is handled by a separate thread (main or other, depending on the ThreadedEvent property) which forces me to use synchronization and complicate the whole code. I would like to handle UDP connection in my own thread. Just send some data and call WaitForData() to wait for an answer and then handle it in the same thread.

And if opossible, I don't want to use any third party controls, but if it is the only solution, I accept it.

Thank you very, very much for your help in advance.

---- Examples ---

i) TUDPSocket:

var
  lR, lW, lE: boolean;
begin
  UdpSocket1.LocalPort := '1600';

  UdpSocket1.RemotePort := '1600';
  UdpSocket1.RemoteHost := '127.0.0.1';
  UdpSocket1.Connect;

  UdpSocket1.Sendln('test');

  UdpSocket1.Select(@lR, @lW, @lE, 2000);    
  if lR then
    ShowMessage(UdpSocket1.Receiveln());
end;

As you can see, the control should receive the data it transmits. And apparently it does, for the lR evaluates to true after the Select() method is called. But Receiveln() returns an empty string, as ReceiveBuf() does. When i start a UDP server and send some data to it, it is received properly, so I'm certain that the data is really sent.

A: 

Another possibility would be to use Synapse for your communication. It is a simple communications library which performs blocking calls, so works well in a single worker thread where you want to stop and wait for data rather than rely on an event to fire. The latest versions in SVN have support for the latest versions of Delphi.

skamradt
+1  A: 

You should need nothing more than this:

function SayHi(Host: String; Port: Integer): String;
var
  Client: TIdUDPClient;
begin
  Client := TIdUDPClient.Create(nil);
  try
    Client.Host := Host;
    Client.Port := Port;
    Client.Send('Hello');
    Result := Client.ReceiveString(1000);
  finally
    Client.Free;
  end;
end;

which will, in the same thread, send a UDP packet and either receive a UDP packet or raise an exception after a timeout.

If the above doesn't work, check (using something like Wireshark that the client's actually sending the data. Then check on the server that it's actually receiving the packet.

Send() ultimately (on Windows) calls WinSock's sendto(), and ReceiveString() uses select() and recvfrom(). You could sort've simulate a TIdUDPServer by

while not Terminated do begin
  S := Client.ReceiveString(1000);
  DoSomething(S);
end;
Frank Shearar
Yes, this is exactly what I would like to get. If only it worked ;-(. For it does not. Client.Send() works perfectly. But Cleint.ReceiveString() never does. I don't really understand it. Is it a matter of Indy version? May my version have a bug? Thanks!
Mariusz
I'm still using Indy 9, but I can't imagine Indy 10 working much differently. I'll add some more details to the answer.
Frank Shearar
I'm using Indy 10 (BDS 2006). I don't know why, but it does not work this way :-(. What's more suprising, I also tried using the Select() method of the TUDPSocket. It returns boolean values like ReadReady, WriteReady. When some data was sent to the port I opened, the ReadReady was set to true, but nevertheless no data could be received when I called any of the Receive...() methods. It's an enigma :-). But let's forget about it. I don't want to bother you any more. Thank you very much for your time!
Mariusz
BTW, when I run your code, I always get an exception saying: "Socket Error # 10054 / Connection reset by peer" when the ReceiveString() method is invoked.
Mariusz
I assume that the host:port to which you send is actually open? `recvfrom()`'s documentation says "On a UDP-datagram socket this error indicates a previous send operation resulted in an ICMP Port Unreachable message."
Frank Shearar