Search code examples
c#windows-phone-8stream-socket-client

How to broadcast a message using StreamSocket


I followed a tutorial to create WindowsPhone devices connect via Stream Socket.

Sending message to eachother worked pretty well. But I don't know how to broadcast a message. Can someone show me how?

    private StreamSocket _socket = new StreamSocket();
    private StreamSocketListener _listener = new StreamSocketListener();
    private List<StreamSocket> _connections = new List<StreamSocket>();
    private bool _connecting = false;

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        //myConnectionTargetText.Text = "192.168.1.3";
        myConnectionTargetText.Text = "localhost"; // a TextBox
    }

    async private void WaitForData(StreamSocket socket)
    {
        var dr = new DataReader(socket.InputStream);
        //dr.InputStreamOptions = InputStreamOptions.Partial;
        var stringHeader = await dr.LoadAsync(4);

        if (stringHeader == 0)
        {
            LogMessage(string.Format("Disconnected (from {0})", socket.Information.RemoteHostName.DisplayName));
            return;
        }

        int strLength = dr.ReadInt32();

        uint numStrBytes = await dr.LoadAsync((uint)strLength);
        string msg = dr.ReadString(numStrBytes);

        LogMessage(string.Format("Received (from {0}): {1}", socket.Information.RemoteHostName.DisplayName, msg));

        WaitForData(socket);
    }

    async private void Connect(object sender, RoutedEventArgs e)
    {
        try
        {
            _connecting = true;
            await _socket.ConnectAsync(new HostName(myConnectionTargetText.Text), "3011");
            _connecting = false;

            LogMessage(string.Format("Connected to {0}", _socket.Information.RemoteHostName.DisplayName));

            WaitForData(_socket);
        }
        catch (Exception ex)
        {
            _connecting = false;
        }
    }

    async private void Listen(object sender, RoutedEventArgs e)
    {
        _listener.ConnectionReceived += listenerConnectionReceived;
        await _listener.BindServiceNameAsync("3011");

        LogMessage(string.Format("listening on {0}...", _listener.Information.LocalPort));
    }

    void listenerConnectionReceived(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args)
    {
        _connections.Add(args.Socket);

        LogMessage(string.Format("Incoming connection from {0}", args.Socket.Information.RemoteHostName.DisplayName));

        WaitForData(args.Socket);
    }

    private void LogMessage(string message)
    {
        Dispatcher.BeginInvoke(() =>
            {
                myText.Text += message + Environment.NewLine;
            });
    }

    async private void SendMessage(StreamSocket socket, string message)
    {
        var writer = new DataWriter(socket.OutputStream);
        var len = writer.MeasureString(message); // Gets the UTF-8 string length.
        writer.WriteInt32((int)len);
        writer.WriteString(message);
        var ret = await writer.StoreAsync();
        writer.DetachStream();

        LogMessage(string.Format("Sent (to {0}) {1}", socket.Information.RemoteHostName.DisplayName, message)); // richTextBox
    }

Solution

  • It's not possible to multicast over a stream socket, because a stream socket is an endpoint-to-endpoint connection.

    You have two options:

    1. Have all the clients connect to a central server, which dispatches messages appropriately. The server will have a list of all clients, so it can simulate a multicast by copying the message.
    2. Switch to UDP instead of TCP (i.e., DatagramSocket) and use multicasting.

    Note that switching to UDP brings its own set of problems: you lose reliability (packets may be lost), ordering (packets may arrive out of order), and there's a maximum datagram size (you'd have to split up your messages yourself). For this reason, most applications fake multicasting by using a central server.