Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multi-protocol support (UDP, TCP, ...) #12

Closed
hoijui opened this issue Apr 28, 2014 · 15 comments
Closed

Multi-protocol support (UDP, TCP, ...) #12

hoijui opened this issue Apr 28, 2014 · 15 comments
Assignees
Labels

Comments

@hoijui
Copy link
Owner

hoijui commented Apr 28, 2014

Currently, we support only sending and receiving over UDP (which is the default for OSC). We may want to also support TCP, and probably arbitrary InputStream and OutputStream or similarly abstract "data-ports".

There is a section in the OSC 1.1 specification paper, referring to the different requirements for packet oriented (e.g. UDP) and stream oriented (e.g. TCP) transportation. So we may have a low level API for these two types of streams, and a higher level one that supports UDP and TCP.

We may also think about supporting OSC URLs, as does LibLo; example: "osc.udp://localhost:4444/my/path/"

@hoijui hoijui self-assigned this Apr 28, 2014
@hoijui hoijui added the feature label Apr 29, 2014
@nybbs2003
Copy link

in need!

@hoijui
Copy link
Owner Author

hoijui commented Mar 7, 2019

hey nyb! :-)
could you maybe be more specific?

@nybbs2003
Copy link

@hoijui I mean that TCP support is useful, and thus should be implemented.

@hoijui
Copy link
Owner Author

hoijui commented Mar 7, 2019

What are you communicating wht that also uses TCP? Or in other words, what is the TCP-package granularity?

@nybbs2003
Copy link

nybbs2003 commented Mar 8, 2019

I would like to use my Java program to communicate with Carla . Current working correctly on UDP, but TCP would be more reliable in some network environment.

@hoijui
Copy link
Owner Author

hoijui commented Mar 8, 2019

I had a look at Carla, and it seems the relevant code is mostly:

It seems like there is not a single line of comment in those files. ;-)
at first glance, it looks like they do not use bundles at all, so they only send and support receiption of single messages. I assume that this is then also the granularity thye use.
I would say, at least as a workaround, you can use JavaOSC already, by just doing the TCP connection yourself with java.net.Socket & co., and using JavaOSC's OSCSerializer|OSCSerializerFactory, which:

Converts OSC packet Java objects to their byte stream representations,
to the OSC specification.

... for sending,
and OSCParser|OSCParserFactory for receiving, if it is urgent.

.. can't promice you anything about when someone else would implement this, though I might at some point.
.. either way, good you gave a +1, thanks! :-)

@nybbs2003
Copy link

Thank you! I will have a try.

@daveyarwood
Copy link
Collaborator

I'm about to take a stab at adding TCP support, to support an application I'm writing.

@daveyarwood
Copy link
Collaborator

@hoijui I'm starting to look at the code, and one issue I see is that com.illposed.osc.transport.udp.OSC{Port,PortIn,PortOut} include a bunch of transport-agnostic OSC logic that should be shared with the TCP implementation.

In the first post in this issue, you said:

So we may have a low level API for these two types of streams, and a higher level one that supports UDP and TCP.

So maybe you were thinking the same thing that I'm starting to think, which is that we should pull the shared logic up a level into a higher-level API that can use either UDP or TCP? Do you have any thoughts on how this might be structured?

Here's an idea that I have:

  • Move transport.udp.OSC{Port,PortIn,PortOut} up a level to transport.OSC{Port,PortIn,PortOut}

  • Extract anything UDP-specific back down to the transport.udp level

  • Implement the corresponding TCP-specific bits in transport.tcp

  • The higher-level transport.udp.OSC{PortIn,PortOut} API would default to UDP as the network protocol, and you could opt in to using TCP instead.

This would be a breaking change in that users would need to change all of their references to transport.udp.OSC{PortIn,PortOut} to transport.OSC{PortIn,PortOut}, but otherwise it would be backwards compatible and their code would continue work like before after making that change.

What do you think?

@daveyarwood
Copy link
Collaborator

Another obstacle I'm running into is that the OSCParser and OSCSerializer operate on a ByteBuffer, but TCP is stream-based and we don't know the length ahead of time. An OSC "packet" sent over TCP technically ends up being many packets, so there is no upper limit on the number of bytes to read/write. Which makes it awkward to use a ByteBuffer or byte array of fixed size.

I think I can see how I can keep most of the logic in OSCParser and OSCSerializer intact, but turn the parts that do the actual reading/writing of bytes into an interface or something. Thoughts on approaches welcome!

@daveyarwood
Copy link
Collaborator

I'm getting further with this, and it's coming along nicely.

On the subject of refactoring OSCParser/OSCSerializer, I think the approach I might take is to simply make them stream-oriented. That way, the TCP transport implementation could simply connect the streams to the sockets, and the UDP transport implementation could convert to/from ByteBuffers in order to interact with the DatagramChannels.

I haven't fully thought this through, so feedback welcome.

@daveyarwood
Copy link
Collaborator

daveyarwood commented Dec 31, 2019

If there is concern about overhead of converting to/from streams and ByteBuffers for the UDP implementation, then maybe my first idea about extracting an interface is a better one.

EDIT: I'm still leaning towards the idea in the post above (make OSCParser/OSCSerializer stream-oriented) because it would make the code cleaner and I don't think streaming the bytes into an array and wrapping the array in a ByteBuffer would add much overhead.

@daveyarwood
Copy link
Collaborator

daveyarwood commented Jan 2, 2020

A new and interesting development: if we want to continue to support the "bad data handler" feature, then we have to keep the parse side ByteBuffer-oriented. This is because "bad data events" include the entire byte buffer for context. That makes working with an input stream awkward on the parse side (I attempted this today) because we're throwing away the context as we're parsing. In retrospect, I think using a ByteBuffer on the parse side makes a lot of sense, so we can leave that part unchanged.

We do, however, need to make OSCSerializer stream-oriented in order to support sending messages of arbitrary size via TCP. I'll take a stab at that next. After that, I think I'll be ready to make a huge PR adding TCP support. 🙂

@hoijui
Copy link
Owner Author

hoijui commented Jan 2, 2020

hey dave! :-)
great work!!!
this is... the main thing for this library that makes it ugly, and you are tackling it, thank you! :-)
I felt unable to do it.. I guess I was too close, or too afraid to make big changes.
and.. great solution you came up with, to make parsing and serializing use different techniques.. sounds very reasonable. :-)
looking forward to it!

(PS: I am very inactive/hardly online till end of January, so if no further feedback till then, do not worry)

@daveyarwood daveyarwood mentioned this issue Jan 17, 2020
@hoijui
Copy link
Owner Author

hoijui commented Nov 2, 2020

dave did it! :-)

(long ago already; the delay is my bad)

@hoijui hoijui closed this as completed Nov 2, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants