* * *

Author Topic: Synapse bidirectional UDP  (Read 2306 times)

SymbolicFrank

  • Sr. Member
  • ****
  • Posts: 299
Synapse bidirectional UDP
« on: August 10, 2017, 04:44:20 pm »
I have a machine that communicates through UDP. So, I send it an UDP message that says: "Start connection", and from that moment on it will start spamming that port with lots of data.

But AFAIK, I can not send data over a socket while I'm listening to it. Should I listen for just a few milliseconds, and then peek if there is a message to send in the queue, etc? That seems very inefficient.

Or do I have to do everything asynchronously with callbacks, all in the same thread? That's a lot of extra code.

What is the easiest way? I use Synapse ATM, but if there is something better for this, I'll use it.

Blestan

  • Sr. Member
  • ****
  • Posts: 456
Re: Synapse bidirectional UDP
« Reply #1 on: August 10, 2017, 06:24:53 pm »
you cannont send and receive in the same program... need to build a.cient and a server
Speak postscript or die!
Translate to pdf and live!

bytebites

  • Full Member
  • ***
  • Posts: 118
Re: Synapse bidirectional UDP
« Reply #2 on: August 10, 2017, 06:52:16 pm »
You can send and receive in the same program, but you need listener-thread and non-blocking socket.

Blestan

  • Sr. Member
  • ****
  • Posts: 456
Re: Synapse bidirectional UDP
« Reply #3 on: August 10, 2017, 07:00:16 pm »
ok but its easy with client/server... if you want do send and receive iteasy to use pipes or ipc
Speak postscript or die!
Translate to pdf and live!

SymbolicFrank

  • Sr. Member
  • ****
  • Posts: 299
Re: Synapse bidirectional UDP
« Reply #4 on: August 10, 2017, 10:24:32 pm »
I tried client/server, but I cannot bind them both to the same socket.

Remy Lebeau

  • Sr. Member
  • ****
  • Posts: 334
    • Lebeau Software
Re: Synapse bidirectional UDP
« Reply #5 on: August 10, 2017, 10:34:27 pm »
A UDP socket is bidirectional, just like a TCP socket is.  A single UDP socket can both send and read data, even at the same time, with multiple peers.  You don't "listen" in UDP like you do in TCP.  Simply create a UDP socket and bind it to the desired local IP/port, then send out the start message and enter a reading loop using the same UDP socket.  Each successful read will tell you which peer the data came from.  You don't have to use a non-blocking socket, either.  You could run the loop on a blocking socket using a separate thread/process, for instance, if you don't want to block the thread that sends out the start message.
« Last Edit: August 10, 2017, 10:36:23 pm by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) open source project - Admin, Developer

SymbolicFrank

  • Sr. Member
  • ****
  • Posts: 299
Re: Synapse bidirectional UDP
« Reply #6 on: August 10, 2017, 10:49:44 pm »
Yes, that's what I did. But that prevents me from sending messages, like "Close connection", while doing that.

Ok, in this case it's probably not a showstopper, as it spams everything that is happening on a CAN bus, so I get lots of messages each second. But if that traffic would stop for whatever reason (UDP = best effort, no guarantees), I would be unable to send a message until the listening times out.

Listen for 10 ms, peek messages to send for 10 ms, repeat, etc. Just when I grew accustomed to simple and straightforward blocking threads. And now I have to change the fancy thread-safe queue to support peeking as well as dequeuing.

But, can do. :)

Remy Lebeau

  • Sr. Member
  • ****
  • Posts: 334
    • Lebeau Software
Re: Synapse bidirectional UDP
« Reply #7 on: August 10, 2017, 11:12:59 pm »
Yes, that's what I did. But that prevents me from sending messages, like "Close connection", while doing that.

Ok, in this case it's probably not a showstopper, as it spams everything that is happening on a CAN bus, so I get lots of messages each second. But if that traffic would stop for whatever reason (UDP = best effort, no guarantees), I would be unable to send a message until the listening times out.

The only way that can happen if you are using a blocking socket and are trying to send out from the same thread that is waiting for data to come in.   So, either use a non-blocking socket, or do the reading and sending in separate threads.  It works fine either way.
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) open source project - Admin, Developer

SymbolicFrank

  • Sr. Member
  • ****
  • Posts: 299
Re: Synapse bidirectional UDP
« Reply #8 on: August 10, 2017, 11:16:23 pm »
Yes, that was my question.

SymbolicFrank

  • Sr. Member
  • ****
  • Posts: 299
Re: Synapse bidirectional UDP
« Reply #9 on: August 14, 2017, 01:31:21 pm »
I cannot get it to work.

Code: Pascal  [Select]
  1. procedure TSixTLNode.Execute;
  2. var
  3.   msg: TMessage;
  4. begin
  5.   MyUDPSocket := TUDPBlockSocket.Create;
  6.  
  7.   try
  8.     MyUDPSocket.CreateSocket;
  9.     MyUDPSocket.Bind('127.0.0.1', '0');
  10.     if MyUDPSocket.LastError <> 0 then Exit;
  11.     MyUDPPort := MyUDPSocket.GetLocalSinPort;
  12.     MyUDPSocket.Connect(SendToHost, SendToPort);
  13.     if MyUDPSocket.LastError <> 0 then Exit;
  14.  
  15.     while not Terminated do
  16.     begin
  17.       if MyUDPMessages.Dequeue(msg) then
  18.       begin
  19.         MyUDPSocket.SendString(msg.Data);
  20.         // TUDPBlockSocket.SendBufferTo reports 20 bytes send, which is correct
  21.         if MyUDPSocket.LastError <> 0 then
  22.         begin
  23.           MyMessages.Enqueue(TMessage.Create(0, '6TL', TCommand.Error,
  24.             IntToStr(MyUDPSocket.LastError)));
  25.         end;
  26.       end;
  27.  
  28.       if MyUDPSocket.CanRead(10) then
  29.       begin
  30.         MyMessages.Enqueue(TMessage.Create(0, '6TL', TCommand.Data,
  31.           MyUDPSocket.RecvPacket(100)));
  32.       end;
  33.  
  34.       Sleep(10);
  35.     end;
  36.   finally
  37.     MyUDPSocket.Free;
  38.   end;
  39. end;

But, nothing gets send. When I look with Wireshark, it's all silent. And yes, I did turn off the firewall.

Strange, I make lots of these kinds of things for TCP (often for Linux), which work well. But UDP is elusive.

rvk

  • Hero Member
  • *****
  • Posts: 2940
Re: Synapse bidirectional UDP
« Reply #10 on: August 14, 2017, 01:54:25 pm »
Two small remarks on your code.
First... I've never needed to use .CreateSocket. I thought this was done automtically.
Second... Shouldn't you bind the socket to 0.0.0.0 instead of 127.0.0.1?

So... this will work for me:

Code: Pascal  [Select]
  1.     // MyUDPSocket.CreateSocket;
  2.     MyUDPSocket.Bind('0.0.0.0', '0');

Thaddy

  • Hero Member
  • *****
  • Posts: 4617
Re: Synapse bidirectional UDP
« Reply #11 on: August 14, 2017, 02:05:14 pm »
I thought this was done automtically.
Makes my day :D :D
"Logically, no number of positive outcomes at the level of experimental testing can confirm a scientific theory, but a single counterexample is logically decisive."

SymbolicFrank

  • Sr. Member
  • ****
  • Posts: 299
Re: Synapse bidirectional UDP
« Reply #12 on: August 14, 2017, 02:09:36 pm »
Thanks rvk, that does work, or at least, the first message is sent.

I did it like that, because otherwise with TCP it will not bind to a socket. That is also in the comment for the Bind function.

And yes, I added the CreateSocket line to show it is done. I left it out at first (because the comments for Bind and Connect say that is done automatically.

And now GetLocalSinPort returns 0 as well, so I don't know which port is used.
« Last Edit: August 14, 2017, 02:11:41 pm by SymbolicFrank »

serbod

  • Full Member
  • ***
  • Posts: 117
Re: Synapse bidirectional UDP
« Reply #13 on: August 14, 2017, 04:16:01 pm »
You don't need do Connect() after Bind() for UDP, but need to set remote address before sending.

Code: Pascal  [Select]
  1.   FBlockSocket.SetRemoteSin(APacket.PeerIP, IntToStr(APacket.PeerPort));
  2.   FBlockSocket.SendString(APacket.Data);
  3.   FLastError := FBlockSocket.LastError;
  4.  

Remy Lebeau

  • Sr. Member
  • ****
  • Posts: 334
    • Lebeau Software
Re: Synapse bidirectional UDP
« Reply #14 on: August 14, 2017, 06:46:05 pm »
You don't need do Connect() after Bind() for UDP

Though, you CAN, if you know you are communicating with only one specific peer.  Connect() allows all outgoing packets to go to that peer without having to specify it each time, and it allows the socket to ignore all inbound packets from other peers.  Connect() establishes a 1-to-1 relationship between peers, in both TCP and UDP.

but need to set remote address before sending.

Yes, if you want to be able to send to, and/or receive from, multiple peers, then don't use Connect().
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) open source project - Admin, Developer

 

Recent

Get Lazarus at SourceForge.net. Fast, secure and Free Open Source software downloads Open Hub project report for Lazarus