Commit e5db999b31e67683ad0e75b2e3ae4bc255dac6d7
1 parent
823b4632
git-svn-id: svn://imanolbarba.net/PAD@39 c2ee353e-ed0d-4329-bf56-03aec153487f
Showing
16 changed files
with
599 additions
and
0 deletions
JChatServer/.classpath
0 → 100644
1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
2 | +<classpath> | ||
3 | + <classpathentry kind="src" path="src"/> | ||
4 | + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/> | ||
5 | + <classpathentry kind="output" path="bin"/> | ||
6 | +</classpath> |
JChatServer/.project
0 → 100644
1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
2 | +<projectDescription> | ||
3 | + <name>JChatServer</name> | ||
4 | + <comment></comment> | ||
5 | + <projects> | ||
6 | + </projects> | ||
7 | + <buildSpec> | ||
8 | + <buildCommand> | ||
9 | + <name>org.eclipse.jdt.core.javabuilder</name> | ||
10 | + <arguments> | ||
11 | + </arguments> | ||
12 | + </buildCommand> | ||
13 | + </buildSpec> | ||
14 | + <natures> | ||
15 | + <nature>org.eclipse.jdt.core.javanature</nature> | ||
16 | + </natures> | ||
17 | +</projectDescription> |
JChatServer/.settings/org.eclipse.jdt.core.prefs
0 → 100644
1 | +eclipse.preferences.version=1 | ||
2 | +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled | ||
3 | +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 | ||
4 | +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve | ||
5 | +org.eclipse.jdt.core.compiler.compliance=1.7 | ||
6 | +org.eclipse.jdt.core.compiler.debug.lineNumber=generate | ||
7 | +org.eclipse.jdt.core.compiler.debug.localVariable=generate | ||
8 | +org.eclipse.jdt.core.compiler.debug.sourceFile=generate | ||
9 | +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error | ||
10 | +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error | ||
11 | +org.eclipse.jdt.core.compiler.source=1.7 |
JChatServer/bin/pad/prac2/ChatException.class
0 → 100644
No preview for this file type
JChatServer/bin/pad/prac2/Connection.class
0 → 100644
No preview for this file type
JChatServer/bin/pad/prac2/JChat$1.class
0 → 100644
No preview for this file type
JChatServer/bin/pad/prac2/JChat.class
0 → 100644
No preview for this file type
JChatServer/bin/pad/prac2/MyServerSocket.class
0 → 100644
No preview for this file type
JChatServer/bin/pad/prac2/MySocket.class
0 → 100644
No preview for this file type
JChatServer/bin/pad/prac2/Server.class
0 → 100644
No preview for this file type
JChatServer/src/pad/prac2/ChatException.java
0 → 100644
1 | +package pad.prac2; | ||
2 | + | ||
3 | +public class ChatException extends Exception | ||
4 | +{ | ||
5 | + | ||
6 | + /** | ||
7 | + * | ||
8 | + */ | ||
9 | + private static final long serialVersionUID = 2263415822589627234L; | ||
10 | + | ||
11 | + public ChatException() | ||
12 | + { | ||
13 | + super(); | ||
14 | + } | ||
15 | + | ||
16 | + public ChatException(String message) | ||
17 | + { | ||
18 | + super(message); | ||
19 | + } | ||
20 | + | ||
21 | +} |
JChatServer/src/pad/prac2/Connection.java
0 → 100644
1 | +package pad.prac2; | ||
2 | + | ||
3 | +import java.io.IOException; | ||
4 | + | ||
5 | +public class Connection extends Thread | ||
6 | +{ | ||
7 | + private MySocket socket; | ||
8 | + private Server serv; | ||
9 | + private boolean sleep, kill; | ||
10 | + | ||
11 | + public Connection(Server s) | ||
12 | + { | ||
13 | + serv = s; | ||
14 | + kill = false; | ||
15 | + sleep = true; | ||
16 | + } | ||
17 | + | ||
18 | + public void awake() | ||
19 | + { | ||
20 | + synchronized(this) | ||
21 | + { | ||
22 | + sleep = false; | ||
23 | + this.notify(); | ||
24 | + } | ||
25 | + } | ||
26 | + | ||
27 | + public void finish() | ||
28 | + { | ||
29 | + kill = true; | ||
30 | + if(sleep) | ||
31 | + { | ||
32 | + sleep = false; | ||
33 | + notify(); | ||
34 | + } | ||
35 | + socket.close(); | ||
36 | + } | ||
37 | + | ||
38 | + public void setSock(MySocket s) | ||
39 | + { | ||
40 | + socket = s; | ||
41 | + } | ||
42 | + | ||
43 | + public void sendMessage(String message) throws IOException | ||
44 | + { | ||
45 | + socket.sendMsg(message); | ||
46 | + } | ||
47 | + | ||
48 | + public void run() | ||
49 | + { | ||
50 | + while(!kill) | ||
51 | + { | ||
52 | + while(sleep) | ||
53 | + { | ||
54 | + try | ||
55 | + { | ||
56 | + synchronized(this) | ||
57 | + { | ||
58 | + wait(); | ||
59 | + } | ||
60 | + } | ||
61 | + catch (InterruptedException e) | ||
62 | + { | ||
63 | + e.printStackTrace(); | ||
64 | + } | ||
65 | + } | ||
66 | + if(!kill) | ||
67 | + { | ||
68 | + String str; | ||
69 | + try | ||
70 | + { | ||
71 | + str = socket.recvMsg(); | ||
72 | + while(str.contains(" ")) | ||
73 | + { | ||
74 | + socket.sendMsg("CHATNICKINVALID"); | ||
75 | + str = socket.recvMsg(); | ||
76 | + } | ||
77 | + while(serv.isOnline(str)) | ||
78 | + { | ||
79 | + socket.sendMsg("CHATNICKEXIST"); | ||
80 | + str = socket.recvMsg(); | ||
81 | + } | ||
82 | + socket.sendMsg("CHATOK"); | ||
83 | + serv.addToChatroom(this, str); | ||
84 | + } | ||
85 | + catch (IOException e) | ||
86 | + { | ||
87 | + if(!kill) | ||
88 | + { | ||
89 | + System.out.println("TCP: Communication with client failed while entering chatroom"); | ||
90 | + sleep = true; | ||
91 | + serv.finishWorker(this); | ||
92 | + } | ||
93 | + continue; | ||
94 | + } | ||
95 | + while(true) | ||
96 | + { | ||
97 | + try | ||
98 | + { | ||
99 | + str = "/disconnect"; | ||
100 | + str = socket.recvMsg(); | ||
101 | + if(str.equals("/disconnect")) | ||
102 | + { | ||
103 | + socket.sendMsg("DISC_OK"); | ||
104 | + System.out.println(serv.getNickname(this) + " disconnected"); | ||
105 | + break; | ||
106 | + } | ||
107 | + else if(str.equals("/exit")) | ||
108 | + { | ||
109 | + socket.sendMsg("EXIT_OK"); | ||
110 | + System.out.println(serv.getNickname(this) + " disconnected"); | ||
111 | + break; | ||
112 | + } | ||
113 | + else if(str.equals("/who")) | ||
114 | + { | ||
115 | + socket.sendMsg(serv.listOnline()); | ||
116 | + } | ||
117 | + else if(str.startsWith("@")) | ||
118 | + { | ||
119 | + try | ||
120 | + { | ||
121 | + if(!str.contains(" ")) | ||
122 | + { | ||
123 | + serv.sendTo(this,str.substring(1),""); | ||
124 | + } | ||
125 | + else | ||
126 | + { | ||
127 | + serv.sendTo(this,str.substring(1,str.indexOf(' ')),str.substring(str.indexOf(' ')+1)); | ||
128 | + } | ||
129 | + } | ||
130 | + catch(ChatException cE) | ||
131 | + { | ||
132 | + socket.sendMsg(cE.getMessage()); | ||
133 | + } | ||
134 | + } | ||
135 | + else | ||
136 | + { | ||
137 | + System.out.println("FROM " + serv.getNickname(this) + ": " + str); | ||
138 | + serv.sendToChat(this,str); | ||
139 | + } | ||
140 | + } | ||
141 | + catch(IOException ioExc) | ||
142 | + { | ||
143 | + System.out.println("TCP: Error writing to socket"); | ||
144 | + System.out.println(serv.getNickname(this) + " disconnected"); | ||
145 | + break; | ||
146 | + } | ||
147 | + } | ||
148 | + sleep = true; | ||
149 | + } | ||
150 | + serv.finishWorker(this); | ||
151 | + } | ||
152 | + } | ||
153 | +} |
JChatServer/src/pad/prac2/JChat.java
0 → 100644
1 | +package pad.prac2; | ||
2 | + | ||
3 | +import java.util.Scanner; | ||
4 | + | ||
5 | +public class JChat | ||
6 | +{ | ||
7 | + public static void main(String[] args) | ||
8 | + { | ||
9 | + String ip; | ||
10 | + int port, roomSize; | ||
11 | + Scanner in = new Scanner(System.in); | ||
12 | + System.out.print("IP: "); | ||
13 | + ip = in.nextLine(); | ||
14 | + System.out.print("Port: "); | ||
15 | + port = in.nextInt(); | ||
16 | + System.out.print("Size of chatroom: "); | ||
17 | + roomSize = in.nextInt(); | ||
18 | + in.close(); | ||
19 | + final Server serv = new Server(ip,port,roomSize); | ||
20 | + Runtime.getRuntime().addShutdownHook(new Thread() | ||
21 | + { | ||
22 | + public void run() | ||
23 | + { | ||
24 | + System.out.println("JChat: Caught interrupt, killing server..."); | ||
25 | + serv.killServer(); | ||
26 | + } | ||
27 | + }); | ||
28 | + serv.startServer(); | ||
29 | + } | ||
30 | +} |
JChatServer/src/pad/prac2/MyServerSocket.java
0 → 100644
1 | +package pad.prac2; | ||
2 | + | ||
3 | +import java.io.IOException; | ||
4 | +import java.net.InetSocketAddress; | ||
5 | +import java.net.ServerSocket; | ||
6 | +import java.net.SocketAddress; | ||
7 | + | ||
8 | +public class MyServerSocket extends ServerSocket | ||
9 | +{ | ||
10 | + public MyServerSocket() throws IOException | ||
11 | + { | ||
12 | + super(); | ||
13 | + } | ||
14 | + | ||
15 | + public void bind(String ip, int port) | ||
16 | + { | ||
17 | + SocketAddress addr = new InetSocketAddress(ip,port); | ||
18 | + try | ||
19 | + { | ||
20 | + super.bind(addr, 5); | ||
21 | + } | ||
22 | + catch(IOException ioExc) | ||
23 | + { | ||
24 | + System.out.println("TCP: Error binding socket to address"); | ||
25 | + } | ||
26 | + } | ||
27 | + | ||
28 | + public MySocket accept() throws IOException | ||
29 | + { | ||
30 | + MySocket incoming = new MySocket(); | ||
31 | + super.implAccept(incoming); | ||
32 | + incoming.initializeStreams(); | ||
33 | + return incoming; | ||
34 | + } | ||
35 | + | ||
36 | + public void close() | ||
37 | + { | ||
38 | + try | ||
39 | + { | ||
40 | + super.close(); | ||
41 | + } | ||
42 | + catch(IOException ioExc) | ||
43 | + { | ||
44 | + System.out.println("TCP: Error while closing socket"); | ||
45 | + } | ||
46 | + } | ||
47 | +} |
JChatServer/src/pad/prac2/MySocket.java
0 → 100644
1 | +package pad.prac2; | ||
2 | + | ||
3 | +import java.io.BufferedReader; | ||
4 | +import java.io.IOException; | ||
5 | +import java.io.InputStreamReader; | ||
6 | +import java.io.OutputStream; | ||
7 | +import java.net.InetSocketAddress; | ||
8 | +import java.net.Socket; | ||
9 | +import java.net.SocketAddress; | ||
10 | + | ||
11 | +public class MySocket extends Socket | ||
12 | +{ | ||
13 | + private BufferedReader input; | ||
14 | + private OutputStream output; | ||
15 | + | ||
16 | + public MySocket() | ||
17 | + { | ||
18 | + super(); | ||
19 | + } | ||
20 | + | ||
21 | + public void connect(String host, int port) | ||
22 | + { | ||
23 | + SocketAddress addr = new InetSocketAddress(host,port); | ||
24 | + try | ||
25 | + { | ||
26 | + super.connect(addr); | ||
27 | + initializeStreams(); | ||
28 | + } | ||
29 | + catch(IOException ioExc) | ||
30 | + { | ||
31 | + System.out.println("TCP: Error occured while connecting to remote host"); | ||
32 | + } | ||
33 | + } | ||
34 | + | ||
35 | + public void initializeStreams() | ||
36 | + { | ||
37 | + try | ||
38 | + { | ||
39 | + output = super.getOutputStream(); | ||
40 | + input = new BufferedReader(new InputStreamReader(super.getInputStream())); | ||
41 | + } | ||
42 | + catch(IOException ioExc) | ||
43 | + { | ||
44 | + System.out.println("TCP: Error initializing socket"); | ||
45 | + } | ||
46 | + } | ||
47 | + | ||
48 | + public void sendMsg(String msg) throws IOException | ||
49 | + { | ||
50 | + String length = new Integer(msg.length()).toString(); | ||
51 | + this.write(length + '\0' + msg); | ||
52 | + } | ||
53 | + | ||
54 | + public String recvMsg() throws IOException | ||
55 | + { | ||
56 | + String len,str; | ||
57 | + int length; | ||
58 | + len = this.readLine(); | ||
59 | + if(len == "") | ||
60 | + { | ||
61 | + return len; | ||
62 | + } | ||
63 | + length = Integer.parseInt(len); | ||
64 | + str = this.read(length); | ||
65 | + return str; | ||
66 | + } | ||
67 | + | ||
68 | + public void write(String str) throws IOException | ||
69 | + { | ||
70 | + output.write(str.getBytes()); | ||
71 | + } | ||
72 | + | ||
73 | + public String read(int bytes) | ||
74 | + { | ||
75 | + char[] buffer = new char[bytes]; | ||
76 | + try | ||
77 | + { | ||
78 | + input.read(buffer, 0, bytes); | ||
79 | + return new String(buffer); | ||
80 | + } | ||
81 | + catch(IOException ioExc) | ||
82 | + { | ||
83 | + System.out.println("TCP: Error retrieving data from remote endpoint"); | ||
84 | + return null; | ||
85 | + } | ||
86 | + } | ||
87 | + | ||
88 | + public String readLine() throws IOException | ||
89 | + { | ||
90 | + | ||
91 | + String line = ""; | ||
92 | + char[] c = new char[1]; | ||
93 | + while(true) | ||
94 | + { | ||
95 | + input.read(c,0,1); | ||
96 | + if(c[0] == '\0') | ||
97 | + { | ||
98 | + break; | ||
99 | + } | ||
100 | + line += c[0]; | ||
101 | + } | ||
102 | + return line; | ||
103 | + } | ||
104 | + | ||
105 | + public void close() | ||
106 | + { | ||
107 | + try | ||
108 | + { | ||
109 | + super.shutdownInput(); | ||
110 | + super.shutdownOutput(); | ||
111 | + super.close(); | ||
112 | + } | ||
113 | + catch(IOException ioExc) | ||
114 | + { | ||
115 | + System.out.println("TCP: Error while closing socket"); | ||
116 | + } | ||
117 | + } | ||
118 | +} | ||
0 | \ No newline at end of file | 119 | \ No newline at end of file |
JChatServer/src/pad/prac2/Server.java
0 → 100644
1 | +package pad.prac2; | ||
2 | + | ||
3 | +import java.io.IOException; | ||
4 | +import java.util.Collection; | ||
5 | +import java.util.Iterator; | ||
6 | +import java.util.Set; | ||
7 | +import java.util.concurrent.ConcurrentHashMap; | ||
8 | +import java.util.concurrent.locks.Condition; | ||
9 | +import java.util.concurrent.locks.Lock; | ||
10 | +import java.util.concurrent.locks.ReentrantLock; | ||
11 | + | ||
12 | +public class Server | ||
13 | +{ | ||
14 | + private MyServerSocket ss; | ||
15 | + private int roomSize; | ||
16 | + private boolean kill; | ||
17 | + private Connection[] workerPool; | ||
18 | + private int freeWorkers; | ||
19 | + private Lock lock; | ||
20 | + private Condition availableWorkers; | ||
21 | + private ConcurrentHashMap<Connection,String> activeConnections; | ||
22 | + | ||
23 | + public Server(String ip, int port, int rS) | ||
24 | + { | ||
25 | + try | ||
26 | + { | ||
27 | + ss = new MyServerSocket(); | ||
28 | + lock = new ReentrantLock(); | ||
29 | + activeConnections = new ConcurrentHashMap<Connection,String>(); | ||
30 | + roomSize = rS; | ||
31 | + freeWorkers = roomSize; | ||
32 | + kill = false; | ||
33 | + availableWorkers = lock.newCondition(); | ||
34 | + workerPool = new Connection[roomSize]; | ||
35 | + for(int i = 0; i < roomSize; i++) | ||
36 | + { | ||
37 | + workerPool[i] = new Connection(this); | ||
38 | + workerPool[i].start(); | ||
39 | + } | ||
40 | + ss.bind(ip, port); | ||
41 | + } | ||
42 | + catch(IOException ioExc) | ||
43 | + { | ||
44 | + System.out.println("TCP: Error initializating server socket"); | ||
45 | + } | ||
46 | + } | ||
47 | + | ||
48 | + public void startServer() | ||
49 | + { | ||
50 | + while(!kill) | ||
51 | + { | ||
52 | + try | ||
53 | + { | ||
54 | + MySocket incoming = ss.accept(); | ||
55 | + startWorker(incoming); | ||
56 | + } | ||
57 | + catch(IOException ioExc) | ||
58 | + { | ||
59 | + if(!kill) | ||
60 | + { | ||
61 | + System.out.println("TCP: Error accepting connection"); | ||
62 | + break; | ||
63 | + } | ||
64 | + } | ||
65 | + } | ||
66 | + | ||
67 | + } | ||
68 | + | ||
69 | + public void startWorker(MySocket s) | ||
70 | + { | ||
71 | + lock.lock(); | ||
72 | + while(freeWorkers == 0) | ||
73 | + { | ||
74 | + try | ||
75 | + { | ||
76 | + s.sendMsg("CHATFULL"); | ||
77 | + s.close(); | ||
78 | + lock.unlock(); | ||
79 | + return; | ||
80 | + } | ||
81 | + catch(IOException ioExc) | ||
82 | + { | ||
83 | + System.out.println("TCP: Error while sending message to client"); | ||
84 | + } | ||
85 | + } | ||
86 | + workerPool[roomSize - freeWorkers].setSock(s); | ||
87 | + workerPool[roomSize - freeWorkers].awake(); | ||
88 | + workerPool[roomSize - freeWorkers] = null; | ||
89 | + freeWorkers--; | ||
90 | + lock.unlock(); | ||
91 | + } | ||
92 | + | ||
93 | + public void finishWorker(Connection c) | ||
94 | + { | ||
95 | + lock.lock(); | ||
96 | + removeFromChatroom(c); | ||
97 | + freeWorkers++; | ||
98 | + workerPool[roomSize - freeWorkers] = c; | ||
99 | + availableWorkers.signal(); | ||
100 | + lock.unlock(); | ||
101 | + } | ||
102 | + | ||
103 | + public void sendTo(Connection orig, String nick, String msg) throws IOException, ChatException | ||
104 | + { | ||
105 | + lock.lock(); | ||
106 | + System.out.println("FROM " + getNickname(orig) + " TO " + nick + ": " + msg); | ||
107 | + msg = getNickname(orig) + ": " + msg; | ||
108 | + Set<Connection> conns = activeConnections.keySet(); | ||
109 | + Iterator<Connection> it = conns.iterator(); | ||
110 | + Connection dest; | ||
111 | + while(it.hasNext()) | ||
112 | + { | ||
113 | + dest = it.next(); | ||
114 | + if(getNickname(dest).equals(nick)) | ||
115 | + { | ||
116 | + dest.sendMessage(msg); | ||
117 | + lock.unlock(); | ||
118 | + return; | ||
119 | + } | ||
120 | + } | ||
121 | + lock.unlock(); | ||
122 | + throw new ChatException("No such nickname"); | ||
123 | + } | ||
124 | + | ||
125 | + public void sendToChat(Connection origin, String message) throws IOException | ||
126 | + { | ||
127 | + lock.lock(); | ||
128 | + String nickname = activeConnections.get(origin); | ||
129 | + Set<Connection> connections = activeConnections.keySet(); | ||
130 | + Iterator<Connection> it = connections.iterator(); | ||
131 | + Connection conn; | ||
132 | + while(it.hasNext()) | ||
133 | + { | ||
134 | + conn = it.next(); | ||
135 | + if(conn != origin) | ||
136 | + { | ||
137 | + conn.sendMessage(nickname + ": " + message); | ||
138 | + } | ||
139 | + } | ||
140 | + lock.unlock(); | ||
141 | + } | ||
142 | + | ||
143 | + public String getNickname(Connection c) | ||
144 | + { | ||
145 | + return activeConnections.get(c); | ||
146 | + } | ||
147 | + | ||
148 | + public void addToChatroom(Connection c, String nickName) | ||
149 | + { | ||
150 | + activeConnections.put(c, nickName); | ||
151 | + System.out.println(nickName + " has entered the room"); | ||
152 | + } | ||
153 | + | ||
154 | + private void removeFromChatroom(Connection c) | ||
155 | + { | ||
156 | + activeConnections.remove(c); | ||
157 | + } | ||
158 | + | ||
159 | + public boolean isOnline(String nick) | ||
160 | + { | ||
161 | + return activeConnections.contains(nick); | ||
162 | + } | ||
163 | + | ||
164 | + public String listOnline() | ||
165 | + { | ||
166 | + lock.lock(); | ||
167 | + String ret = new Integer(activeConnections.size()).toString(); | ||
168 | + ret += " people currently online:"; | ||
169 | + Collection<String> nickNames = activeConnections.values(); | ||
170 | + Iterator<String> it = nickNames.iterator(); | ||
171 | + while(it.hasNext()) | ||
172 | + { | ||
173 | + ret += "\n"; | ||
174 | + ret += it.next(); | ||
175 | + } | ||
176 | + lock.unlock(); | ||
177 | + return ret; | ||
178 | + } | ||
179 | + | ||
180 | + public void killServer() | ||
181 | + { | ||
182 | + kill = true; | ||
183 | + ss.close(); | ||
184 | + finishConnections(); | ||
185 | + } | ||
186 | + | ||
187 | + public void finishConnections() | ||
188 | + { | ||
189 | + Set<Connection> conns = activeConnections.keySet(); | ||
190 | + Iterator<Connection> it = conns.iterator(); | ||
191 | + while(it.hasNext()) | ||
192 | + { | ||
193 | + it.next().finish(); | ||
194 | + } | ||
195 | + } | ||
196 | +} |