Compare commits
10 Commits
8c2c09a339
...
e4b9d9553a
Author | SHA1 | Date | |
---|---|---|---|
|
e4b9d9553a | ||
|
d19c6dccde | ||
|
24a711e8c1 | ||
|
f6f9511537 | ||
|
51f3d88a8e | ||
|
bf2c69bb32 | ||
|
b6b6c07841 | ||
|
376a626506 | ||
|
4b9f582fd0 | ||
|
b9540f162f |
13
README.md
13
README.md
@ -1,16 +1,15 @@
|
|||||||
ConsoleChat
|
ConsoleChat-Server
|
||||||
===========
|
==================
|
||||||
|
This is the _server-side_ to the __ConsoleChat__ project. This code takes care of handling commands and sending the information to all the other clients connected.
|
||||||
|
|
||||||
This program was made as a personal project to learn Java network programming. The concept of it is rather simple, all it does is send messages to a server which, in turn, sends the message to everyone else (aside from some other commands added). Although the license is MIT, please consider also disclosing the source-code under an open-source license. It helps to give back to the community and help others just like this may have helped you.
|
### Compiling
|
||||||
|
|
||||||
###Compiling
|
|
||||||
To compile the source code, make sure you have JDK and Apache Ant installed. Then run the following command:
|
To compile the source code, make sure you have JDK and Apache Ant installed. Then run the following command:
|
||||||
```bash
|
```bash
|
||||||
$ ant
|
$ ant
|
||||||
```
|
```
|
||||||
|
|
||||||
###Contributing
|
### Contributing
|
||||||
To contribute to the project, simply open a pull request and I'll make sure to get back to you as soon as possible.
|
To contribute to the project, simply open a pull request and I'll make sure to get back to you as soon as possible.
|
||||||
|
|
||||||
###License
|
### License
|
||||||
This program is licensed with an [MIT license](/LICENSE). However, please take into account that you took from the community, and you should make sure to give back.
|
This program is licensed with an [MIT license](/LICENSE). However, please take into account that you took from the community, and you should make sure to give back.
|
||||||
|
14
build.xml
14
build.xml
@ -1,10 +1,9 @@
|
|||||||
<project name="ConsoleChat" basedir="." default="main" >
|
<project name="ConsoleChat-Server" basedir="." default="main" >
|
||||||
<property name="src.dir" value="src" />
|
<property name="src.dir" value="src" />
|
||||||
<property name="bin.dir" value="bin" />
|
<property name="bin.dir" value="bin" />
|
||||||
<property name="classes.dir" value="${bin.dir}/classes" />
|
<property name="classes.dir" value="${bin.dir}/classes" />
|
||||||
<property name="jar.dir" value="${bin.dir}/jar" />
|
<property name="jar.dir" value="${bin.dir}/jar" />
|
||||||
<property name="main-class-client" value="consolechat.client.Client" />
|
<property name="main-class" value="consolechat.server.Server" />
|
||||||
<property name="main-class-server" value="consolechat.server.Server" />
|
|
||||||
|
|
||||||
<target name="clean" >
|
<target name="clean" >
|
||||||
<delete dir="bin" />
|
<delete dir="bin" />
|
||||||
@ -17,14 +16,9 @@
|
|||||||
|
|
||||||
<target name="jar" depends="compile" >
|
<target name="jar" depends="compile" >
|
||||||
<mkdir dir="${jar.dir}" />
|
<mkdir dir="${jar.dir}" />
|
||||||
<jar destfile="${jar.dir}/${ant.project.name}-client.jar" basedir="${classes.dir}" >
|
<jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${classes.dir}" >
|
||||||
<manifest>
|
<manifest>
|
||||||
<attribute name="Main-Class" value="${main-class-client}" />
|
<attribute name="Main-Class" value="${main-class}" />
|
||||||
</manifest>
|
|
||||||
</jar>
|
|
||||||
<jar destfile="${jar.dir}/${ant.project.name}-server.jar" basedir="${classes.dir}" >
|
|
||||||
<manifest>
|
|
||||||
<attribute name="Main-Class" value="${main-class-server}" />
|
|
||||||
</manifest>
|
</manifest>
|
||||||
</jar>
|
</jar>
|
||||||
</target>
|
</target>
|
||||||
|
@ -1,116 +0,0 @@
|
|||||||
package consolechat.client;
|
|
||||||
|
|
||||||
import java.net.*;
|
|
||||||
import java.io.*;
|
|
||||||
import java.lang.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Nicolás A. Ortega
|
|
||||||
* @copyright Nicolás A. Ortega
|
|
||||||
* @license MIT
|
|
||||||
* @year 2014
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class Client implements Runnable {
|
|
||||||
private String version = "v1.0.1";
|
|
||||||
private Socket socket = null;
|
|
||||||
private ClientThread cThread = null;
|
|
||||||
private DataOutputStream streamOut = null;
|
|
||||||
private BufferedReader console = null;
|
|
||||||
private Thread thread = null;
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
if(args.length != 2) {
|
|
||||||
System.out.println("Usage: consolechat-client [server] [port]");
|
|
||||||
} else {
|
|
||||||
new Client(args[0], Integer.parseInt(args[1]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Constructor method
|
|
||||||
public Client(String server, int port) {
|
|
||||||
System.out.println("ConsoleChat client " + version + " Copyright (C) 2014 Nicolás A. Ortega\n" +
|
|
||||||
"This program comes with ABSOLUTELY NO WARRANTY; details in WARRANTY file.\n" +
|
|
||||||
"This is free software, and you are welcome to redistribute it\n" +
|
|
||||||
"under certain conditions; details in LICENSE file.\n");
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Create a new socket connection
|
|
||||||
System.out.println("Connecting to server...");
|
|
||||||
socket = new Socket(server, port);
|
|
||||||
System.out.println("Connected!");
|
|
||||||
start();
|
|
||||||
} catch(UnknownHostException uhe) {
|
|
||||||
System.out.println("Host unknown: " + uhe.getMessage());
|
|
||||||
} catch(IOException e) {
|
|
||||||
System.out.println("Unknown exception: " + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The run method containing the main loop
|
|
||||||
public void run() {
|
|
||||||
String uinput;
|
|
||||||
while(thread != null) {
|
|
||||||
try {
|
|
||||||
uinput = console.readLine();
|
|
||||||
if(uinput.equals("/clientVersion")) {
|
|
||||||
System.out.println(version);
|
|
||||||
} else {
|
|
||||||
streamOut.writeUTF(uinput);
|
|
||||||
streamOut.flush();
|
|
||||||
}
|
|
||||||
} catch(IOException e) {
|
|
||||||
System.out.println("Sending error: " + e.getMessage());
|
|
||||||
stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle messages
|
|
||||||
public void handle(String msg) {
|
|
||||||
if(msg.equals("/quit")) {
|
|
||||||
System.out.println("Goodbye bye. Press RETURN to exit...");
|
|
||||||
stop();
|
|
||||||
} else {
|
|
||||||
System.out.println(msg);
|
|
||||||
if(msg.length() > 6 && msg.substring(0, 5).equals("Kick:")) {
|
|
||||||
stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open and start all necessary threads
|
|
||||||
private void start() throws IOException {
|
|
||||||
console = new BufferedReader(new InputStreamReader(System.in));
|
|
||||||
streamOut = new DataOutputStream(socket.getOutputStream());
|
|
||||||
|
|
||||||
if(thread == null) {
|
|
||||||
cThread = new ClientThread(this, socket);
|
|
||||||
thread = new Thread(this);
|
|
||||||
thread.start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stop and close all necessary threads
|
|
||||||
public void stop() {
|
|
||||||
if(thread != null) {
|
|
||||||
thread.interrupt();
|
|
||||||
thread = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
if(console != null) { console.close(); }
|
|
||||||
if(streamOut != null) { streamOut.close(); }
|
|
||||||
if(socket != null) { socket.close(); }
|
|
||||||
} catch(IOException e) {
|
|
||||||
System.out.println("Error closing...");
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
cThread.close();
|
|
||||||
} catch(IOException e) {
|
|
||||||
System.out.println("Error closing the thread: " + e);
|
|
||||||
}
|
|
||||||
cThread.interrupt();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
package consolechat.client;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.net.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Nicolás A. Ortega
|
|
||||||
* @copyright Nicolás A. Ortega
|
|
||||||
* @license MIT
|
|
||||||
* @year 2014
|
|
||||||
*
|
|
||||||
* For details on the copyright, look at the COPYRIGHT file that came with
|
|
||||||
* this program.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class ClientThread extends Thread {
|
|
||||||
private Socket socket = null;
|
|
||||||
private Client client = null;
|
|
||||||
private DataInputStream streamIn = null;
|
|
||||||
private boolean run = false;
|
|
||||||
|
|
||||||
// Constructor
|
|
||||||
public ClientThread(Client _client, Socket _socket) {
|
|
||||||
client = _client;
|
|
||||||
socket = _socket;
|
|
||||||
open();
|
|
||||||
start();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open all necessary streams/threads
|
|
||||||
public void open() {
|
|
||||||
try {
|
|
||||||
streamIn = new DataInputStream(socket.getInputStream());
|
|
||||||
} catch(IOException e) {
|
|
||||||
System.out.println("Error getting input stream: " + e);
|
|
||||||
client.stop();
|
|
||||||
}
|
|
||||||
run = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close the streams
|
|
||||||
public void close() throws IOException {
|
|
||||||
if(streamIn != null) { streamIn.close(); }
|
|
||||||
run = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The run method which will be called every frame
|
|
||||||
public void run() {
|
|
||||||
while(run) {
|
|
||||||
try {
|
|
||||||
client.handle(streamIn.readUTF());
|
|
||||||
} catch(IOException e) {
|
|
||||||
System.out.println("Listening error: " + e.getMessage());
|
|
||||||
client.stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -10,17 +10,15 @@ import java.util.*;
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
* @year 2014
|
* @year 2014
|
||||||
*
|
*
|
||||||
* For details on the copyright, look at the COPYRIGHT file that came with
|
|
||||||
* this program.
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class Server implements Runnable {
|
public class Server implements Runnable {
|
||||||
private String version = "v1.0.1";
|
private String version = "v1.1";
|
||||||
private ArrayList<ServerThread> clients = new ArrayList<ServerThread>();
|
private ArrayList<ServerThread> clients = new ArrayList<ServerThread>();
|
||||||
private ServerSocket sSocket = null;
|
private ServerSocket sSocket = null;
|
||||||
private Thread thread = null;
|
private Thread thread = null;
|
||||||
private int clientCount = 0;
|
private int clientCount = 0;
|
||||||
private String passwd = "admin";
|
private String passwd = "admin";
|
||||||
|
private ArrayList<String> banned = new ArrayList<String>();
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
if(args.length != 1) {
|
if(args.length != 1) {
|
||||||
@ -45,6 +43,27 @@ public class Server implements Runnable {
|
|||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
System.out.println(e);
|
System.out.println(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read admin password
|
||||||
|
try {
|
||||||
|
BufferedReader passwdbuffer = new BufferedReader(new FileReader("adminpasswd.txt"));
|
||||||
|
try {
|
||||||
|
passwd = passwdbuffer.readLine();
|
||||||
|
} catch(IOException ioe) {
|
||||||
|
System.out.println("Error reading from adminpassword.txt.");
|
||||||
|
}
|
||||||
|
} catch(FileNotFoundException fnfe) { System.out.println("No adminpasswd.txt file."); }
|
||||||
|
|
||||||
|
// Read banned list
|
||||||
|
try {
|
||||||
|
String bannedIP;
|
||||||
|
BufferedReader banbuffer = new BufferedReader(new FileReader("banned.txt"));
|
||||||
|
try {
|
||||||
|
while((bannedIP = banbuffer.readLine()) != null) {
|
||||||
|
banned.add(bannedIP);
|
||||||
|
}
|
||||||
|
} catch(IOException ioe) { System.out.println("Error while reading from banned.txt"); }
|
||||||
|
} catch(FileNotFoundException fnfe) { System.out.println("No banned.txt file."); }
|
||||||
}
|
}
|
||||||
|
|
||||||
// The run method that will be called every frame
|
// The run method that will be called every frame
|
||||||
@ -124,6 +143,14 @@ public class Server implements Runnable {
|
|||||||
} else {
|
} else {
|
||||||
clients.get(findClient(id)).send("You are not admin.");
|
clients.get(findClient(id)).send("You are not admin.");
|
||||||
}
|
}
|
||||||
|
} else if(input.length() > 11 && input.substring(0, 4).equals("/ban")) {
|
||||||
|
if(clients.get(findClient(id)).isAdmin()) {
|
||||||
|
int bID = Integer.parseInt(input.substring(5, 10));
|
||||||
|
String reason = input.substring(11);
|
||||||
|
ban(bID, reason);
|
||||||
|
} else {
|
||||||
|
clients.get(findClient(id)).send("You are not admin.");
|
||||||
|
}
|
||||||
} else if(input.length() > 10 && input.substring(0, 10).equals("/giveadmin")) {
|
} else if(input.length() > 10 && input.substring(0, 10).equals("/giveadmin")) {
|
||||||
if(clients.get(findClient(id)).isAdmin()) {
|
if(clients.get(findClient(id)).isAdmin()) {
|
||||||
int aID = Integer.parseInt(input.substring(11));
|
int aID = Integer.parseInt(input.substring(11));
|
||||||
@ -144,10 +171,25 @@ public class Server implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ban a client
|
||||||
|
public void ban(int id, String reason) {
|
||||||
|
int pos = findClient(id);
|
||||||
|
if(pos < 0) return;
|
||||||
|
String clientAddress = clients.get(pos).getSocket().getRemoteSocketAddress().toString();
|
||||||
|
String clientIP = clientAddress.substring(1, clientAddress.indexOf(':'));
|
||||||
|
try {
|
||||||
|
PrintWriter banwriter = new PrintWriter(new BufferedWriter(new FileWriter("banned.txt", true)));
|
||||||
|
banwriter.println(clientIP);
|
||||||
|
banwriter.close();
|
||||||
|
} catch(IOException ioe) { System.out.println("Error printing client IP '" + clientIP + "' to banned.txt ."); }
|
||||||
|
clients.get(pos).send("You have been banned from this server.\nReason: " + reason);
|
||||||
|
remove(id);
|
||||||
|
}
|
||||||
|
|
||||||
// Remove a client
|
// Remove a client
|
||||||
public synchronized void remove(int id) {
|
public synchronized void remove(int id) {
|
||||||
int pos = findClient(id);
|
int pos = findClient(id);
|
||||||
if(pos >= 0) {
|
if(pos < 0) return;
|
||||||
ServerThread toTerminate = clients.get(pos);
|
ServerThread toTerminate = clients.get(pos);
|
||||||
System.out.println("Remove client thread: " + id + " at " + pos);
|
System.out.println("Remove client thread: " + id + " at " + pos);
|
||||||
try {
|
try {
|
||||||
@ -164,13 +206,20 @@ public class Server implements Runnable {
|
|||||||
}
|
}
|
||||||
toTerminate.interrupt();
|
toTerminate.interrupt();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Add a new client
|
// Add a new client
|
||||||
public void addThread(Socket socket) {
|
public void addThread(Socket socket) {
|
||||||
|
// If IP is banned to not admit!
|
||||||
|
String clientAddress = socket.getRemoteSocketAddress().toString();
|
||||||
|
String clientIP = clientAddress.substring(1, clientAddress.indexOf(':'));
|
||||||
|
for(int i = 0; i < banned.size(); i++) {
|
||||||
|
if(clientIP.equals(banned.get(i))) return;
|
||||||
|
}
|
||||||
|
// Otherwise add them
|
||||||
clients.add(new ServerThread(this, socket));
|
clients.add(new ServerThread(this, socket));
|
||||||
try {
|
try {
|
||||||
clients.get(clientCount).open();
|
clients.get(clientCount).open();
|
||||||
|
clients.get(clientCount).send("Use /help for a list of commands.\n");
|
||||||
clients.get(clientCount).start();
|
clients.get(clientCount).start();
|
||||||
clientCount++;
|
clientCount++;
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
@ -182,5 +231,16 @@ public class Server implements Runnable {
|
|||||||
public String getPasswd() { return passwd; }
|
public String getPasswd() { return passwd; }
|
||||||
|
|
||||||
// Setter methods
|
// Setter methods
|
||||||
public void setPasswd(String npasswd) { this.passwd = npasswd; }
|
public void setPasswd(String npasswd) {
|
||||||
|
this.passwd = npasswd;
|
||||||
|
try {
|
||||||
|
PrintWriter writer = new PrintWriter("adminpasswd.txt", "UTF-8");
|
||||||
|
writer.println(npasswd);
|
||||||
|
writer.close();
|
||||||
|
} catch(UnsupportedEncodingException uee) {
|
||||||
|
System.out.println("Error writing new password to adminpasswd.txt");
|
||||||
|
} catch(FileNotFoundException fnfe) {
|
||||||
|
System.out.println("Error writing new password to adminpasswd.txt");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,9 +9,6 @@ import java.io.*;
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
* @year 2014
|
* @year 2014
|
||||||
*
|
*
|
||||||
* For details on the copyright, look at the COPYRIGHT file that came with
|
|
||||||
* this program.
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class ServerThread extends Thread {
|
public class ServerThread extends Thread {
|
||||||
private Server server = null;
|
private Server server = null;
|
||||||
@ -74,7 +71,8 @@ public class ServerThread extends Thread {
|
|||||||
send("Admin commands:\n" +
|
send("Admin commands:\n" +
|
||||||
" - /chgpasswd [newpasswd] -- Change the server admin password.\n" +
|
" - /chgpasswd [newpasswd] -- Change the server admin password.\n" +
|
||||||
" - /giveadmin [id] -- Give another client admin as well.\n" +
|
" - /giveadmin [id] -- Give another client admin as well.\n" +
|
||||||
" - /kick [id] [reason] -- Kick out a user and state a reason for the kick.\n");
|
" - /kick [id] [reason] -- Kick out a user and state a reason for the kick.\n" +
|
||||||
|
" - /ban [id] [reason] -- Ban a user from ever being able to connect to the server again.\n");
|
||||||
}
|
}
|
||||||
} else if(command.length() > 6 && command.substring(0, 6).equals("/admin")) {
|
} else if(command.length() > 6 && command.substring(0, 6).equals("/admin")) {
|
||||||
if(command.substring(7).equals(server.getPasswd())) {
|
if(command.substring(7).equals(server.getPasswd())) {
|
||||||
@ -123,6 +121,7 @@ public class ServerThread extends Thread {
|
|||||||
|
|
||||||
// Getter methods
|
// Getter methods
|
||||||
public int getID() { return id; }
|
public int getID() { return id; }
|
||||||
|
public Socket getSocket() { return socket; }
|
||||||
public String getUsername() { return username; }
|
public String getUsername() { return username; }
|
||||||
public boolean isAdmin() { return admin; }
|
public boolean isAdmin() { return admin; }
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user