#how do I know what buffer size to use when receiving data over tcp socket

65 messages · Page 1 of 1 (latest)

mighty willow
#

I have a go backend that receives images from a .net application. The golang uses the net library receiving data using
connection.Read(buffer)

Any way to not predefine the size of the buffer?

Btw I am sending stream of images which might fluctuate in size/resolution

umbral pollen
#

io.Copy + bytes.Buffer

#

no need to manually pass a slice buffer to the Read method.

mighty willow
edgy ridge
#

The way you are meant to use io.Reader is in a streaming way, so you make your buffer let's say 32KiB and reuse it over and over

#

if you really just want everything, as @umbral pollen suggested.
You can also call io.ReadAll

#

but theses solutions can allocate lots of memory and are slow because you can't do work before you got everything

#

@mighty willow what are you doing with the images ?

mighty willow
#

io.readall but its the net library ?

edgy ridge
#

io.ReadAll takes in an io.Reader

#

which is an interface implement by the tcp connection

#

so you can pass a tcp connection to io.ReadAll

mighty willow
#

ahh I see! I will try that, that sounds a lot simples

#

I am going to send the images to a webrtc connection in the future, right now I am just trying to send them for testing purposes

edgy ridge
#

it's not a great solution, uses lots of memory and is most often slower than streaming the file instead

#

how are you using it ? Writing it to a file ? Decoding it using the image librairy ?

mighty willow
#

have a video scene in the .net application

#

so basically sending frames

edgy ridge
#

you want to stream video between .net and golang ?

mighty willow
#

yes, it won't be production, I will probably use a better cross process communication in the future. But yes

#

video streaming from .net to golang and then next step attach it to a webrtc stream

edgy ridge
#

you might need to be carefull with performance. A 1080p video stream is around 1Gbps

#

that a problem you can solve later however

mighty willow
#

yeah that is tomorrows problem 🙂

edgy ridge
#

Last question, do you open a TCP connection per image or do you reuse the same one ?

mighty willow
#

same connection

edgy ridge
#

Ok so, you can't use io.ReadAll.
You could but it only returns after having red everything

#

So you will run out of memory very quickly as it keeps reading

#

and you can't stream images over webrtc

mighty willow
#

no it needs to be encoded also

edgy ridge
#

like ?

mighty willow
#

not gotten to that yet, I will be using pion and maybe ffmpeg in some capacity

edgy ridge
#

Ah so you aren't literally streaming images

mighty willow
#

so instead of io.ReadAll I should use?

edgy ridge
#

you will be using a video encoder ?

edgy ridge
mighty willow
#

.net video frame -> golang using websocket -> video encoding -> webrtc stream

edgy ridge
#

is the websocket going through multiple machines ?

mighty willow
#

not sure yet to be honest, just wanted to start by sending the images from .net to golang and golang seemed like a good first step

#

same machine

#

i might use named pipes in the future

edgy ridge
#

Yeah that sounds like a better idea.
Honnestly I would even use two of them and do that using named pipes:

.net → ffmpeg → golang → webrtc
mighty willow
#

was using .net webrtc framework but the support of webrtc was not stable and the ffmpeg adapter was even worse. No hardware encoding possible and very little control overall

edgy ridge
#

You can invoke ffmpeg cli

#

and then access pipes

#

kinda writting your own wrapper in that way

mighty willow
#

never done that, maybe a good option

edgy ridge
#

Anyway to send images, your best bet is to have .net preffix them with the length, read them one by one and reuse buffers

func DecodeFrames(r io.Reader, useFrame([]byte) error) error {
 buffer := make([]byte, 4)
 for {
  _, err := io.ReadFull(r, buffer[:4])
  if err != nil { return err }

  size := binary.LittleEndian.Uint32(buffer)
  if uint(len(buffer)) < uint(size) {
   buffer = make([]byte, size)
  }

  _, err = io.ReadFull(r, buffer[:size])
  if err != nil {
   if err == io.EOF { err = io.ErrUnexpectedEOF }
   return err
  }

  err = useFrame(buffer[:size])
  if err != nil { return err }
 }
}
#

Then in .net you need to send the size of the frame first, as 4 byte little endian (you can use bigendian if you want, both just needs to agree) and then the image

#

the point is that then you can easily know where one frame begins and when one ends

#

You also maybe want to add a limit on size and error if it is too big, because right now each connection can allocate 4GiB images which could use a lot of memory and crash the app

mighty willow
#

thank you that makes total sense!

#

just curious about the code

    if uint(len(buffer)) < uint(size) {

wont that like always be true, reusing the 4 byte[] that is used to get buffer size which is usually smaller than the data buffer itself?

edgy ridge
#

the buffer is outside the loop

#

you are correct this will most likely always be true in the first iteration

#

but after that the next image can reuse the buffer of the previous image

#

btw I realised I made a mistake the second .ReadFull call needs to be limited to size

#
  _, err = io.ReadFull(r, buffer[:size])
mighty willow
#

thanks.

#

btw for the ffmpeg solution do you happen to know if only cli call is possible or if you can use streams?

edgy ridge
#

at least in go you can stream over cli

#

let me find a link

#

#go-chat message

#

something along theses lines

#

(warning untested code)