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 | 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 | +} | ... | ... |