Canvas
Canvas

Reputation: 5897

UDP support multiple connections to same port, sending and receiving

At the moment I have a server that will allow clients to connect to it by sending a message "connect", when the server receives this message, it takes in the InetAddress, and then uses that InetAddress to send data to the client, once the client is connected and receives its ID number, it will constantly send data to the UDP socket so it can update its position, now when a new client wants to connect, it will send a message "connect" but only very rarely the new client will connect, What is happening is the client that is already connected is keeping the host.receive function busy, so when the new client goes to connect, it is lucky if the current client connected doesn't jump in the way, and then the client is just left with a blank screen.

What I need help with is, how can I support multiple clients on a UDP socket using the same port? All clients that will connect to the server are on the same Router,

Here is the whole server code

public class gameServer /*extends Thread*/ extends AsyncTask<String, String, String>{

/**
 * Sets up a server for Android applciation
 */
private static final String TAG = "GameServer";
private DatagramSocket socket;
private int port = 50000;
private int players = 0;
private String[] positions = new String[8];
private ArrayList<InetAddress> addresses = new ArrayList();
private boolean wait = false;
private Context contextHolder = null;

//Make an array, this array will hold all the positions
//the clients sent to it,
//using the ID number, it will store it in a array block
//and the "host" can just return it and use that

public gameServer( Context context ) throws IOException
{
    //Here we take in the clients block,
    //this will be assets[0];
    contextHolder = context;
    socket = new DatagramSocket( port );
    Log.d(TAG, "Server was setup");
}

public DatagramSocket rtnSocket(){ return socket; }

private String getLocalIPAddress()
{
    try
    {
        for (Enumeration<NetworkInterface> nis = NetworkInterface.getNetworkInterfaces(); nis.hasMoreElements();)
        {
            NetworkInterface ni = nis.nextElement();
            Log.v(TAG, "NetworkInterface = " + ni.getDisplayName());
            for (Enumeration<InetAddress> ips = ni.getInetAddresses(); ips.hasMoreElements();)
            {
                InetAddress ip = ips.nextElement();
                String s = ip.getHostAddress();
                Log.v(TAG, "InetAddress = " + s);
                if (!ip.isLoopbackAddress())
                {
                            if(InetAddressUtils.isIPv4Address(s)) return s;
                }
            }
        }
    }
    catch (SocketException e)
    {
            Log.e(TAG,"getLocalIPAddress()", e);
    }
    return null;
}

public void getClientPosition(int xPos, int yPos)
{
    positions[0] = xPos + ":" + yPos;
}

@Override
protected String doInBackground(String... params) {
    InetAddress client = null;
    boolean run = true;
    String data = "";
    DatagramPacket packet = null;
    boolean position = false;
    while( run )
    {
        if( data.equalsIgnoreCase( "" ) )
        {

        }

        //Send some data
        if( data.equalsIgnoreCase( "connect" ) && wait == true )
        {
            Log.d(TAG, "Someone wants to connect");
            //Increase the total players by 1
            players = players + 1;
            //Notify to the host (client) something has change
            //notify client
            //Send a message to the client with the ID
            byte[] bufer = new byte[256];
            //Send a message "connect" to the host
            String msg = Integer.toString( players );
            int msgLength = msg.length();
            bufer = msg.getBytes();
            InetAddress address;
            //Default ip address of the host
            //Take the address from the packet
            addresses.add( packet.getAddress() );
            Log.d(TAG, "Address is " + addresses.get( addresses.size() - 1 ) );
            address = addresses.get( addresses.size() - 1 );
            DatagramPacket p = new DatagramPacket( bufer, bufer.length , address, port );
            //Send packet
            try 
            {
                socket.send( p );
            } 
            catch (IOException e) 
            {
                e.printStackTrace();
            }

            wait = false;
        }

        if( wait == true && position == true )
        {
            position = false;
            wait = false;
        }

        for(int i = 0;i < positions.length; i++)
        {
            if(positions[i] != null)
            {
            //Log.d(TAG, "X and Y position of asset:"+i+", is:"+ positions[i]);
            }
        }

        //Needs to try and reteive data...
        if( wait == false )
        {
            //Log.d(TAG, "Waiting to retreive data");
            byte[] buf = new byte[256];
            packet = new DatagramPacket( buf, buf.length );
            try 
            {
                socket.receive( packet );
                wait = true;
            } 
            catch (IOException e) 
            {
                Log.d(TAG, "Error with receiving data");
                e.printStackTrace();
            }

            data = new String( buf, 0, packet.getLength() );
            //Log.d(TAG, "Data received from :" + packet.getAddress() + ", holds this value: " + data);
            String[] dataStrings = data.split(":");
            if( dataStrings[0].equalsIgnoreCase( "position" ) )
            {
                position = true;
            }
        }



        //Log.d(TAG, "Data received was :" + data);

        /*try 
        {
            Thread.sleep( 25 );
        } 
        catch (InterruptedException e) 
        {
            // TODO Auto-generated catch block
            Log.d(TAG, "Error with trying to sleep");
            e.printStackTrace();
        }*/
    }
    Log.d(TAG, "Error with while run value");
    return "finished";
}

public int returnPlayers(){ return players; }
}

Here is the Client code

public class gameClient extends AsyncTask<String, String, String> 
{

//Variables
private static final String TAG = "gameClient";
private gameServer server;
private boolean rdyForPlay = false;
//Holds all of the over clients blocks
private gameObject[] assets = new gameObject[8];
private int ID = 0;
private int port = 50000;
private Context contextHolder;
//If this client is the host
private boolean host = false;
private DatagramSocket socket = null;
//How many clients are connected to the server
private int totalPlayers = 0;

//Constructor for gameclient
public gameClient( boolean serverTag, Context context )
{
    host = serverTag;
    //Client is host
    if( host == true)
    {
        host = true;
        try 
        {
            //Start the server
            contextHolder = context;
            server = new gameServer( contextHolder );
            this.execute();
        } 
        catch (IOException e) 
        {
            //Error
            Log.d(TAG, "Could not start server");
            e.printStackTrace();
        }
    }
    //Client is not host
    else
    {
        //Connect to the host
        contextHolder = context;
        this.execute();
    }
}

//Connect to the host, to receive and send data to
public void connectToServer()
{
    //Send a connect message to the server
    try {
        //Create a socket
        socket = new DatagramSocket( port );
        byte[] bufer = new byte[256];
        //Send a message "connect" to the host
        String msg = "connect";
        int msgLength = msg.length();
        bufer = msg.getBytes();
        InetAddress address;
        //Default ip address of the host
        address = InetAddress.getByName("192.168.1.59");
        DatagramPacket p = new DatagramPacket( bufer, bufer.length , address, port );
        //Send packet
        socket.send( p );

    } catch (UnknownHostException e2) {
        Log.d(TAG, "Unknown host");
        e2.printStackTrace();
    } catch (SocketException e) {
        Log.d(TAG, "Socket problem");
        e.printStackTrace();
    } catch (IOException e) {
        Log.d(TAG, "I/O problem");
        e.printStackTrace();
    }

    //Receive the message back
    byte[] buf = new byte[256];
    DatagramPacket packet = new DatagramPacket( buf, buf.length );
    //Try to receive a packet from the server
    try 
    {
        Log.d(TAG, "Waiting for data");
        socket.receive( packet );
    } 
    //Error
    catch (IOException e) 
    {
        Log.d(TAG, "Error with receiving data");
        e.printStackTrace();
    }

    //Convert the packet to a string
    String data = new String( buf, 0, packet.getLength() );

    //Use the string to find out what ID this client is
    ID = Integer.parseInt( data );
    //Setup the client game
    setUpClient();
}

//Setup the client game/screen
public void setUpClient()
{
    //Setup the client using the ID that was given by the host
    Log.d(TAG, "ID is : " + ID);
    gameObject temp = new gameObject(BitmapFactory.decodeResource(contextHolder.getResources(), R.drawable.player), 250, 300);
    assets[ID] = temp;
    for(int i = 0; i < ID; i++)
    {
        temp = new gameObject(BitmapFactory.decodeResource(contextHolder.getResources(), R.drawable.new_player), 50*i, 50*i);
        assets[i] = temp;
    }

    //If this client is the host, then pass the client to the server for easy access
    if( host == true )
    {
    server.getClientPosition( assets[ID].returnPosX(), assets[ID].returnPosY() );
    }
}

//When the screen is touched
public void sendTouchEvent(float xSet, float ySet)
{
    assets[ID].setPosition( xSet, ySet );
}

@Override
//Keep the game updated
protected String doInBackground(String... params)
{
    //Connect to the server
    if( host == false ){ while(ID == 0) { Log.d( TAG, "Client will connect to server" ); connectToServer(); } }
    //If the client is host, then start the server thread
    if( host == true ) { setUpClient(); server.execute(); }
    //game us now ready to be played
    rdyForPlay = true;
    boolean run = true;
    boolean setupPlayer = false;

    while( run )
    {
        int players = 0;
        //Tell the server to give position of players
        //if( setupPlayer == true )
        //{
        //  setUpClient();
        //  setupPlayer = false;
        //}
        if( host == true )
        {
            server.getClientPosition( assets[ID].returnPosX(), assets[ID].returnPosY() );
            int newPlayers = server.returnPlayers();
            if( players != newPlayers )
            {
                for(int i = players; i < newPlayers; i++)
                {
                    i = i+1;
                    gameObject temp = new gameObject(BitmapFactory.decodeResource(contextHolder.getResources(), R.drawable.new_player), 50*i, 50*i);
                    assets[i] = temp;
                }
                players = newPlayers;
            }

        }

        //If this is a client then do this
        if( host == false )
        {
            try {
                //If the socket is not yet setup, set it up
                if(socket == null)
                {
                    socket = new DatagramSocket( port );
                }
                byte[] bufer = new byte[256];
                //Using the ID given at the start, send X and Y position to the server
                String msg = "position:" + ID +":"+ assets[ID].returnPosX() +":"+ assets[ID].returnPosY();
                int msgLength = msg.length();
                bufer = msg.getBytes();
                InetAddress address;
                address = InetAddress.getByName("192.168.1.59");
                DatagramPacket p = new DatagramPacket( bufer, bufer.length , address, port );
                //Send the data
                socket.send( p );
                Log.d(TAG, "data sent");

            } catch (UnknownHostException e2) {
                // TODO Auto-generated catch block
                Log.d(TAG, "Error with unknown host");
                e2.printStackTrace();
            } catch (SocketException e) {
                // TODO Auto-generated catch block
                Log.d(TAG, "Error with socket");
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                Log.d(TAG, "Error with sending/receiving data");
                e.printStackTrace();
            }


        }

        //Host data will ofcourse be differnet

    }
    Log.d(TAG, "Error with run value");
    return "finished";
}

//If a new player needs to be added to the array
private void newPlayer( int idOfNewPlayer )
{
    gameObject temp = new gameObject(BitmapFactory.decodeResource(contextHolder.getResources(), R.drawable.new_player), 250, 300);
    assets[ idOfNewPlayer ] = temp;
}

//Update all the assets in the game
private void updateAssets()
{

}

//Return methods
public gameObject[] rtnAssets(){ return assets; }
public int rtnID(){ return ID; }
public boolean rtnRdy(){ return rdyForPlay; }
public gameServer rtnServer(){ return server; }
public boolean rtnHost(){ return host; }
//Stop the client server if host
public void stopServers()
{
    if( host == true )
    {
    socket.close();
    server.rtnSocket().close();
    System.gc();
    }
}

public void stopBackground()
{
    socket.close();
    this.cancel( true );
    System.gc();
}
}

Upvotes: 1

Views: 7275

Answers (1)

ds345
ds345

Reputation: 737

Wheneva we request for a connection we'll kwn of one port number and request. So, try to keep that port free. It can be done by using the other ports in ur system which are free. So when a client requests for connection reply back with a port number and assign that client with that port number. Our system can support upto 10k connection due to so many logical ports. So I assume it shouldnt be a problem for many users. And once connection is established, user will communicate on the port it is assigned to and thus other users can access ur server easily.

Upvotes: 2

Related Questions