1

I want to write a part of code in which I start sending packages using tcp stream, but without any part that receives it over the internet. In the meantime I would also like to have another method that can connect to that particular stream at any time and starts receiving bytes from the moment it connects. I wanted to use multicasting, but I see it's impossible to do it over the Internet Is there a way to do it? I only found some info so far, that the tcp connection in C# uses point to point way, so my case sounds impossible to implement, because the listener has to be always active to even initialize the streamer, how can I bypass that?

randomuser2
  • 107
  • 10
  • 3
    Sounds like you might want UDP instead of TCP... – Jon Skeet Mar 12 '15 at 09:39
  • Thanks for your answer, what I try to manage is to stream the video between two apps with the third one in the middle. So app1 would stream the data into app in the middle (let's call it app2), and app2 would forward this stream to show it on app3, but only when app3 is online. Otherwise it would be collected/flushed on app2 until the time app3 is online... What is more, I would like to have more apps like app1 and app3, that could connect with each other through app2, is it possible to have multiple streams between different apps being forwarded by one app in the middle? – randomuser2 Mar 12 '15 at 10:13
  • Use UDP. TCP link requires 2 parties. – i486 Mar 12 '15 at 10:28
  • Your use case sounds like a streaming server. Could you keep accepted clients in a list and simply write the same data to all of them? – usr Mar 12 '15 at 10:33

2 Answers2

4

Edit Added an example of a simply "broker" who republishes all messages it receives.

Either use UDP and broadcast your packets to an endpoint that may or maynot be listening at any point in time.

Or use a message queue such as MSMQ, RabbitMQ or 0MQ.

MSMQ may become a problem if the listening service is offline for to long as the messages queue on your dispatch system resulting in a backlog that may fill.

If you would like to create something using UDP here is some code.

Listener (server):

using System;
using System.Text;
using System.Net;
using System.Net.Sockets;

namespace UDPLISTENER
{
    class Program
    {
        static void Main(string[] args)
        {
            var port = 8750;
            var listener = new UdpClient(port);
            var group = new IPEndPoint(IPAddress.Any, port);

            Console.WriteLine("Listening for datagrams on port {0}", port);
            while(true)
            {
                var data = listener.Receive(ref group);
                Console.WriteLine("{0}: {1}", group.ToString(), Encoding.Default.GetString(data, 0, data.Length));
            }
        }
    }
}

Broker (Server&Client):

sing System;
using System.Text;
using System.Net;
using System.Net.Sockets;

namespace UDPCLIENT
{
    class Program
    {
        static void Main(string[] args)
        {
            int listeningPort = 8749, dispatchPort = 8750;
            var listener = new UdpClient(listeningPort);
            var group = new IPEndPoint(IPAddress.Any, listeningPort);

            // Republish client
            var sender = new UdpClient("127.0.0.1", dispatchPort);

            Console.WriteLine("Listening for datagrams on port {0}", listeningPort);
            while (true)
            {
                var data = listener.Receive(ref group);
                Console.WriteLine("{0}: {1}", group.ToString(), Encoding.Default.GetString(data, 0, data.Length));
                sender.Send(data, data.Length);
            }
        }
    }
}

Sender (Client):

using System;
using System.Text;
using System.Net;
using System.Net.Sockets;

namespace UDPSENDER
{
    class Program
    {
        static void Main(string[] args)
        {
            var sender = new UdpClient("127.0.0.1", 8749);

            while (true)
            {
                Console.WriteLine("Message: ");
                var data = Encoding.Default.GetBytes(Console.ReadLine());
                sender.Send(data, data.Length);
            }
        }
    }
}

Depending what you wish to archive I recommend message queues they give to the most flexibility.

But as you can see UDP works a bit differently to TCP. You don't need a handshake like TCP does, this means if no one is listening to your messages they vanish with no cost to the sender (there is still cost to the network). But if a listener pops up then they start consuming the messages right away. Remember no UDP packet is guaranteed delivery, this is both a blessing and a curse.

If you want messages to be guaranteed you need to implement your own solution, one method is a counter on the datagrams that the listener watches if there is a message missing then it request that message be resent.

brokkc
  • 53
  • 1
  • 7
  • Thank you for that example! And I have one more question - is it possible to introduce a third app - man in the middle, between client and listener? it would just receive bytes from client and transfer it to the listener... and also - is it possible to introduce many clients and many listeners (in relation 1 to 1) that connect through the single app in the middle? – randomuser2 Mar 12 '15 at 10:36
  • It sounds like you want to "broker" your streams yes you can do this. If you already have a over the wire protocol you can port that to UDP. You will need to figure out how you want the network traffic to be routed but you could use a channel. UDP is nice that you can throw any thing at it and it will just work, try the example and fire up serveral "clients" and fire them at the "server" and notice that they just work, no need to listen - create a socket - and start processing each sockets stream. – brokkc Mar 12 '15 at 10:39
  • It sounds like you have a problem with the overall design of the solution you're looking for. Sadly you're the best person to answer that question. I can say programmaticly you can achieve what you're after with UDP and TCP. UDP simply sounds like the better fit for your problems. I would write 3 systems a streamer a broker and a viewer, then make them all as generic as possible and use config files to drive them. Using the examples I listed you can see the listener can easily handle multiple clients, and the clients don't care if the listener is alive or not. – brokkc Mar 12 '15 at 10:54
  • Thanks! I just reviewed your edit and the code of man in the middle, it really helps to clear my doubts. What I want to achieve is to have the possibility like this: http://i.imgur.com/ObGQ5eF.png (sorry for poor paint skills) - to connect each client with each listener (1 to 1) through the man in the middle, on which the only thing will be the possibility of configuration which client connects with which listener... Using your example above - is it possible to run several clients and several listeners and connect each of them with one single Broker? – randomuser2 Mar 12 '15 at 11:18
  • Yes you could use the server (broker) as a sort of software router, this will introduce some (unneeded?) latency. Off the top of my head you could encode the ip/port or use a registry of listeners and encode their registration number into the datagrams as the first few bytes. Extract the information inside the broker create a new UDPClient (cache it inside a dictionary for fast lookup next time) and stream the message (with the encoded ip or registry removed). – brokkc Mar 12 '15 at 11:36
  • But looking at your diagram I don't see much reason for a broker unless you want to monitor, administrate or log the messages and you absolutely need the data flowing through your system. Another method would be to simply push to the clients what listeners they should be talking to. This would reduce unneeded latency introduced by the broker and its message processing. You have so many options, I think your best bet is to try making a few test systems and benchmark them. Don't forget some of this you can achieve using your network hardware (such as unicast/multicasting and routing). – brokkc Mar 12 '15 at 11:39
  • Thanks, I wanted to have the broker, so that I can control which client connects to which listener, change it from time to time and also maintain the whole system from it (like restart the client/listener, etc, but that's the problem for the future). Do you think it's a good idea to avoid putting the registration number in the datagram (I already have the architecture for that without the registration id being sent) and just recognize the client by the port number it uses? The same with listeners... – randomuser2 Mar 12 '15 at 11:45
  • And then based on that I could just connect them with each other and later, at some point - for example reconnect the client with some other listener, and previous listener to some other client (all based on their port numbers) – randomuser2 Mar 12 '15 at 11:46
  • I would have the broker connect to the clients and tell them directly who they should be talking to. Like an administration connection, this would greatly increase performance and reduce resource load on your broker. Another option is to have the clients read from a config file where they should be dispatching to and how they should be dispatching (unicast/multicast) and use FileSystemWatcher to watch when the config changes and updates its destination when needed. I would still use UDP though. Your broker can then ask for metrics from clients/listeners and check for service health issues. – brokkc Mar 12 '15 at 11:50
  • Ok, yes, the first option (broker without the stream, but with the possibility of changing each clients/listeners behavior) sounds reasonable. As the last thing - because this thread is getting enormous - could you give me some hint how could I manage each client app from the broker over the internet? Should I use tcp for that? Or maybe there's some clever way of doing that in C#? And by manage I mean check their statistics through the broker, change their parameters (ip of the listeners), etc. – randomuser2 Mar 12 '15 at 12:13
  • and by the way - if I know the client ip and it streams the data through UDP to listener on some defined ip and port - can I still use this stream and show it also in some different place? In general - can I use one client and display data on e.g. two or more listeners? I've read it's the functionality of multicast, but it seems to be impossible to use it over ip... – randomuser2 Mar 12 '15 at 12:14
  • I agree this thread is enormous. I would code the administration code to work over TCP (as you need reliable delivery) you could use a message queue with RPC support to speed up development (such as 0MQ or RabbitMQ or MSMQ), and have each client dial into the broker this brings its own problems - system down or un-routable the client/listener is offline. Multicast over [the internet is hard](http://stackoverflow.com/questions/3068497/udp-multicast-over-the-internet) but over a network you control [it is possible](http://www.jarloo.com/c-udp-multicasting-tutorial/). – brokkc Mar 12 '15 at 12:42
-1

You can create a new class derived from Stream, override the Write method, and manage the writing to the tcp clients here. You will be able to write to this stream from your code whether a client is connected or not. When no client is connected, the data will simply be ignored.

Andy
  • 3,631
  • 2
  • 23
  • 32