diff --git a/JChatClient/bin/client b/JChatClient/bin/client index 683ed61..1d67a21 100755 --- a/JChatClient/bin/client +++ b/JChatClient/bin/client diff --git a/JChatClient/src/Socket.cpp b/JChatClient/src/Socket.cpp index 6ec78bf..440b407 100644 --- a/JChatClient/src/Socket.cpp +++ b/JChatClient/src/Socket.cpp @@ -6,11 +6,6 @@ * En este fichero se implementan los métodos de la clase Socket definidos en Socket.h */ #include "Socket.h" -#include "SocketException.h" -#include -#include -#include -#include using namespace std; @@ -149,8 +144,11 @@ const Socket& Socket::operator << ( const std::string& text) } sstream << length; string len = sstream.str(); - Send(len.c_str(), len.length()+1); - Send(text.c_str(), text.length()); + char* msg = new char[len.length() + text.length() + 1]; + strcpy(msg,len.c_str()); + strcpy(msg+len.length()+1,text.c_str()); + Send(msg, text.length() + len.length() + 1); + delete[] msg; return *this; } diff --git a/JChatClient/src/client.cpp b/JChatClient/src/client.cpp index 8b688ce..774c5a4 100644 --- a/JChatClient/src/client.cpp +++ b/JChatClient/src/client.cpp @@ -25,13 +25,6 @@ void exitClient(int signal/*!s)->Close(); - pthread_mutex_lock(t_arg->mutex); - if(t_arg->s != 0) - { - delete t_arg->s; - t_arg->s = 0; - } if(t_arg != 0) { delete t_arg; @@ -42,42 +35,69 @@ void killThread(thread_args *t_arg) bool connect(Socket& s) { - string host, nick; + string host, nick, response; int port; /*cout << "Hostname: "; - cin >> host; + getline(cin,host); cout << "Port: "; cin >> port;*/ cout << "Nickname: "; - cin >> nick; - cin.ignore(); + getline(cin,nick); host = "localhost"; port = 3001; try { + s.Create(); s.Connect(host,port); cout << "Connected" << endl; connected = true; s << nick; + s >> response; + while(response == "CHATNICKINVALID") + { + cout << "Spaces not allowed in nicknames, please enter another nickname: "; + getline(cin,nick); + s << nick; + s >> response; + } + while(response == "CHATNICKEXIST") + { + cout << "Nickname in use, please enter another nickname: "; + getline(cin,nick); + s << nick; + s >> response; + } + while(response == "CHATFULL") + { + cout << "Chatroom is full, please wait..." << endl; + s >> response; + } + if(response != "CHATOK") + { + cout << "Error: " << response << endl; + return false; + } } catch(SocketException& e) { cout << e.description() << endl; + exit(-1); } + return true; } void* sendThread(void* args) { string send; struct thread_args *t_arg = (struct thread_args*)args; - while(true) + while(connected) { cout << "> "; getline(cin,send); if(cin.eof()) { - send = "/disconnect"; + send = "/exit"; } try { @@ -90,9 +110,6 @@ void* sendThread(void* args) catch(SocketException& e) { cout << e.description() << endl; - cout << "Exiting" << endl; - (t_arg->s)->Close(); - exit(-1); } } killThread(t_arg); @@ -104,11 +121,20 @@ void* recvThread(void* args) struct thread_args *t_arg = (struct thread_args*)args; while(true) { - *(t_arg->s) >> recv; + try + { + *(t_arg->s) >> recv; + } + catch(SocketException &e) + { + connected = false; + cout << e.description() << endl; + (t_arg->s)->Close(); + break; + } if(recv == "DISC_OK") { cout << "Disconnecting" << endl; - (t_arg->s)->Close(); connected = false; pthread_cond_signal(t_arg->condition); break; @@ -116,7 +142,6 @@ void* recvThread(void* args) else if(recv == "EXIT_OK") { cout << "Exiting" << endl; - (t_arg->s)->Close(); connected = false; finished = true; pthread_cond_signal(t_arg->condition); @@ -144,10 +169,15 @@ int main() thread_args *sArgs = new thread_args; thread_args *rArgs = new thread_args; pthread_t recv, send; - s.Create(); + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); while (!finished) { - connect(s); + if(!connect(s)) + { + exit(-1); + } pthread_mutex_lock(&mutex); sArgs->mutex = &mutex; sArgs->condition = &condition; @@ -157,14 +187,17 @@ int main() rArgs->condition = &condition; rArgs->s = &s; - pthread_create(&send,NULL,sendThread,(void *)sArgs); - pthread_create(&recv,NULL,recvThread,(void *)rArgs); + pthread_create(&send,&attr,sendThread,(void *)sArgs); + pthread_create(&recv,&attr,recvThread,(void *)rArgs); while(connected) { pthread_cond_wait(&condition,&mutex); } pthread_mutex_unlock(&mutex); + pthread_join(recv,NULL); + pthread_join(send,NULL); + s.Close(); } pthread_cond_destroy(&condition); pthread_mutex_destroy(&mutex); @@ -172,7 +205,5 @@ int main() /* TODO * - * disconnecting causes some real shit - * list nicks - * unicast message + * CTRL+C */ \ No newline at end of file diff --git a/JChatClient/src/include/Socket.h b/JChatClient/src/include/Socket.h index 8b87b14..49f1a0d 100644 --- a/JChatClient/src/include/Socket.h +++ b/JChatClient/src/include/Socket.h @@ -9,13 +9,17 @@ #define SOCKET_H_ #include +#include +#include "SocketException.h" #include +#include #include +#include #include #include -#include -#include #include +#include +#include using namespace std; diff --git a/JChatServer/bin/pad/prac2/ChatException.class b/JChatServer/bin/pad/prac2/ChatException.class new file mode 100644 index 0000000..0e0d11e --- /dev/null +++ b/JChatServer/bin/pad/prac2/ChatException.class diff --git a/JChatServer/bin/pad/prac2/Connection.class b/JChatServer/bin/pad/prac2/Connection.class index 0b6ee78..91aeb10 100644 --- a/JChatServer/bin/pad/prac2/Connection.class +++ b/JChatServer/bin/pad/prac2/Connection.class diff --git a/JChatServer/bin/pad/prac2/JChat$1.class b/JChatServer/bin/pad/prac2/JChat$1.class new file mode 100644 index 0000000..e169b54 --- /dev/null +++ b/JChatServer/bin/pad/prac2/JChat$1.class diff --git a/JChatServer/bin/pad/prac2/MyServerSocket.class b/JChatServer/bin/pad/prac2/MyServerSocket.class index 84d5d6b..97d4974 100644 --- a/JChatServer/bin/pad/prac2/MyServerSocket.class +++ b/JChatServer/bin/pad/prac2/MyServerSocket.class diff --git a/JChatServer/bin/pad/prac2/MySocket.class b/JChatServer/bin/pad/prac2/MySocket.class index 245314e..d646e02 100644 --- a/JChatServer/bin/pad/prac2/MySocket.class +++ b/JChatServer/bin/pad/prac2/MySocket.class diff --git a/JChatServer/bin/pad/prac2/Server.class b/JChatServer/bin/pad/prac2/Server.class index 99c00c6..5832f85 100644 --- a/JChatServer/bin/pad/prac2/Server.class +++ b/JChatServer/bin/pad/prac2/Server.class 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 index bfabe3c..757e66a 100644 --- a/JChatServer/src/pad/prac2/Connection.java +++ b/JChatServer/src/pad/prac2/Connection.java @@ -15,11 +15,6 @@ public class Connection extends Thread sleep = true; } - public void sendMessage(String message) throws IOException - { - socket.sendMsg(message); - } - public void awake() { synchronized(this) @@ -32,9 +27,12 @@ public class Connection extends Thread public void finish() { kill = true; - sleep = false; + if(sleep) + { + sleep = false; + notify(); + } socket.close(); - this.notify(); } public void setSock(MySocket s) @@ -42,6 +40,11 @@ public class Connection extends Thread socket = s; } + public void sendMessage(String message) throws IOException + { + socket.sendMsg(message); + } + public void run() { while(!kill) @@ -60,45 +63,88 @@ public class Connection extends Thread e.printStackTrace(); } } - String str = socket.recvMsg(); - serv.addToChatroom(this, str); if(!kill) { - while(true) + String str; + try { str = socket.recvMsg(); - if(str != null) + while(str.contains(" ")) { - try + 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 = ""; + str = socket.recvMsg(); + if(str.equals("/disconnect")) { - if(str.equals("/disconnect")) - { - socket.sendMsg("DISC_OK"); - kill = true; - System.out.println(serv.getNickname(this) + " disconnected"); - break; - } - else if(str.equals("/exit")) + 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 { - socket.sendMsg("EXIT_OK"); - kill = true; - System.out.println(serv.getNickname(this) + " disconnected"); - break; + if(!str.contains(" ")) + { + serv.sendTo(this,str.substring(1),""); + } + else + { + serv.sendTo(this,str.substring(1,str.indexOf(' ')),str.substring(str.indexOf(' ')+1)); + } } - else + catch(ChatException cE) { - System.out.println("FROM " + serv.getNickname(this) + ": " + str); - serv.sendToChat(this,str); + socket.sendMsg(cE.getMessage()); } } - catch(IOException ioExc) + else if(str.equals("")) { - System.out.println("TCP: Error writing to socket"); break; } + else + { + System.out.println("FROM " + serv.getNickname(this) + ": " + str); + serv.sendToChat(this,str); + } } - else + catch(IOException ioExc) { + System.out.println("TCP: Error writing to socket"); break; } } @@ -107,5 +153,4 @@ public class Connection extends Thread serv.finishWorker(this); } } - } diff --git a/JChatServer/src/pad/prac2/JChat.java b/JChatServer/src/pad/prac2/JChat.java index 45a1c1c..2455693 100644 --- a/JChatServer/src/pad/prac2/JChat.java +++ b/JChatServer/src/pad/prac2/JChat.java @@ -25,7 +25,7 @@ public class JChat { public void run() { - System.out.println("JChat: interrupt catched, killing server..."); + System.out.println("JChat: Caught interrupt, killing server..."); serv.killServer(); } }); @@ -34,8 +34,6 @@ public class JChat /* * TODO * - * unicast message - * list nicks - * disconnect/reconnect successfully + * CTRL+C */ } diff --git a/JChatServer/src/pad/prac2/MyServerSocket.java b/JChatServer/src/pad/prac2/MyServerSocket.java index 35522b3..ae9a6e3 100644 --- a/JChatServer/src/pad/prac2/MyServerSocket.java +++ b/JChatServer/src/pad/prac2/MyServerSocket.java @@ -12,22 +12,6 @@ public class MyServerSocket extends ServerSocket super(); } - public MySocket accept() - { - try - { - MySocket incoming = new MySocket(); - super.implAccept(incoming); - incoming.initializeStreams(); - return incoming; - } - catch(IOException ioExc) - { - System.out.println("TCP: Error accepting connection"); - return null; - } - } - public void bind(String ip, int port) { SocketAddress addr = new InetSocketAddress(ip,port); @@ -41,6 +25,14 @@ public class MyServerSocket extends ServerSocket } } + public MySocket accept() throws IOException + { + MySocket incoming = new MySocket(); + super.implAccept(incoming); + incoming.initializeStreams(); + return incoming; + } + public void close() { try diff --git a/JChatServer/src/pad/prac2/MySocket.java b/JChatServer/src/pad/prac2/MySocket.java index 2a1802a..a41eb88 100644 --- a/JChatServer/src/pad/prac2/MySocket.java +++ b/JChatServer/src/pad/prac2/MySocket.java @@ -45,28 +45,13 @@ public class MySocket extends Socket } } - public void close() - { - try - { - super.shutdownInput(); - super.shutdownOutput(); - super.close(); - } - catch(IOException ioExc) - { - System.out.println("TCP: Error while closing socket"); - } - } - public void sendMsg(String msg) throws IOException { String length = new Integer(msg.length()).toString(); - this.write(length + '\0'); - this.write(msg); + this.write(length + '\0' + msg); } - public String recvMsg() + public String recvMsg() throws IOException { String len,str; int length; @@ -100,28 +85,34 @@ public class MySocket extends Socket } } - public String readLine() + public String readLine() throws IOException { - try + + String line = ""; + char[] c = new char[1]; + while(true) { - String line = ""; - char[] c = new char[1]; - while(true) + input.read(c,0,1); + if(c[0] == '\0') { - input.read(c,0,1); - if(c[0] == '\0') - { - break; - } - line += c[0]; + break; } - return line; + line += c[0]; + } + return line; + } + + public void close() + { + try + { + super.shutdownInput(); + super.shutdownOutput(); + super.close(); } catch(IOException ioExc) { - System.out.println("TCP: Error retrieving data from remote endpoint"); - return null; + 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 index b25fa54..a77c45d 100644 --- a/JChatServer/src/pad/prac2/Server.java +++ b/JChatServer/src/pad/prac2/Server.java @@ -1,6 +1,7 @@ package pad.prac2; import java.io.IOException; +import java.util.Collection; import java.util.Iterator; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -44,35 +45,24 @@ public class Server } } - 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 void startServer() { while(!kill) { - MySocket incoming = ss.accept(); - if(incoming != null) + try { + MySocket incoming = ss.accept(); System.out.println("Accepted connection from " + incoming.getInetAddress()); - startWorker(incoming); } + catch(IOException ioExc) + { + if(!kill) + { + System.out.println("TCP: Error accepting connection"); + break; + } + } } } @@ -84,14 +74,20 @@ public class Server { try { - lock.unlock(); - availableWorkers.await(); - lock.lock(); + s.sendMsg("CHATFULL"); + synchronized(this) + { + availableWorkers.await(); + } } catch(InterruptedException intExc) { intExc.printStackTrace(); } + catch(IOException ioExc) + { + System.out.println("TCP: Error while sending message to client"); + } } workerPool[roomSize - freeWorkers].setSock(s); workerPool[roomSize - freeWorkers].awake(); @@ -100,34 +96,91 @@ public class Server lock.unlock(); } - public String getNickname(Connection c) - { - return activeConnections.get(c); - } - 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"); } - public void finishConnections() + private void removeFromChatroom(Connection c) { - Set conns = activeConnections.keySet(); - Iterator it = conns.iterator(); + 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()) { - it.next().finish(); + ret += "\n"; + ret += it.next(); } + lock.unlock(); + return ret; } public void killServer() @@ -136,4 +189,14 @@ public class Server ss.close(); finishConnections(); } + + public void finishConnections() + { + Set conns = activeConnections.keySet(); + Iterator it = conns.iterator(); + while(it.hasNext()) + { + it.next().finish(); + } + } }