2

I have a metro app talking to a device over wifi using UDP. However, when I disconnect the device from the network or start the app with the device disconnected, nothing happens. ConnectAsync doesn't throw an exception, the app doesn't throw an exception, the app runs like nothing's wrong. I can't ping the other end but If I give it a formatted string it will respond. The device is currently connected to a router which has internet access but I'm eventually planning to use a router without internet access. I've never done anything with UDP so I'm at a loss here.

Here is an implementation of a UDP listener/writer(taken from Pete Bright at 10rem.net)

class Network
    {
        private DatagramSocket _socket;
        public bool IsConnected { get; set; }
        public bool recieved;
        public string ret;


        public Network()
        {
            IsConnected = false;

            _socket = new DatagramSocket();

            _socket.MessageReceived += OnSocketMessageReceived;
        }

        public async void Connect(HostName remoteHostName, string remoteServiceNameOrPort)
        {
            try
            {
              await  _socket.ConnectAsync(remoteHostName, remoteServiceNameOrPort);
            }
            catch (Exception e)
            {
                    var msg = new MessageDialog(e.ToString());
                    msg.ShowAsync();
            }
            IsConnected = true;
        }



        private void OnSocketMessageReceived(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs args)
        {
              var reader = args.GetDataReader();

                var count = reader.UnconsumedBufferLength;

                var data = reader.ReadString(count);

                ret = data.Trim();

                recieved = true;

        }


        DataWriter _writer =null;
        public async void SendMessage(string message)
        {
            if (String.IsNullOrEmpty(message)) return;
            if (_writer == null)
            {
                var stream = _socket.OutputStream;
                _writer = new DataWriter(stream);
            }

            _writer.WriteString(message);

            await _writer.StoreAsync();
        }            

    }
bakedpatato
  • 105
  • 5
  • 16

3 Answers3

2

UDP Sockets are "connection-less", so the protocol does not know anything about whether or not the server and client are connected. To know if a a connection is still "active" you will have to implement your own connection detection.

I might recommend reading beej's guide to sockets. It's a good read and pretty funny: http://beej.us/guide/bgnet/

user1892929
  • 135
  • 1
  • 5
  • Cool,thanks. I'm not sure how to write a connection detection scheme for this case;I can't determine that the device exists on the other end without pushing characters and waiting for a response and I can't push characters because both `ConnectAsync` and `GetOutputStreamAsync` do nothing and block all code under it(as it should) when there is no device. – bakedpatato Mar 07 '13 at 16:53
1

As it was said, there is no concept like there is in tcp/ip with sync/ack, etc to communicate back and forth and ensure something is there.

Clients are neither connected nor disconnected, only listening or sending really. So with that said you need to implement a receive timeout from the client.

There are some funny jokes with UDP, since you send data and just essentially fling it out into space. The order the packets are received can't matter either or you are stuck implementing your own scheme here as well.

What you'll need to do here is actually try to reach the device. If you care, then you can do this every X seconds.

As it is stated here: How to test a remote UDP Port

(keep with me, a better approach below this but wanted to provide multiple means)

You can use UdpClient, set a receive timeout on the underlying socket, 
make a connection to that remote server/port, Send some small message
 (byte[] !) and call Receive.

IF the port is closed you get an exception saying that the connection 
was forcibly closed (SocketException with
 ErrorCode 10054 = WSAECONNRESET)... which means the port is NOT open.

However- I think a better approach is to actually agree upon a protocol id or some specific data that the clients send every X seconds. If received, then update your 'client connected' table, otherwise consider them disconnected until the client sends a packet with a protocol id over.

A great series on this that you can probably easily adapt to c# is at: http://gafferongames.com/networking-for-game-programmers/virtual-connection-over-udp/

I believe your code above can be refactored as well to only Send() to an address rather than connect, since there really is no true connect.

Community
  • 1
  • 1
Adam Tuliper
  • 29,982
  • 4
  • 53
  • 71
0

To help out people that stumble upon this:Apparently my google-fu is pretty weak. This shows how to set timeouts for TCP and UDP sockets. Default behavior is to never time out(which is consistent with what I saw).

Edit: It doesn't work. Even with a timeout of 500ms I'm still seeing the same behavior of "no exception thrown".

bakedpatato
  • 105
  • 5
  • 16