Reputation: 5897
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
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