Finding server with broadcast

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • pekspro@home.se

    #1

    Finding server with broadcast

    I need some code that gets the address from a server. I read somewhere
    that you could do this by starting some broadcast server using UDP. The
    client should send an broadcast message, and when the server answering
    the client gets the address. But how do I implement this?

    I did this simple quick-hack:

    Server:
    Socket server = new Socket(AddressF amily.InterNetw ork,
    SocketType.Dgra m, ProtocolType.Ud p);
    server.Bind( new IPEndPoint( IPAddress.Any, 48000 ) );

    while(true)
    {
    byte[] buffer = new byte[1000];
    server.Receive( buffer);

    Console.Write(" Server got: " + buffer[0]);
    //Next line crash cause some permission error.
    server.SendTo( new byte[] {2},
    new IPEndPoint( IPAddress.Broad cast, 48000 ) );
    }

    Client:
    Socket client = new Socket(AddressF amily.InterNetw ork,
    SocketType.Dgra m, ProtocolType.Ud p);
    client.Connect( new IPEndPoint( IPAddress.Broad cast, 48000 ));

    Console.Write(" Client send: 1");
    client.Send( new byte[] {1} );

    byte[] buffer = new byte[1000];
    client.Receive( buffer);
    Console.Write(" Client got: " + buffer[0]);

    client.Close();

    To my surprise the code almost worked :-). The server receive the
    message from the client, but it fails when sending data. And even if it
    did it doesn't help the client cause will not know who send the
    message.

    I'm thankful for any ideas. What I'm looking for is a way to find the
    address of a server. It doesn't need to be perfect, it will just give
    the users a hint which address to use for the real application.

  • Markus Stoeger

    #2
    Re: Finding server with broadcast

    pekspro@home.se wrote:
    [color=blue]
    > I did this simple quick-hack:[/color]

    see below
    [color=blue]
    > Server:
    > Socket server = new Socket(AddressF amily.InterNetw ork,
    > SocketType.Dgra m, ProtocolType.Ud p);
    > server.Bind( new IPEndPoint( IPAddress.Any, 48000 ) );
    >
    > while(true)
    > {
    > byte[] buffer = new byte[1000];
    > server.Receive( buffer);[/color]

    use ReceiveFrom here. this will give you an IPEndPoint with the address of
    the sending client.
    [color=blue]
    > Console.Write(" Server got: " + buffer[0]);
    > //Next line crash cause some permission error.
    > server.SendTo( new byte[] {2},
    > new IPEndPoint( IPAddress.Broad cast, 48000 ) );[/color]

    don't send the response back by broadcast. you can send it directly to the
    client using the above IPEndPoint.
    [color=blue]
    > }
    >
    > Client:
    > Socket client = new Socket(AddressF amily.InterNetw ork,
    > SocketType.Dgra m, ProtocolType.Ud p);
    > client.Connect( new IPEndPoint( IPAddress.Broad cast, 48000 ));[/color]

    not sure if Connect should be used for a connectionless (UDP) socket. I
    think it should work, but I always prefer the SendTo and ReceiveFrom
    functions for UDP. also you might want to use port 0 for the client. this
    way some free source port will be allocated automatically. in your case, if
    client and server are running on the same system, they will both access
    port 48000, which might fail.
    [color=blue]
    >
    > Console.Write(" Client send: 1");
    > client.Send( new byte[] {1} );
    >
    > byte[] buffer = new byte[1000];
    > client.Receive( buffer);
    > Console.Write(" Client got: " + buffer[0]);
    >
    > client.Close();[/color]

    hth,
    Max

    Comment

    • pekspro@home.se

      #3
      Re: Finding server with broadcast

      Markus Stoeger wrote:[color=blue]
      >not sure if Connect should be used for a connectionless (UDP) socket. I
      >think it should work, but I always prefer the SendTo and ReceiveFrom
      >functions for UDP. also you might want to use port 0 for the client. this
      >way some free source port will be allocated automatically. in your case, if
      >client and server are running on the same system, they will both access
      >port 48000, which might fail.[/color]

      Thank you, I followed your instructions and now the code works. I also
      tried to use port 0 on the client, but then the server didn't received
      any message (btw, should I use bind on the server?).

      This is the code that have so far. Works pretty well:

      Server:
      //Start server
      Socket server = new Socket(AddressF amily.InterNetw ork,
      SocketType.Dgra m, ProtocolType.Ud p);
      Console.Write(" Running server..." + Environment.New Line);
      server.Bind( new IPEndPoint( IPAddress.Any, 48000 ) );

      while(true)
      {
      IPEndPoint sender = new IPEndPoint(IPAd dress.Any, 0);
      EndPoint tempRemoteEP = (EndPoint)sende r;
      byte[] buffer = new byte[1000];
      //Recive message from anyone.
      server.ReceiveF rom(buffer, ref tempRemoteEP);

      Console.Write(" Server got '" + buffer[0] +
      "' from " + tempRemoteEP.To String() +
      Environment.New Line);

      Console.Write(" Sending '2' to " + tempRemoteEP.To String() +
      Environment.New Line);

      //Replay to client
      server.SendTo( new byte[] {2},
      tempRemoteEP );
      }

      Client:
      Socket client = new Socket(AddressF amily.InterNetw ork,
      SocketType.Dgra m,
      ProtocolType.Ud p);

      IPEndPoint AllEndPoint = new IPEndPoint( IPAddress.Broad cast, 48000 );

      //Allow sending broadcast messages
      client.SetSocke tOption(SocketO ptionLevel.Sock et,
      SocketOptionNam e.Broadcast, 1);

      //Send message to everyone
      client.SendTo( new byte[] {1}, AllEndPoint );
      Console.Write(" Client send '1' to " + AllEndPoint.ToS tring() +
      Environment.New Line);

      IPEndPoint sender = new IPEndPoint(IPAd dress.Any, 0);
      EndPoint tempRemoteEP = (EndPoint)sende r;
      byte[] buffer = new byte[1000];

      string serverIp;

      try
      {
      //Recieve from server. Don't wait more than 3000 milliseconds.
      client.SetSocke tOption(SocketO ptionLevel.Sock et,
      SocketOptionNam e.ReceiveTimeou t, 3000);
      client.ReceiveF rom(buffer, ref tempRemoteEP);
      Console.Write(" Client got '" + buffer[0] + "' from " +
      tempRemoteEP.To String()+ Environment.New Line);

      //Get server IP (ugly)
      serverIp = tempRemoteEP.To String().Split( ":".ToCharArray (), 2)[0];
      }
      catch
      {
      //Timout. No server answered.
      serverIp = "?";
      }

      Console.Write(" ServerIp: " + serverIp + Environment.New Line);

      Comment

      • Markus Stoeger

        #4
        Re: Finding server with broadcast

        pekspro@home.se wrote:
        [color=blue]
        > Thank you, I followed your instructions and now the code works. I also
        > tried to use port 0 on the client, but then the server didn't received
        > any message[/color]

        I think you have to bind the port on the client side also. Then it should
        work with port 0 (haven't tried it right now though).
        [color=blue]
        > (btw, should I use bind on the server?).[/color]

        Yes you have to, otherwise it doesn't know where to listen for the
        broadcast.

        Have you tested this code on a system with multiple network interfaces yet?
        I did something like that a while ago and as far as I remember such a
        broadcast is only sent out on one interface, not on all. You have to lookup
        the network interface addresses and send a broadcast on each of them. You
        can use the Dns functions to resolve your computers hostname, that should
        give you all available local network interface addresses.

        Max

        Comment

        • pekspro@home.se

          #5
          Re: Finding server with broadcast

          Markus Stoeger wrote:[color=blue]
          > I think you have to bind the port on the client side also. Then it should
          > work with port 0 (haven't tried it right now though).[/color]

          I added a bind call in the client code. It failed, as expected, cause
          two programs where listening on port 48000 at the same time. I then
          changed to port 0. No program crashed, but the client didn't find the
          server.
          [color=blue]
          > Have you tested this code on a system with multiple network interfaces yet?
          > I did something like that a while ago and as far as I remember such a
          > broadcast is only sent out on one interface, not on all. You have to lookup
          > the network interface addresses and send a broadcast on each of them. You
          > can use the Dns functions to resolve your computers hostname, that should
          > give you all available local network interface addresses.[/color]

          Good point. I could get all addresses by calling:
          string hostname = System.Net.Dns. GetHostName();
          IPHostEntry allLocalNetwork Addresses = Dns.Resolve(hos tname);

          But how do I use that information? Creating EndPoint like this:

          foreach(IPAddre ss ip in allLocalNetwork Addresses.Addre ssList)
          {
          IPEndPoint AllEndPoint = new IPEndPoint( ip, Port );

          will only make the client call it self to find the server. In the
          original code I do this:

          IPEndPoint AllEndPoint = new IPEndPoint( IPAddress.Broad cast, Port );

          How do I get the broadcast address for each network?

          PEK

          Comment

          • Markus Stoeger

            #6
            Re: Finding server with broadcast

            pekspro@home.se wrote:
            [color=blue]
            > Markus Stoeger wrote:
            > Good point. I could get all addresses by calling:
            > string hostname = System.Net.Dns. GetHostName();
            > IPHostEntry allLocalNetwork Addresses = Dns.Resolve(hos tname);
            >
            > But how do I use that information?[/color]

            I don't have the source code here right now, but I think you have to create
            one socket for each ip address that you get from Dns.Resolve. Then bind the
            sockets to these addresses (instead of binding them to IPAddress.Any).
            When you call SendTo, use IPAddress.Broad cast as destination.
            This way it will be sent out as broadcast on exactly the interface you have
            bound the socket to. You'll also have to call ReceiveFrom on each socket.
            [color=blue][color=green]
            >> I think you have to bind the port on the client side also. Then it should
            >> work with port 0 (haven't tried it right now though).[/color]
            >
            > I added a bind call in the client code. It failed, as expected, cause
            > two programs where listening on port 48000 at the same time. I then
            > changed to port 0. No program crashed, but the client didn't find the
            > server.[/color]

            It should work.. maybe there is another problem? Take a look at the Bind
            description on MSDN: http://tinyurl.com/cqoce
            It says "If you do not care which local port is used, you can create an
            IPEndPoint using 0 for the port number. In this case, the service provider
            will assign an available port number between 1024 and 5000."

            hth,
            Max

            Comment

            • pekspro@home.se

              #7
              Re: Finding server with broadcast

              Markus Stoeger wrote:[color=blue]
              > I don't have the source code here right now, but I think you have to create
              > one socket for each ip address that you get from Dns.Resolve. Then bind the
              > sockets to these addresses (instead of binding them to IPAddress.Any).
              > When you call SendTo, use IPAddress.Broad cast as destination.
              > This way it will be sent out as broadcast on exactly the interface you have
              > bound the socket to. You'll also have to call ReceiveFrom on each socket.[/color]

              Yes, of course. I should have figured out that myself.

              [color=blue]
              > It should work.. maybe there is another problem? Take a look at the Bind
              > description on MSDN: http://tinyurl.com/cqoce
              > It says "If you do not care which local port is used, you can create an
              > IPEndPoint using 0 for the port number. In this case, the service provider
              > will assign an available port number between 1024 and 5000."[/color]

              My mathematical knowledge tells me that 48000 > 5000 :-). Changing to
              port 4800 solved the final problem. To those that are interested, this
              is the code:

              Server:
              //Start server
              const int Port = 4800;
              Socket server = new Socket(AddressF amily.InterNetw ork,
              SocketType.Dgra m, ProtocolType.Ud p);
              Console.Write(" Running server..." + Environment.New Line);
              server.Bind( new IPEndPoint( IPAddress.Any, Port ) );

              while(true)
              {
              IPEndPoint sender = new IPEndPoint(IPAd dress.Any, 0);
              EndPoint tempRemoteEP = (EndPoint)sende r;
              byte[] buffer = new byte[1000];
              //Recive message from anyone.
              //Server could crash here if there is another server
              //on the network listening at the same port.
              server.ReceiveF rom(buffer, ref tempRemoteEP);

              Console.Write(" Server got '" + buffer[0] +
              "' from " + tempRemoteEP.To String() + Environment.New Line);

              Console.Write(" Sending '2' to " + tempRemoteEP.To String() +
              Environment.New Line);

              //Replay to client
              server.SendTo( new byte[] {2},
              tempRemoteEP );
              }

              Client:
              const int Port = 4800;
              string serverIp = "?";

              //Get all addresses
              string hostname = System.Net.Dns. GetHostName();
              IPHostEntry allLocalNetwork Addresses = Dns.Resolve(hos tname);

              //Walk thru all network interfaces.
              foreach(IPAddre ss ip in allLocalNetwork Addresses.Addre ssList)
              {
              Socket client = new Socket(AddressF amily.InterNetw ork,
              SocketType.Dgra m, ProtocolType.Ud p);

              //Bind on port 0. The OS will give some port between 1025 and 5000.
              client.Bind( new IPEndPoint( ip, 0 ) );

              //Create endpoint, broadcast.
              IPEndPoint AllEndPoint = new IPEndPoint( IPAddress.Broad cast, Port );

              //Allow sending broadcast messages
              client.SetSocke tOption(SocketO ptionLevel.Sock et,
              SocketOptionNam e.Broadcast, 1);

              //Send message to everyone on this network
              client.SendTo( new byte[] {1}, AllEndPoint );
              Console.Write(" Client send '1' to " + AllEndPoint.ToS tring() +
              Environment.New Line);

              try
              {
              //Create object for the server.
              IPEndPoint sender = new IPEndPoint(IPAd dress.Any, 0);
              EndPoint tempRemoteEP = (EndPoint)sende r;
              byte[] buffer = new byte[1000];

              //Recieve from server. Don't wait more than 3000 milliseconds.
              client.SetSocke tOption(SocketO ptionLevel.Sock et,
              SocketOptionNam e.ReceiveTimeou t, 3000);

              //Recive message, save wherefrom in tempRemoteIp
              client.ReceiveF rom(buffer, ref tempRemoteEP);
              Console.Write(" Client got '" + buffer[0] + "' from " +
              tempRemoteEP.To String()+ Environment.New Line);

              //Get server IP (ugly)
              serverIp = tempRemoteEP.To String().Split( ":".ToCharArray (), 2)[0];

              //Don't try any more networkss
              break;
              }
              catch
              {
              //Timout. No server answered. Try next network.
              }
              }

              Console.Write(" ServerIp: " + serverIp + Environment.New Line);


              Thanks for your excellent support Max!

              PEK

              Comment

              Working...