0

I'm trying to push the contents of a single input stream to multiple output streams obtained from tcp sockets. I didn't find any existing solution, so I built something from scratch but I really feel I'm reinventing the wheel. My requirements are:

  • Java. Would be nice if it runs on Android as well, but that's optional.
  • Up to around 10 clients
  • Clients can be frequently added/removed
  • Each client should receive roughly the same bytes/sec
  • Throughput should decline as little as possible when a new client is added
  • Solution should not be specific to certain data (i.e. while I'm testing with raw h264 the solution should handle text streams just as fine)

So, firstly, is there a lib that meets these requirements?

If not, how can I improve the performance of my own solution (see below). I use it like this:

  • On application startup I run an instance of this class in a new thread.
  • If a client connects, the output stream of the respective socket is attached to that instance

While it works, the throughput on each client with N clients attached is extremely unstable. There seems to be no throughput function with respect to N. (Disclaimer: I testet from a single client using multiple threads) I think the performance of this solution is influenced mainly by two things:

  • Thread synchronization for the consumer collection, adding/removing consumers will block writing to all streams.
  • Iteration time on that collection since iterator() will probably create a new instance every time but I need that remove() function.

I'll appreciate any suggestions, thanks.

public class InfiniteStreamingResource implements Runnable {

    private LinkedHashSet<OutputStream> consumers;
    private byte[] buf;
    private boolean running;
    InputStream stream;

    Logger logger = Logger.getLogger(InfiniteStreamingResource.class);

    public InfiniteStreamingResource(InputStream stream, int bufSize) {
        this.stream = stream
        consumers = new LinkedHashSet<>(100);
        buf = new byte[bufSize];
    }

    public synchronized void attachConsumer(OutputStream consumer) {
        consumers.add(consumer);
    }

    public synchronized void stop() {
        running = false;
    }

    @Override
    public void run() {
        running = true;
        int bytesRead;
        Iterator<OutputStream> it;
        OutputStream current;
        try {
            while ((bytesRead = stream.read(buf)) > 0 && running) {
                synchronized(this) {
                    it = consumers.iterator();
                    while (it.hasNext()) {
                        current = it.next();
                        try {
                            current.write(buf, 0, bytesRead);
                        } catch (IOException e) {
                            if (e instanceof SocketException) {
                                it.remove();
                                try {
                                    current.close();
                                } catch (IOException inner) {
                                    //ignore
                                }
                            } else {
                            e.printStackTrace();
                            }
                        }
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        for (OutputStream consumer : consumers) { //if stopped, close any remaining streams
            try {
                consumer.close();
            } catch (IOException e) {
                //ignore
            }
        }

    }


}
bewi
  • 321
  • 3
  • 9

1 Answers1

0

I would decide depending on your data you want to send.

If it is raw byte data (e.g. video streaming) I don't know a library.

In the case of text or Java objects use RabbitMQ Therefore you need to install a Broker. This can receives the messages from your publisher and forwarding it to all subscribed clients.

Its easy to implement (also in Android).

mr.wolle
  • 1,148
  • 2
  • 13
  • 21
  • I can't decide depending on the data, so the question is really aims for raw byte streams and interpretation of the data is up to the clients. – bewi Jul 05 '14 at 12:03