Protobufs is what you want. Since you have the schema on server and client the amount of data dictionary overhead per message is minimal - essentially numeric tags and the raw data.
> On Dec 24, 2020, at 8:21 AM, Artur Vianna <lordhowen...@gmail.com> wrote: > > > I will definitely explore your ideas, thanks for the insights. I'll let you > know how it turned out in the end :D > > Thanks > >> On Thu, 24 Dec 2020, 06:59 Axel Wagner, <axel.wagner...@googlemail.com> >> wrote: >>> On Thu, Dec 24, 2020 at 6:35 AM Artur Vianna <lordhowen...@gmail.com> wrote: >> >>> Exposing the bytes would hurt the abstraction. >> >> I strongly disagree with this. Exposing the bytes would improve the >> abstraction, by making the transmission- and encoding method orthogonal. And >> as I said, you can still provide just as convenient a wrapper around it. >> >>> I will certainly look into Json and maybe MessagePack. But first i may >>> fiddle with the gob source code, if my sanity allows it. If i can control >>> when the type information is sent i may be able to fix this without >>> changing the API. The ideal enconding would be a stateless gob, with the >>> proper decoding/encoding "machines" set on either side when you call >>> gob.Register, but i'm not sure of the feasibility of that. >> >> Sure, that's definitely possible. I factored that in, when I said "I think >> it's far less effort to just use a different format than trying to make this >> work with gob". >> >> But, of course, you do you. :) The decision of what API to expose and what >> encoding scheme to use and how much work you are putting into what piece is >> ultimately up to you :) >> >>> >>>> On Wed, 23 Dec 2020, 21:55 Axel Wagner, <axel.wagner...@googlemail.com> >>>> wrote: >>>>> On Thu, Dec 24, 2020 at 1:08 AM Artur Vianna <lordhowen...@gmail.com> >>>>> wrote: >>>> >>>>> Before using gob was using encoding.BinaryMarshaler, but that would mean >>>>> the user of the api would need to implement a MarshalBinary for every >>>>> type, which is kind of cumbersome. >>>>> >>>>> An option might be to let the user choose gob, BinaryMarshaler or Json >>>>> etc to best fit the use case, but that takes the simplicity of only gobs >>>>> away. >>>> >>>> I am all in favor of API simplicity, but gob just isn't super useful for >>>> this. Not to repeat myself, but you should really at least try JSON - it >>>> provides exactly the same convenience as gob, but doesn't suffer these >>>> problems. It might have a bit more overhead and might even be costlier to >>>> encode - but the savings from being able to eliminate duplicate effort >>>> should offset that (and I'm not even super convinced - I don't think gob >>>> is the most well-optimized encoding in the stdlib). >>>> >>>> But IMO, if you provide an API, the best solution is to a) just use >>>> `[]byte` at the base-layer and then b) provide convenience-wrappers around >>>> that for other formats. This lets the users decide what they want (they >>>> might want something completely different anyway) while still providing a >>>> decently convenient API for simple uses. >>>> >>>>> >>>>> I did try your solution to reset the client too but i'm getting >>>>> inconsistent behaviour, in one server it works and in another it doesn't >>>>> ("corrupted data or unknown type"). I think synching the server and >>>>> client will be error prone, while also increasing the use of network. >>>>> >>>>> The easiest solution now is to label the package for ≤32 players and test >>>>> alternative encodings that keep the API as clean as with gob. I took a >>>>> look at flatbuffers but it will be cumbersome for the user to create the >>>>> builders, and i really wanted the simplest possible API. >>>>> >>>>> Maybe i should try UDP Broadcast too and see what happens, probably chaos >>>>> :D >>>>> >>>>> >>>>>> On Wed, 23 Dec 2020, 20:36 Axel Wagner, <axel.wagner...@googlemail.com> >>>>>> wrote: >>>>>> No, it wouldn't. Because the encoder keeps state about which >>>>>> type-information it already sent and wouldn't sent it again - causing >>>>>> the client to be unable to decode. So you'd also need a new encoder on >>>>>> the server. And at that point, you're back to the status quo, with one >>>>>> encoder per client and the duplication of encoding effort. >>>>>> >>>>>> A solution would, perhaps, be if the gob API would give you a way to >>>>>> send *only* the type-info (so you could, if the connection breaks, >>>>>> create a new encoder, send all the type info, and *then* multicast the >>>>>> encoded values). But it doesn't. >>>>>> >>>>>> Really, I think it's far less effort to just use a different format (and >>>>>> I would maintain that even json would probably be fine) than trying to >>>>>> make this work with gob :) >>>>>> >>>>>> On Thu, Dec 24, 2020 at 12:20 AM Matthew Zimmerman >>>>>> <mzimmer...@gmail.com> wrote: >>>>>>> If you would "reset" each client with a new decoder each time you make >>>>>>> a new encoder, everything should work fine. Just would take some >>>>>>> coordination. >>>>>>> >>>>>>>> On Wed, Dec 23, 2020, 6:08 PM Artur Vianna <lordhowen...@gmail.com> >>>>>>>> wrote: >>>>>>>> I will look into other protocols, although for now the performance is >>>>>>>> not an issue in servers with less than 100 players. >>>>>>>> >>>>>>>> The problem with io.MultiWriter is that a player inside the group may >>>>>>>> disconnect or a new player may come in. This means a new >>>>>>>> io.MultiWriter must be created each time you dispatch, since the group >>>>>>>> may have changed in the meantime. This would also need a new encoder >>>>>>>> and then the "duplicate type received" happens. >>>>>>>> >>>>>>>>> On Wed, 23 Dec 2020, 19:58 'Axel Wagner' via golang-nuts, >>>>>>>>> <golang-nuts@googlegroups.com> wrote: >>>>>>>>> The issue with that approach is that gob keeps state about which >>>>>>>>> type-information it still has to send. So if you encode to, say, a >>>>>>>>> bytes.Buffer, it would encode all type-info on every message sent, >>>>>>>>> which is a significant overhead. >>>>>>>>> TBH, I don't understand why `io.MultiWriter` wouldn't work. It would >>>>>>>>> be helpful to see the code that causes the error message OP is seeing. >>>>>>>>> >>>>>>>>> However, really, gob just doesn't provide a good API for this sorta >>>>>>>>> thing, as mentioned. The format itself is fine, but the stateful >>>>>>>>> connection means that if you don't want to write *exactly* the same >>>>>>>>> data in exactly the same order to all connections (which can perform >>>>>>>>> poorly and lead to operational problems with timeouts and >>>>>>>>> intermittently lost connections and the like), you are going to have >>>>>>>>> a bad time. >>>>>>>>> You honestly would fare better with a full-fledged RPC framework such >>>>>>>>> as gRPC. Or, if you don't want the overhead of its IDL, even json. >>>>>>>>> Because at least the "encode once, send to each client" is trivial to >>>>>>>>> solve with that. >>>>>>>>> >>>>>>>>> But, that's just my 2¢ :) >>>>>>>>> >>>>>>>>>> On Wed, Dec 23, 2020 at 11:43 PM Robert Engels >>>>>>>>>> <reng...@ix.netcom.com> wrote: >>>>>>>>>> Yes, that is why you need to create your own protocol. Use the gob >>>>>>>>>> to encode to a buffer then send the buffer on each of the >>>>>>>>>> connections using your protocol. >>>>>>>>>> >>>>>>>>>>>> On Dec 23, 2020, at 4:19 PM, Matthew Zimmerman >>>>>>>>>>>> <mzimmer...@gmail.com> wrote: >>>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> My understanding is that gob streams are unique. >>>>>>>>>>> >>>>>>>>>>> From https://golang.org/pkg/encoding/gob/ >>>>>>>>>>> "A stream of gobs is self-describing. Each data item in the stream >>>>>>>>>>> is preceded by a specification of its type, expressed in terms of a >>>>>>>>>>> small set of predefined types." >>>>>>>>>>> >>>>>>>>>>> In my own rudimentary understanding/terms, it sends the struct >>>>>>>>>>> definition once, then uses shorthand for it afterwards. E.g, how >>>>>>>>>>> many bytes and what order. If you mix and match streams that send >>>>>>>>>>> definitions in different orders, then chaos ensues. >>>>>>>>>>> >>>>>>>>>>> I think this is why people use other encoders in the scenario >>>>>>>>>>> you're taking about. For a one to one stream gob works great, but >>>>>>>>>>> in this multi scenario I don't think it does. >>>>>>>>>>> >>>>>>>>>>> Matt >>>>>>>>>>> >>>>>>>>>>>> On Wed, Dec 23, 2020, 5:07 PM Artur Vianna >>>>>>>>>>>> <lordhowen...@gmail.com> wrote: >>>>>>>>>>>> If i create a bytes.Buffer and a gob.Encoder, each time i write to >>>>>>>>>>>> a group of connections i get "duplicate type received" and if i >>>>>>>>>>>> try and reuse the encoder, i get "corrupted data" and "unknown >>>>>>>>>>>> type". >>>>>>>>>>>> It seems i can't use both net.Conn.Write and gob.Encoder.Encode in >>>>>>>>>>>> the same connection, i will try always encoding to a buffer in >>>>>>>>>>>> both unicast and multicast like you said and report if it works. >>>>>>>>>>>> >>>>>>>>>>>>> On Wed, 23 Dec 2020, 18:49 Robert Engels, <reng...@ix.netcom.com> >>>>>>>>>>>>> wrote: >>>>>>>>>>>>> You need to encode once to a byte array then send the byte array >>>>>>>>>>>>> on each connection. >>>>>>>>>>>>> >>>>>>>>>>>>>>> On Dec 23, 2020, at 3:45 PM, meera <lordhowen...@gmail.com> >>>>>>>>>>>>>>> wrote: >>>>>>>>>>>>>>> >>>>>>>>>>>>>> >>>>>>>>>>>>>> I am trying to create a package for game servers using gob. The >>>>>>>>>>>>>> current approach is an application level multicasting over TCP, >>>>>>>>>>>>>> having a gob encoder and decoder for each player connection, and >>>>>>>>>>>>>> set up a goroutine to receive and another to dispatch for each >>>>>>>>>>>>>> one. The code for the dispatcher is here. But summarized, it >>>>>>>>>>>>>> simply receives data from a channel and encodes it. >>>>>>>>>>>>>> >>>>>>>>>>>>>> The problem is that if i want to transmit a single piece of data >>>>>>>>>>>>>> to all players, this piece of data is encoded again and again >>>>>>>>>>>>>> for each connection, doing duplicate work. With less than 100 >>>>>>>>>>>>>> players this is not a problem, but with 300+ my machine is at >>>>>>>>>>>>>> almost 100% usage and the profiler shows that most of it is >>>>>>>>>>>>>> spent on encoding. Here's the issue on github. >>>>>>>>>>>>>> >>>>>>>>>>>>>> I tryied using a io.MultiWriter but gob complains of duplicate >>>>>>>>>>>>>> type received, and if i try to write the raw bytes from the >>>>>>>>>>>>>> gob.Encoder i get corrupted data. An option is using UDP >>>>>>>>>>>>>> Broadcasting but since gob expects a stream, i'm affraid i will >>>>>>>>>>>>>> run into unexpected behavior when packets start to be lost and >>>>>>>>>>>>>> fragmented. >>>>>>>>>>>>>> >>>>>>>>>>>>>> Does gob expect a single encoder and decoder to own the stream? >>>>>>>>>>>>>> Not allowing two encoders on the server for one decoder on the >>>>>>>>>>>>>> client? >>>>>>>>>>>>>> -- >>>>>>>>>>>>>> You received this message because you are subscribed to the >>>>>>>>>>>>>> Google Groups "golang-nuts" group. >>>>>>>>>>>>>> To unsubscribe from this group and stop receiving emails from >>>>>>>>>>>>>> it, send an email to golang-nuts+unsubscr...@googlegroups.com. >>>>>>>>>>>>>> To view this discussion on the web visit >>>>>>>>>>>>>> https://groups.google.com/d/msgid/golang-nuts/0562184e-bbcc-44c9-adbf-37e8d5411c7cn%40googlegroups.com. >>>>>>>>>>>> >>>>>>>>>>>> -- >>>>>>>>>>>> You received this message because you are subscribed to the Google >>>>>>>>>>>> Groups "golang-nuts" group. >>>>>>>>>>>> To unsubscribe from this group and stop receiving emails from it, >>>>>>>>>>>> send an email to golang-nuts+unsubscr...@googlegroups.com. >>>>>>>>>>>> To view this discussion on the web visit >>>>>>>>>>>> https://groups.google.com/d/msgid/golang-nuts/CAE%3DAWBXN46idvqUbCsGs%2BZbZt%2BCj4MowJ4Ozj3_U9_6-68OWDw%40mail.gmail.com. >>>>>>>>>> >>>>>>>>>> -- >>>>>>>>>> You received this message because you are subscribed to the Google >>>>>>>>>> Groups "golang-nuts" group. >>>>>>>>>> To unsubscribe from this group and stop receiving emails from it, >>>>>>>>>> send an email to golang-nuts+unsubscr...@googlegroups.com. >>>>>>>>>> To view this discussion on the web visit >>>>>>>>>> https://groups.google.com/d/msgid/golang-nuts/214752B6-2666-4892-A9B8-E4BC4127FD42%40ix.netcom.com. >>>>>>>>> >>>>>>>>> -- >>>>>>>>> You received this message because you are subscribed to the Google >>>>>>>>> Groups "golang-nuts" group. >>>>>>>>> To unsubscribe from this group and stop receiving emails from it, >>>>>>>>> send an email to golang-nuts+unsubscr...@googlegroups.com. >>>>>>>>> To view this discussion on the web visit >>>>>>>>> https://groups.google.com/d/msgid/golang-nuts/CAEkBMfGWtULh8Q3Jqu_gq5m5Si4PvJ1oVSZY7DVhu%3D6hGK83bg%40mail.gmail.com. >>>>>>>> >>>>>>>> -- >>>>>>>> You received this message because you are subscribed to the Google >>>>>>>> Groups "golang-nuts" group. >>>>>>>> To unsubscribe from this group and stop receiving emails from it, send >>>>>>>> an email to golang-nuts+unsubscr...@googlegroups.com. >>>>>>>> To view this discussion on the web visit >>>>>>>> https://groups.google.com/d/msgid/golang-nuts/CAE%3DAWBUsmp2sbiEh%3D3z0cC9EhjLig%2B8exXyA05YngBJ-tsC_uA%40mail.gmail.com. > > -- > You received this message because you are subscribed to the Google Groups > "golang-nuts" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to golang-nuts+unsubscr...@googlegroups.com. > To view this discussion on the web visit > https://groups.google.com/d/msgid/golang-nuts/CAE%3DAWBWmiQbVBxQ2FcWguzbd7Y62LUjmQ%3DY0qKe%3D4M0WKgoubg%40mail.gmail.com. -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/ABA44548-985F-4BDD-B7E6-7A034C6BA051%40ix.netcom.com.