GNAT.Sockets gives me a Stream_Element_Array, which I can't find any documentation on how to make use of other than "You should also be able
to get a Stream, which you should use instead" (About ten years ago, on
this very newsgroup, somebody said not to use streams with UDP, or at
least not GNAT.Sockets.Stream).
On 2022-12-31 13:11, Mark Gardner wrote:
...
Stream_Element_Array is declared in Ada.Streams as
  type Stream_Element_Array is
     array(Stream_Element_Offset range <>) of
        aliased Stream_Element;
For communication purpose it is an array of octets. Your datagram is represented as a Stream_Element_Array or a slice of.
As for streams, yes, it does not make sense to use them for networking, unless you override all stream primitives. The reasons for that are
- non-portability of predefined primitives
- low efficiency for complex data types
- encoding inefficiency as well
You will need to handle some application protocol artifacts, checksums, counters, strange encodings, sequence number etc. It is easier to this directly on the Stream_Element_Array elements.
And, well, do not use UDP, expect for broadcasting. There is no reason
to use it. For multicast consider delivery-safe protocols like PGM. For single cast use TCP/IP. (If you need low latency see the socket NO_DELAY option)
On 31/12/2022 15:11, Dmitry A. Kazakov wrote:
On 2022-12-31 13:11, Mark Gardner wrote:
...
Stream_Element_Array is declared in Ada.Streams as
   type Stream_Element_Array is
      array(Stream_Element_Offset range <>) of
         aliased Stream_Element;
For communication purpose it is an array of octets. Your datagram is
represented as a Stream_Element_Array or a slice of.
According to RM 13.13.1, "Stream_Element is mod implementation-defined"
which to me says there is no guarantee that they will be octets, unless
this is specified elsewhere?
So, how would I do this directly on the elements? I mean, if it is an octet-array to a string, I expect an element-to-element copy, or type conversion to work, but what about integers?
Do I need to do something like My_Int:=Unsigned_8(octet(1))+2**8*Unsigned_8(octet(2));
or whatever endianness demands? Or is this the time to learn how to use Unchecked_Conversion?
According to RM 13.13.1, "Stream_Element is mod implementation-defined" which to
me says there is no guarantee that they will be octets, unless this is specified
elsewhere?
GNAT.Sockets gives me a Stream_Element_Array, which I can't find any documentation on how to make use of other than "You should also be
able to get a Stream, which you should use instead" (About ten years
ago, on this very newsgroup, somebody said not to use streams with
UDP, or at least not GNAT.Sockets.Stream).
[...]
The approach we adopted was to create a 'memory stream', which is a
chunk of memory that you can treat as a stream (see for example ColdFrame.Memory_Streams at [1]). With Ada2022, you should be able to
use Ada.Streams.Storage.Bounded[2].
Message'Write the record into the memory stream;
transmit the written contents as one datagram.
To read, create a memory stream large enough for the message you expect;
read a datagram into the memory stream;
Message'Read (Stream => the_memory_stream, Item => a_message);
You can use gnatbind's switch -xdr to "Use the target-independent XDR protocol for stream oriented attributes instead of the default
implementation which is based on direct binary representations and is therefore target-and endianness-dependent".
On 31/12/2022 19:39, Simon Wright wrote:
Message'Write the record into the memory stream;
transmit the written contents as one datagram.
I'm guessing with Memory_Stream'Write(Socket_Stream, Buffer);?
I have to disagree here. UDP is perfectly fine for RPC-like (Remote Procedure Call) transactions on a local area network.
And it is orders of magnitude easier to implement on microcontrollers than TCP.
Getting between Stream_Element_Array and a byte array is a pain and I wound up just looping over arrays, copying one byte at a time. If somebody has a better idea, let me know.
And, well, do not use UDP, expect for broadcasting. There is no reason
to use it. For multicast consider delivery-safe protocols like PGM. For single cast use TCP/IP. (If you need low latency see the socket NO_DELAY option)
Getting between Stream_Element_Array and a byte array is a pain and I wound up just looping over arrays, copying one byte at a time. If somebody has a better idea, let me know.
My advise would be not to do this. It is wasting resources and
complicated being indirect when 'Write and 'Read are
compiler-generated. If you implement 'Write and 'Read yourself, then
why not calling these implementations directly. It just does not make
sense to me. I always wonder why people always overdesign
communication stuff.
Build messages directly in a Stream_Element_Array. Use
system-independent ways to encode packet data. E.g. chained codes for integers. Mantissa + exponent for real numbers. If you have Booleans
and enumerations it is a good idea to pack them into one or two octets
to shorten the packets. All this is very straightforward and easy to implement.
"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
My advise would be not to do this. It is wasting resources and
complicated being indirect when 'Write and 'Read are
compiler-generated. If you implement 'Write and 'Read yourself, then
why not calling these implementations directly. It just does not make
sense to me. I always wonder why people always overdesign
communication stuff.
Build messages directly in a Stream_Element_Array. Use
system-independent ways to encode packet data. E.g. chained codes for
integers. Mantissa + exponent for real numbers. If you have Booleans
and enumerations it is a good idea to pack them into one or two octets
to shorten the packets. All this is very straightforward and easy to
implement.
It has to depend on the design criteria.
If you need something now, and it's not performance critical, and you
have control over both ends of the channel, why not go for a
low-brain-power solution?
On the other hand, when faced with e.g. SNTP, why not use Ada's
facilities (e.g. [1]) to describe the network packet and use unchecked conversion to convert to/from the corresponding stream element array to
be sent/received?
Well decoding NTP query from Stream_Element_Array takes 2 statements (extracting two big-endian 32-bit numbers). You can check the
implementation here:
http://www.dmitry-kazakov.de/ada/components.htm#17.17
which is under-zero brained (:-)) compared to dealing with definition
of record layout and bit orders you suggest.
"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:https://sourceforge.net/p/coldframe/adasntp/code/ci/default/tree/SNTP.impl/sntp_support.ads
My advise would be not to do this. It is wasting resources and
complicated being indirect when 'Write and 'Read are
compiler-generated. If you implement 'Write and 'Read yourself, then
why not calling these implementations directly. It just does not make
sense to me. I always wonder why people always overdesign
communication stuff.
Build messages directly in a Stream_Element_Array. Use
system-independent ways to encode packet data. E.g. chained codes for
integers. Mantissa + exponent for real numbers. If you have Booleans
and enumerations it is a good idea to pack them into one or two octets
to shorten the packets. All this is very straightforward and easy to
implement.
It has to depend on the design criteria.
If you need something now, and it's not performance critical, and you
have control over both ends of the channel, why not go for a
low-brain-power solution?
On the other hand, when faced with e.g. SNTP, why not use Ada's
facilities (e.g. [1]) to describe the network packet and use
unchecked conversion to convert to/from the corresponding stream
element array to be sent/received?
[1]
At this point, I'm half-tempted to make my own binding, but as I've
never done that sort of thing before, I thought I'd ask the wisdom of
the Usenet if there is a way to convert a Stream_Element_Array into the exotic types of Unsigned_16 and String.
Em Sat, 31 Dec 2022 14:11:55 +0200, Mark Gardner escreveu:
At this point, I'm half-tempted to make my own binding, but as I've
never done that sort of thing before, I thought I'd ask the wisdom of
the Usenet if there is a way to convert a Stream_Element_Array into the
exotic types of Unsigned_16 and String.
You are obliged to use gnat-sockets ?
No? then use https://github.com/danieagle/adare-net
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 399 |
Nodes: | 16 (2 / 14) |
Uptime: | 65:07:29 |
Calls: | 8,355 |
Calls today: | 15 |
Files: | 13,159 |
Messages: | 5,893,953 |
Posted today: | 1 |