From e5db999b31e67683ad0e75b2e3ae4bc255dac6d7 Mon Sep 17 00:00:00 2001 From: Imanol-Mikel Barba Sabariego Date: Wed, 25 Dec 2013 22:06:32 +0000 Subject: [PATCH] git-svn-id: svn://imanolbarba.net/PAD@39 c2ee353e-ed0d-4329-bf56-03aec153487f --- JChatServer/.classpath | 6 ++++++ JChatServer/.project | 17 +++++++++++++++++ JChatServer/.settings/org.eclipse.jdt.core.prefs | 11 +++++++++++ JChatServer/bin/pad/prac2/ChatException.class | Bin 0 -> 496 bytes JChatServer/bin/pad/prac2/Connection.class | Bin 0 -> 3730 bytes JChatServer/bin/pad/prac2/JChat$1.class | Bin 0 -> 774 bytes JChatServer/bin/pad/prac2/JChat.class | Bin 0 -> 1315 bytes JChatServer/bin/pad/prac2/MyServerSocket.class | Bin 0 -> 1532 bytes JChatServer/bin/pad/prac2/MySocket.class | Bin 0 -> 3210 bytes JChatServer/bin/pad/prac2/Server.class | Bin 0 -> 6261 bytes JChatServer/src/pad/prac2/ChatException.java | 21 +++++++++++++++++++++ JChatServer/src/pad/prac2/Connection.java | 153 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ JChatServer/src/pad/prac2/JChat.java | 30 ++++++++++++++++++++++++++++++ JChatServer/src/pad/prac2/MyServerSocket.java | 47 +++++++++++++++++++++++++++++++++++++++++++++++ JChatServer/src/pad/prac2/MySocket.java | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ JChatServer/src/pad/prac2/Server.java | 196 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 16 files changed, 599 insertions(+), 0 deletions(-) create mode 100644 JChatServer/.classpath create mode 100644 JChatServer/.project create mode 100644 JChatServer/.settings/org.eclipse.jdt.core.prefs create mode 100644 JChatServer/bin/pad/prac2/ChatException.class create mode 100644 JChatServer/bin/pad/prac2/Connection.class create mode 100644 JChatServer/bin/pad/prac2/JChat$1.class create mode 100644 JChatServer/bin/pad/prac2/JChat.class create mode 100644 JChatServer/bin/pad/prac2/MyServerSocket.class create mode 100644 JChatServer/bin/pad/prac2/MySocket.class create mode 100644 JChatServer/bin/pad/prac2/Server.class create mode 100644 JChatServer/src/pad/prac2/ChatException.java create mode 100644 JChatServer/src/pad/prac2/Connection.java create mode 100644 JChatServer/src/pad/prac2/JChat.java create mode 100644 JChatServer/src/pad/prac2/MyServerSocket.java create mode 100644 JChatServer/src/pad/prac2/MySocket.java create mode 100644 JChatServer/src/pad/prac2/Server.java diff --git a/JChatServer/.classpath b/JChatServer/.classpath new file mode 100644 index 0000000..fb565a5 --- /dev/null +++ b/JChatServer/.classpath @@ -0,0 +1,6 @@ + + + + + + diff --git a/JChatServer/.project b/JChatServer/.project new file mode 100644 index 0000000..28dac34 --- /dev/null +++ b/JChatServer/.project @@ -0,0 +1,17 @@ + + + JChatServer + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/JChatServer/.settings/org.eclipse.jdt.core.prefs b/JChatServer/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..7341ab1 --- /dev/null +++ b/JChatServer/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,11 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.7 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.7 diff --git a/JChatServer/bin/pad/prac2/ChatException.class b/JChatServer/bin/pad/prac2/ChatException.class new file mode 100644 index 0000000..0e0d11e Binary files /dev/null and b/JChatServer/bin/pad/prac2/ChatException.class differ diff --git a/JChatServer/bin/pad/prac2/Connection.class b/JChatServer/bin/pad/prac2/Connection.class new file mode 100644 index 0000000..53b85cd Binary files /dev/null and b/JChatServer/bin/pad/prac2/Connection.class differ diff --git a/JChatServer/bin/pad/prac2/JChat$1.class b/JChatServer/bin/pad/prac2/JChat$1.class new file mode 100644 index 0000000..e8fef6f Binary files /dev/null and b/JChatServer/bin/pad/prac2/JChat$1.class differ diff --git a/JChatServer/bin/pad/prac2/JChat.class b/JChatServer/bin/pad/prac2/JChat.class new file mode 100644 index 0000000..5c8923a Binary files /dev/null and b/JChatServer/bin/pad/prac2/JChat.class differ diff --git a/JChatServer/bin/pad/prac2/MyServerSocket.class b/JChatServer/bin/pad/prac2/MyServerSocket.class new file mode 100644 index 0000000..97d4974 Binary files /dev/null and b/JChatServer/bin/pad/prac2/MyServerSocket.class differ diff --git a/JChatServer/bin/pad/prac2/MySocket.class b/JChatServer/bin/pad/prac2/MySocket.class new file mode 100644 index 0000000..ea93697 Binary files /dev/null and b/JChatServer/bin/pad/prac2/MySocket.class differ diff --git a/JChatServer/bin/pad/prac2/Server.class b/JChatServer/bin/pad/prac2/Server.class new file mode 100644 index 0000000..a6de29a Binary files /dev/null and b/JChatServer/bin/pad/prac2/Server.class differ diff --git a/JChatServer/src/pad/prac2/ChatException.java b/JChatServer/src/pad/prac2/ChatException.java new file mode 100644 index 0000000..ab9017e --- /dev/null +++ b/JChatServer/src/pad/prac2/ChatException.java @@ -0,0 +1,21 @@ +package pad.prac2; + +public class ChatException extends Exception +{ + + /** + * + */ + private static final long serialVersionUID = 2263415822589627234L; + + public ChatException() + { + super(); + } + + public ChatException(String message) + { + super(message); + } + +} diff --git a/JChatServer/src/pad/prac2/Connection.java b/JChatServer/src/pad/prac2/Connection.java new file mode 100644 index 0000000..3d8c263 --- /dev/null +++ b/JChatServer/src/pad/prac2/Connection.java @@ -0,0 +1,153 @@ +package pad.prac2; + +import java.io.IOException; + +public class Connection extends Thread +{ + private MySocket socket; + private Server serv; + private boolean sleep, kill; + + public Connection(Server s) + { + serv = s; + kill = false; + sleep = true; + } + + public void awake() + { + synchronized(this) + { + sleep = false; + this.notify(); + } + } + + public void finish() + { + kill = true; + if(sleep) + { + sleep = false; + notify(); + } + socket.close(); + } + + public void setSock(MySocket s) + { + socket = s; + } + + public void sendMessage(String message) throws IOException + { + socket.sendMsg(message); + } + + public void run() + { + while(!kill) + { + while(sleep) + { + try + { + synchronized(this) + { + wait(); + } + } + catch (InterruptedException e) + { + e.printStackTrace(); + } + } + if(!kill) + { + String str; + try + { + str = socket.recvMsg(); + while(str.contains(" ")) + { + socket.sendMsg("CHATNICKINVALID"); + str = socket.recvMsg(); + } + while(serv.isOnline(str)) + { + socket.sendMsg("CHATNICKEXIST"); + str = socket.recvMsg(); + } + socket.sendMsg("CHATOK"); + serv.addToChatroom(this, str); + } + catch (IOException e) + { + if(!kill) + { + System.out.println("TCP: Communication with client failed while entering chatroom"); + sleep = true; + serv.finishWorker(this); + } + continue; + } + while(true) + { + try + { + str = "/disconnect"; + str = socket.recvMsg(); + if(str.equals("/disconnect")) + { + socket.sendMsg("DISC_OK"); + System.out.println(serv.getNickname(this) + " disconnected"); + break; + } + else if(str.equals("/exit")) + { + socket.sendMsg("EXIT_OK"); + System.out.println(serv.getNickname(this) + " disconnected"); + break; + } + else if(str.equals("/who")) + { + socket.sendMsg(serv.listOnline()); + } + else if(str.startsWith("@")) + { + try + { + if(!str.contains(" ")) + { + serv.sendTo(this,str.substring(1),""); + } + else + { + serv.sendTo(this,str.substring(1,str.indexOf(' ')),str.substring(str.indexOf(' ')+1)); + } + } + catch(ChatException cE) + { + socket.sendMsg(cE.getMessage()); + } + } + else + { + System.out.println("FROM " + serv.getNickname(this) + ": " + str); + serv.sendToChat(this,str); + } + } + catch(IOException ioExc) + { + System.out.println("TCP: Error writing to socket"); + System.out.println(serv.getNickname(this) + " disconnected"); + break; + } + } + sleep = true; + } + serv.finishWorker(this); + } + } +} diff --git a/JChatServer/src/pad/prac2/JChat.java b/JChatServer/src/pad/prac2/JChat.java new file mode 100644 index 0000000..a906273 --- /dev/null +++ b/JChatServer/src/pad/prac2/JChat.java @@ -0,0 +1,30 @@ +package pad.prac2; + +import java.util.Scanner; + +public class JChat +{ + public static void main(String[] args) + { + String ip; + int port, roomSize; + Scanner in = new Scanner(System.in); + System.out.print("IP: "); + ip = in.nextLine(); + System.out.print("Port: "); + port = in.nextInt(); + System.out.print("Size of chatroom: "); + roomSize = in.nextInt(); + in.close(); + final Server serv = new Server(ip,port,roomSize); + Runtime.getRuntime().addShutdownHook(new Thread() + { + public void run() + { + System.out.println("JChat: Caught interrupt, killing server..."); + serv.killServer(); + } + }); + serv.startServer(); + } +} diff --git a/JChatServer/src/pad/prac2/MyServerSocket.java b/JChatServer/src/pad/prac2/MyServerSocket.java new file mode 100644 index 0000000..ae9a6e3 --- /dev/null +++ b/JChatServer/src/pad/prac2/MyServerSocket.java @@ -0,0 +1,47 @@ +package pad.prac2; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.SocketAddress; + +public class MyServerSocket extends ServerSocket +{ + public MyServerSocket() throws IOException + { + super(); + } + + public void bind(String ip, int port) + { + SocketAddress addr = new InetSocketAddress(ip,port); + try + { + super.bind(addr, 5); + } + catch(IOException ioExc) + { + System.out.println("TCP: Error binding socket to address"); + } + } + + public MySocket accept() throws IOException + { + MySocket incoming = new MySocket(); + super.implAccept(incoming); + incoming.initializeStreams(); + return incoming; + } + + public void close() + { + try + { + super.close(); + } + catch(IOException ioExc) + { + System.out.println("TCP: Error while closing socket"); + } + } +} diff --git a/JChatServer/src/pad/prac2/MySocket.java b/JChatServer/src/pad/prac2/MySocket.java new file mode 100644 index 0000000..26d367b --- /dev/null +++ b/JChatServer/src/pad/prac2/MySocket.java @@ -0,0 +1,118 @@ +package pad.prac2; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketAddress; + +public class MySocket extends Socket +{ + private BufferedReader input; + private OutputStream output; + + public MySocket() + { + super(); + } + + public void connect(String host, int port) + { + SocketAddress addr = new InetSocketAddress(host,port); + try + { + super.connect(addr); + initializeStreams(); + } + catch(IOException ioExc) + { + System.out.println("TCP: Error occured while connecting to remote host"); + } + } + + public void initializeStreams() + { + try + { + output = super.getOutputStream(); + input = new BufferedReader(new InputStreamReader(super.getInputStream())); + } + catch(IOException ioExc) + { + System.out.println("TCP: Error initializing socket"); + } + } + + public void sendMsg(String msg) throws IOException + { + String length = new Integer(msg.length()).toString(); + this.write(length + '\0' + msg); + } + + public String recvMsg() throws IOException + { + String len,str; + int length; + len = this.readLine(); + if(len == "") + { + return len; + } + length = Integer.parseInt(len); + str = this.read(length); + return str; + } + + public void write(String str) throws IOException + { + output.write(str.getBytes()); + } + + public String read(int bytes) + { + char[] buffer = new char[bytes]; + try + { + input.read(buffer, 0, bytes); + return new String(buffer); + } + catch(IOException ioExc) + { + System.out.println("TCP: Error retrieving data from remote endpoint"); + return null; + } + } + + public String readLine() throws IOException + { + + String line = ""; + char[] c = new char[1]; + while(true) + { + input.read(c,0,1); + if(c[0] == '\0') + { + break; + } + line += c[0]; + } + return line; + } + + public void close() + { + try + { + super.shutdownInput(); + super.shutdownOutput(); + super.close(); + } + catch(IOException ioExc) + { + System.out.println("TCP: Error while closing socket"); + } + } +} \ No newline at end of file diff --git a/JChatServer/src/pad/prac2/Server.java b/JChatServer/src/pad/prac2/Server.java new file mode 100644 index 0000000..4d860de --- /dev/null +++ b/JChatServer/src/pad/prac2/Server.java @@ -0,0 +1,196 @@ +package pad.prac2; + +import java.io.IOException; +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +public class Server +{ + private MyServerSocket ss; + private int roomSize; + private boolean kill; + private Connection[] workerPool; + private int freeWorkers; + private Lock lock; + private Condition availableWorkers; + private ConcurrentHashMap activeConnections; + + public Server(String ip, int port, int rS) + { + try + { + ss = new MyServerSocket(); + lock = new ReentrantLock(); + activeConnections = new ConcurrentHashMap(); + roomSize = rS; + freeWorkers = roomSize; + kill = false; + availableWorkers = lock.newCondition(); + workerPool = new Connection[roomSize]; + for(int i = 0; i < roomSize; i++) + { + workerPool[i] = new Connection(this); + workerPool[i].start(); + } + ss.bind(ip, port); + } + catch(IOException ioExc) + { + System.out.println("TCP: Error initializating server socket"); + } + } + + public void startServer() + { + while(!kill) + { + try + { + MySocket incoming = ss.accept(); + startWorker(incoming); + } + catch(IOException ioExc) + { + if(!kill) + { + System.out.println("TCP: Error accepting connection"); + break; + } + } + } + + } + + public void startWorker(MySocket s) + { + lock.lock(); + while(freeWorkers == 0) + { + try + { + s.sendMsg("CHATFULL"); + s.close(); + lock.unlock(); + return; + } + catch(IOException ioExc) + { + System.out.println("TCP: Error while sending message to client"); + } + } + workerPool[roomSize - freeWorkers].setSock(s); + workerPool[roomSize - freeWorkers].awake(); + workerPool[roomSize - freeWorkers] = null; + freeWorkers--; + lock.unlock(); + } + + public void finishWorker(Connection c) + { + lock.lock(); + removeFromChatroom(c); + freeWorkers++; + workerPool[roomSize - freeWorkers] = c; + availableWorkers.signal(); + lock.unlock(); + } + + public void sendTo(Connection orig, String nick, String msg) throws IOException, ChatException + { + lock.lock(); + System.out.println("FROM " + getNickname(orig) + " TO " + nick + ": " + msg); + msg = getNickname(orig) + ": " + msg; + Set conns = activeConnections.keySet(); + Iterator it = conns.iterator(); + Connection dest; + while(it.hasNext()) + { + dest = it.next(); + if(getNickname(dest).equals(nick)) + { + dest.sendMessage(msg); + lock.unlock(); + return; + } + } + lock.unlock(); + throw new ChatException("No such nickname"); + } + + public void sendToChat(Connection origin, String message) throws IOException + { + lock.lock(); + String nickname = activeConnections.get(origin); + Set connections = activeConnections.keySet(); + Iterator it = connections.iterator(); + Connection conn; + while(it.hasNext()) + { + conn = it.next(); + if(conn != origin) + { + conn.sendMessage(nickname + ": " + message); + } + } + lock.unlock(); + } + + public String getNickname(Connection c) + { + return activeConnections.get(c); + } + + public void addToChatroom(Connection c, String nickName) + { + activeConnections.put(c, nickName); + System.out.println(nickName + " has entered the room"); + } + + private void removeFromChatroom(Connection c) + { + activeConnections.remove(c); + } + + public boolean isOnline(String nick) + { + return activeConnections.contains(nick); + } + + public String listOnline() + { + lock.lock(); + String ret = new Integer(activeConnections.size()).toString(); + ret += " people currently online:"; + Collection nickNames = activeConnections.values(); + Iterator it = nickNames.iterator(); + while(it.hasNext()) + { + ret += "\n"; + ret += it.next(); + } + lock.unlock(); + return ret; + } + + public void killServer() + { + kill = true; + ss.close(); + finishConnections(); + } + + public void finishConnections() + { + Set conns = activeConnections.keySet(); + Iterator it = conns.iterator(); + while(it.hasNext()) + { + it.next().finish(); + } + } +} -- libgit2 0.22.2