I’m making a multyplayer game and I’m using java sockets for the server, the server is working very well but I think it needs some tweaks regarding the way I’m parsing/handling the requests.
-
I would like to know if there is a better way of parse the requests instead of splitting input lines by (,) commas like I’m doing.
-
Should the data sent between the client and server be encrypted in some way? Just a small encryption to obfuscate the requests on sniffers eyes. What is the best way of doing that?
-
And regarding the thread safe is it OK with Collections.synchronizedList and synchronized blocks on iterations? Or is there a better/cleaner way?
-
Finally is there any java sockes library that will do all those things above? If so should I use it or is that an overkill for a small java sokets game server.
-
Is any thing else that I should improve?
Thanks 🙂
Bellow is the basic structure of my server.
public class Servidor extends Thread {
private ServerSocket serverSocket;
public static boolean LISTENING = true;
private final List<Client> clients = Collections.synchronizedList(new ArrayList<Client>());
private final List<Game> games = Collections.synchronizedList(new ArrayList<Game>());
public Servidor() {
try {
serverSocket = new ServerSocket(SERVER_PORT);
} catch (IOException e) {
Log.add("error starting server: " + e);
}
}
@Override
public void run() {
// Wait for players to connect
while (LISTENING) {
try {
Client c = new Client(serverSocket.accept());
clients.add(c);
c.start();
} catch (IOException e) {}
}
}
class Client extends Thread {
private Socket socket;
private PrintWriter out;
private BufferedReader in;
private boolean loggedin;
private Player player;
private Game game;
public Cliente(Socket sock) {
socket = sock;
try {
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8")), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
} catch (IOException e) {
Log.add("error connecting to player!");
}
}
/* Send to this player */
public void send(String s) {
out.println(s);
}
/* Send to all players on the server */
public void boardcast(String s) {
synchronized (clients) {
for (Client c : clients) {
c.send(s);
}
}
}
/* Get player by ID */
private Player getPlayerByID(int playerID) {
synchronized (clients) {
for (Client c : clients) {
if (c.player != null) {
if (c.player.getID() == playerID) {
return c.player;
}
}
}
}
return null;
}
/* Split inputLine */
private String[] splitInput(String input, int argsNumber) {
String[] args = null;
try {
args = input.split(",", -1);
if (args.length != argsNumber) {
args = null;
}
} catch (Exception ex) {
Log.add("error splitting input");
} finally {
return args;
}
}
@Override
public void run() {
char cmd;
String inputLine, outputLine;
String[] args;
try {
loop:
while ((inputLine = in.readLine()) != null) {
// check if inputLine have 2 chars (CMD_TYPE:)
if (inputLine.length() < 2) {
kickPlayer();
break loop;
}
// get CMD
cmd = inputLine.charAt(0);
// remove (CMD_TYPE:) from inputLine
inputLine = inputLine.substring(2);
// check e player is logged (L:username,password)
if (!loggedin) {
// check if the input string have 2 arguments
if ((args = splitInput(inputLine, 2)) == null) {
kickPlayer();
break loop;
}else{
// ... TESTE LOGIN ON DATABASE ...
// set player data
player = new Player(query.getInt("player_id"), query.getString("username"), query.getInt("level"))
}
}else{
// Commands
switch (cmd) {
// P:CARD_ID,TARGET_ID eg:(P:5:3)
case CMD_PLAY:
// check if the input string have 2 arguments
if ((args = splitInput(inputLine, 2)) == null) {
kickPlayer();
break loop;
} else {
// ... VALIDATE OTHER PARAMETERS ...
// update game
game.addCard(args[0], args[0]);
// update players
boardcast(CMD_PLAY + ":" + player.getID+ "," + game.LastCard());
}
break;
// ... TEST OTHER COMMANDS ...
default:
Log.add("invalid command";
break loop;
}
}
}
} catch (IOException e) {
Log.add("connection lost";
} finally {
removeClient();
}
}
}
}
Adding basic security to communication is fairly simple and can be achieved without a lot of hassle. It took me a day of “googling” to figure out how to use it … I have forgotten most of the details but if you want I can upload the source of my project for you to have a look at … I personally would recommend some encryption before actually releasing the game…
A link for java ssl sockets can be found here
A link to create your own keystore can be found here
That should help you get started and message me if you want me to upload my source code.
As far as the lists are concerned most of the time you will only be reading the lists so I would suggest that you make a custom lock so that writers must acquire write lock whereas multiple readers can acquire the lock concurrently.. Will require you to design a new class or perhaps you can find a solution on-line.
As far as parsing the string is concerned, to the best of my knowledge objects can be passed remotely so you can transmit array of string instead of having to parse them. I personally broke my communication into several calls to read and write to input streams (probably the slowest approach 🙂 )
and any ways good luck with your project. Message me if you need the source 🙂
.