Commit 493ea8e792d6cb2328647617b2621f6681eb2241

Authored by Imanol-Mikel Barba Sabariego
1 parent 791d4e1f

git-svn-id: svn://imanolbarba.net/PAD@25 c2ee353e-ed0d-4329-bf56-03aec153487f

JChatClient/bin/client
No preview for this file type
JChatClient/src/client.cpp
... ... @@ -5,13 +5,7 @@
5 5 *
6 6 * En este fichero se implementa un cliente para poder usar con el servidor creado, usando la clase Socket.
7 7 */
8   -#include "Socket.h"
9   -#include <iostream>
10   -#include "SocketException.h"
11   -#include <sstream>
12   -#include <signal.h>
13   -#include <cstdlib>
14   -#include <sys/time.h>
  8 +#include "client.h"
15 9  
16 10 using namespace std;
17 11  
... ... @@ -22,24 +16,50 @@ bool connected, finished;
22 16 el signal SIGPIPE. */
23 17 void exitClient(int signal/*!<Parámetro que captura el signal recibido*/)
24 18 {
25   - cout << "Server connection terminated unexpectedly" << endl << "Exiting" << endl;
26   - exit(-1);
  19 + if(signal == SIGPIPE)
  20 + {
  21 + cout << "Server connection terminated unexpectedly" << endl << "Exiting" << endl;
  22 + exit(-1);
  23 + }
  24 +}
  25 +
  26 +void killThread(thread_args *t_arg)
  27 +{
  28 + (t_arg->s)->Close();
  29 + pthread_mutex_lock(t_arg->mutex);
  30 + if(t_arg->s != 0)
  31 + {
  32 + delete t_arg->s;
  33 + t_arg->s = 0;
  34 + }
  35 + if(t_arg != 0)
  36 + {
  37 + delete t_arg;
  38 + t_arg = 0;
  39 + }
  40 + pthread_exit(NULL);
27 41 }
28 42  
29 43 bool connect(Socket& s)
30 44 {
31   - string host;
  45 + string host, nick;
32 46 int port;
33   - cout << "Hostname: ";
  47 + /*cout << "Hostname: ";
34 48 cin >> host;
35 49 cout << "Port: ";
36   - cin >> port;
  50 + cin >> port;*/
  51 + cout << "Nickname: ";
  52 + cin >> nick;
37 53 cin.ignore();
  54 + host = "localhost";
  55 + port = 3001;
  56 +
38 57 try
39 58 {
40 59 s.Connect(host,port);
41 60 cout << "Connected" << endl;
42 61 connected = true;
  62 + s << nick;
43 63 }
44 64 catch(SocketException& e)
45 65 {
... ... @@ -47,32 +67,68 @@ bool connect(Socket&amp; s)
47 67 }
48 68 }
49 69  
50   -void speedTest(Socket& s)
  70 +void* sendThread(void* args)
51 71 {
52   - string data = "", answer;
53   - double size;
54   - double start, duration;
55   - cout << "Size in MB: ";
56   - cin >> size;
57   - cin.ignore();
58   - for(long int i = 0; i < size*1e6; i++ )
  72 + string send;
  73 + struct thread_args *t_arg = (struct thread_args*)args;
  74 + while(true)
59 75 {
60   - data += (char)( 65 + i % 26);
  76 + cout << "> ";
  77 + getline(cin,send);
  78 + if(cin.eof())
  79 + {
  80 + send = "/disconnect";
  81 + }
  82 + try
  83 + {
  84 + *(t_arg->s) << send;
  85 + if(send == "/disconnect" || send == "/exit")
  86 + {
  87 + break;
  88 + }
  89 + }
  90 + catch(SocketException& e)
  91 + {
  92 + cout << e.description() << endl;
  93 + cout << "Exiting" << endl;
  94 + (t_arg->s)->Close();
  95 + exit(-1);
  96 + }
61 97 }
62   - cout << "Data generated, commencing transfer" << endl;
63   - struct timeval st, ed;
64   - gettimeofday(&st, NULL);
65   - s << data;
66   - cout << "Data sent" << endl;
67   - s >> answer;
68   - gettimeofday(&ed, NULL);
69   - start = (st.tv_sec) + (st.tv_usec) / 1e6;
70   - duration = ((ed.tv_sec) + (ed.tv_usec) / 1e6) - start;
71   - if(answer == "ACK")
  98 + killThread(t_arg);
  99 +}
  100 +
  101 +void* recvThread(void* args)
  102 +{
  103 + string recv;
  104 + struct thread_args *t_arg = (struct thread_args*)args;
  105 + while(true)
72 106 {
73   - cout << "Transferred " << size << " MB in " << duration << " seconds" << endl;
74   - cout << "Data rate: " << size/duration << " MB/s" << endl;
  107 + *(t_arg->s) >> recv;
  108 + if(recv == "DISC_OK")
  109 + {
  110 + cout << "Disconnecting" << endl;
  111 + (t_arg->s)->Close();
  112 + connected = false;
  113 + pthread_cond_signal(t_arg->condition);
  114 + break;
  115 + }
  116 + else if(recv == "EXIT_OK")
  117 + {
  118 + cout << "Exiting" << endl;
  119 + (t_arg->s)->Close();
  120 + connected = false;
  121 + finished = true;
  122 + pthread_cond_signal(t_arg->condition);
  123 + break;
  124 + }
  125 + else
  126 + {
  127 + *(t_arg->s) >> recv;
  128 + cout << recv << endl;
  129 + }
75 130 }
  131 + killThread(t_arg);
76 132 }
77 133  
78 134 //! Método principal del cliente
... ... @@ -80,71 +136,43 @@ void speedTest(Socket&amp; s)
80 136 int main()
81 137 {
82 138 signal(SIGPIPE, exitClient);
83   - signal(SIGINT, exitClient);
84 139 Socket s;
85 140 connected = finished = false;
86   - string send, recv;
  141 + pthread_mutex_t mutex;
  142 + pthread_mutex_init(&mutex,0);
  143 + pthread_cond_t condition;
  144 + pthread_cond_init(&condition,0);
  145 + thread_args *sArgs = new thread_args;
  146 + thread_args *rArgs = new thread_args;
  147 + pthread_t recv, send;
87 148 s.Create();
88   - while (!exit)
  149 + while (!finished)
89 150 {
90 151 connect(s);
  152 + pthread_mutex_lock(&mutex);
  153 + sArgs->mutex = &mutex;
  154 + sArgs->condition = &condition;
  155 + sArgs->s = &s;
  156 +
  157 + rArgs->mutex = &mutex;
  158 + rArgs->condition = &condition;
  159 + rArgs->s = &s;
  160 +
  161 + pthread_create(&send,NULL,sendThread,(void *)sArgs);
  162 + pthread_create(&recv,NULL,recvThread,(void *)rArgs);
  163 +
91 164 while(connected)
92 165 {
93   - cout << "> ";
94   - getline(cin,send);
95   - if(cin.eof())
96   - {
97   - send = "/disconnect";
98   - }
99   - try
100   - {
101   - s << send;
102   - if(send == "/disconnect")
103   - {
104   - s >> recv;
105   - if(recv == "OK")
106   - {
107   - cout << "Disconnecting" << endl;
108   - s.Close();
109   - connected = false;
110   - }
111   - }
112   - else if(send == "/exit")
113   - {
114   - s >> recv;
115   - if(recv == "OK")
116   - {
117   - cout << "Exiting" << endl;
118   - s.Close();
119   - connected = false;
120   - finished = true;
121   - }
122   - }
123   - else if(send == "/test")
124   - {
125   - speedTest(s);
126   - }
127   - else
128   - {
129   - s >> recv;
130   - cout << "Received: " << recv << endl;
131   - }
132   - }
133   - catch(SocketException& e)
134   - {
135   - cout << e.description() << endl;
136   - cout << "Exiting" << endl;
137   - s.Close();
138   - return -1;
139   - }
  166 + pthread_cond_wait(&condition,&mutex);
140 167 }
  168 + pthread_mutex_unlock(&mutex);
141 169 }
  170 + pthread_cond_destroy(&condition);
  171 + pthread_mutex_destroy(&mutex);
142 172 }
143 173  
144   -/* TO-DO
  174 +/* TODO
145 175 *
146   - * spawn 2 IO threads
147   - * connect/disconnect commands
148 176 * list nicks
149 177 * unicast message
150 178 */
151 179 \ No newline at end of file
... ...
JChatClient/src/include/client.h 0 → 100644
  1 +#ifndef CLIENT_H_
  2 +#define CLIENT_H_
  3 +
  4 +#include "Socket.h"
  5 +#include <iostream>
  6 +#include "SocketException.h"
  7 +#include <sstream>
  8 +#include <signal.h>
  9 +#include <cstdlib>
  10 +#include <sys/time.h>
  11 +
  12 +//!Argumentos de los threads
  13 +/**
  14 +\brief Este struct define los argumentos que recibe un thread abierto por la aplicación servidor al recibir una conexión entrante
  15 +\author Imanol Barba Sabariego
  16 +\date 11/06/2013 */
  17 +struct thread_args
  18 +{
  19 + //! Variable de control de la exclusión mútua entre threads
  20 + /** Esta variable se usa para bloquear otros threads en operaciones de exclusion mútua donde se modifican variables compartidas */
  21 + pthread_mutex_t *mutex;
  22 + //! Variable de notificación a otros threads
  23 + /*! \brief Esta variable se usa para notificar a otros threads cuando deben realizar otras acciones.
  24 +
  25 + *Actualmente se usa para notificar al thread principal cuando el thread que lo invoca ha terminado, en caso de que el principal haya
  26 + quedado bloqueado y no admita más conexiones.* */
  27 + pthread_cond_t *condition;
  28 + //! Puntero al socket
  29 + /*! \brief Esta variable representa el puntero al socket que proviene de la conexión entrante recibida por el servidor. Con este, el thread
  30 + puede recibir y enviar los datos. */
  31 + Socket *s;
  32 +};
  33 +
  34 +
  35 +
  36 +#endif /* CLIENT_H_ */
0 37 \ No newline at end of file
... ...
JChatClient/src/include/server.h deleted
1   -/** @file
2   -* \brief Header de la clase Server
3   -* \author Imanol Barba Sabariego
4   -* \date 11/06/2013
5   -*
6   -* En este fichero se define la clase Server y algunos métodos globales usados por ésta para la gestión de threads y otros aspectos.
7   -*/
8   -
9   -#ifndef SERVER_H_
10   -#define SERVER_H_
11   -
12   -#include "Socket.h"
13   -#include "SocketException.h"
14   -#include <iostream>
15   -#include <sstream>
16   -#include <signal.h>
17   -#include <fstream>
18   -#include <list>
19   -#include <fstream>
20   -
21   -//! Numero de conexiones permitidas activas (en espera o activas)
22   -/*! Esta constante controla cuantas conexiones puede haber en espera o cuantas puede haber establecias en cualquier momento: habrá N activas
23   -y N en espera como mucho, no N en espera o activas. */
24   -#define N 5
25   -//! Ruta al fichero de configuración
26   -/*! Ruta relativa o absoluta al fichero de configuración, de no existir o ser inválido el programa no funcionará. */
27   -#define CONFFILE "socket.conf"
28   -//! Nombre del socket del módulo de control
29   -/*! Nombre y ruta del socket UNIX del módulo de control */
30   -
31   -using namespace std;
32   -
33   -//! Clase de aplicación servidor
34   -/**
35   -Esta clase define un objeto con los métodos y atributos necesarios para lanzar una aplicación servidor y atender las conexiones. Para realizar
36   -la comunicación con el cliente, usa un objeto de la clase Socket
37   -*/
38   -class Server
39   -{
40   - private:
41   - //! Contador de threads
42   - /*! Esta variable se encarga de mantener la cuenta de threads activos, por tanto, el número de conexiones que estan siendo antendidas
43   - simultáneamente. */
44   - int nWorkers;
45   - //! Variable de apagado
46   - /*! Esta variable controla el apagado del servidor, al ponerla a true, la siguiente iteración del bucle que atiende las conexiones
47   - no se producirá y el programa terminará. */
48   - bool shutdownServer;
49   - //! Contador de ID de thread
50   - /*! Esta variable contiene el ID del próximo thread que se creará, por tanto, indica el número de conexiones que han sido atendidas desde
51   - el inicio del servidor */
52   - int workerID;
53   - //! Pila de threads terminados
54   - /*! Esta variable contiene una lista de threads que han finalizado su ejecución. A cada iteración del bucle que atiende conexiones,
55   - se libera toda la memoria de los threads que hay almacenados aquí. */
56   - list<pthread_t*> stoppedThreads;
57   - //! Pila de threads empezados
58   - /*! \brief Esta variable contiene una lista de threads que han empezado su ejecución. Si el programa finalizara prematuramente, se liberarían los punteros
59   - de los threads almacenados en esta pila.
60   -
61   - __NOTA: No se liberará la memoria asignada a los argumentos de los threads, dando lugar a memory leaks; sin embargo, esto se produciria al finalizar
62   - el programa, por tanto no es relevante.__ */
63   - list<pthread_t*> startedThreads;
64   - //! Socket de comunicación
65   - /*! Esta variable contiene el objeto de la clase Socket que la aplicación servidor usa para poder atender las peticiones. Su función
66   - es quedarse escuchando el el puerto e IP introducidas en el fichero de configuración y crear un objeto de la clase Socket para cada
67   - petición de cada cliente nuevo, siendo este último objeto creado el que se usa para la comuncación. */
68   - Socket ss;
69   -
70   - public:
71   - //! Constructor de la clase Server
72   - /*! Incializa los argumentos inciales del servidor */
73   - Server() : nWorkers(0), workerID(0), shutdownServer(false) {}
74   - //! Getter del número de threads activos
75   - /*! Devuelve el número de threads activos en ese instante, por tanto, del número de conexiones que están siendo atendidas. */
76   - int getNWorkers();
77   - //! Setter del número de threads activos
78   - /*! Establece el número de threads activos, para poder cambiarlo cuando alguno de los threads activos finaliza */
79   - void setNWorkers(int n /*!<Nuevo número de threads activos*/);
80   - //! Getter de la pila de threads activos
81   - /*! Devuelve un contenedor con la lista de threads que estan activos, para terminarlos en caso de que el programa finalice prematuramente */
82   - list<pthread_t*>* getStartedThreads();
83   - //! Getter de la pila de threads terminados
84   - /*! Devuelve un contenedor con la lista de threads que han terminado, para poder liberar la memoria que se le ha asignado */
85   - list<pthread_t*>* getStoppedThreads();
86   - //! Método de inicialización del servidor
87   - /*! Incializa el servidor en el puerto e IP especificados para empezar a recibir conexiones entrantes */
88   - void startServer(string i /*!<IP donde se aceptan las conexiones */, int p/*!<Puerto donde se aceptan las conexiones*/);
89   - //! Método para liberar memória de threads
90   - /*! Este método se llama para que libere la memoria de todos los threads que se le proporcionan por argumento */
91   - void freeRAM(list<pthread_t*> *threadList/*!<Contenedor con los threads a liberar */);
92   - //! Método para terminar el servidor
93   - /*! Este método inicia la secuencia de finalización del servidor */
94   - void requestExit();
95   -};
96   -
97   -//!Argumentos de los threads
98   -/**
99   -\brief Este struct define los argumentos que recibe un thread abierto por la aplicación servidor al recibir una conexión entrante
100   -\author Imanol Barba Sabariego
101   -\date 11/06/2013 */
102   -struct thread_args
103   -{
104   - //! Variable de control de la exclusión mútua entre threads
105   - /** Esta variable se usa para bloquear otros threads en operaciones de exclusion mútua donde se modifican variables compartidas */
106   - pthread_mutex_t *mutex;
107   - //! Variable de notificación a otros threads
108   - /*! \brief Esta variable se usa para notificar a otros threads cuando deben realizar otras acciones.
109   -
110   - *Actualmente se usa para notificar al thread principal cuando el thread que lo invoca ha terminado, en caso de que el principal haya
111   - quedado bloqueado y no admita más conexiones.* */
112   - pthread_cond_t *condition;
113   - //! Puntero al thread
114   - /*! \brief Esta variable representa el puntero del propio thread. Al finalizar, este enviará su puntero a la lista de threads terminados,
115   - donde la memoria asignada al thread se destruirá. */
116   - pthread_t *thread;
117   - //! Puntero al socket
118   - /*! \brief Esta variable representa el puntero al socket que proviene de la conexión entrante recibida por el servidor. Con este, el thread
119   - puede recibir y enviar los datos. */
120   - Socket *s;
121   - //! Puntero al servidor
122   - /*! \brief Esta variable representa el puntero al servidor de la aplicación. Con este puntero, los threads se mueven a la pila de threads
123   - terminados una vez terminan la ejecución para que el thread principal (el propio servidor), vaya liberando la memoria asignada. */
124   - Server *serv;
125   - //! ID del thread
126   - /*! \brief Identifica al thread con un ID único */
127   - int id;
128   -};
129   -
130   -//! Método de finalización de Threads
131   -/*! \brief Éste método se ejecuta para liberar la memoria de los argumentos del thread y mandarlo a la pila de threads terminados. */
132   -void killThread(thread_args *t_arg /*!<Puntero al struct que contiene los argumentos del thread */);
133   -//! Método gestión de conexiones
134   -/*! \brief Éste método es el que los threads ejecutan al crearse, aquí es donde se define el comportamiento del servidor, ya que cada conexión
135   -se gestionará como aquí se detalla.
136   -
137   -_Por defecto, el comportamiento que lleva programado es el de un servidor "echo", esperará que el cliente le envíe un mensaje y responderá con el
138   -mismo mensaje._ */
139   -void *WorkerThread(void* args /*!< Puntero al struct de los argumentos del thread casteado a tipo void**/);
140   -//! Método auxiliar de procesado de texto
141   -/*! \brief Éste método usa para procesar las entradas de texto del fichero de configuración para adaptarlas a un formato adecuado.
142   -
143   -_De momento se limita a eliminar whitespace (tabulaciones, saltos de línea y espacios)._ */
144   -void processText(string *str/*!<Línea de texto a procesar*/);
145   -//! Método de lectura de configuración
146   -/*! \brief Éste método lee el fichero de configuración espeficado para obtener parámetros de configuración para el funcionamiento del servidor. */
147   -bool readConf(string *ip/*!Puntero donde se almacena la IP leída*/, int *port/*!<Puntero donde se almacena el puerto leído*/);
148   -
149   -#endif /* SERVER_H_ */
JChatServer/bin/pad/prac2/Connection.class
No preview for this file type
JChatServer/bin/pad/prac2/JChat.class
No preview for this file type
JChatServer/bin/pad/prac2/MyServerSocket.class
No preview for this file type
JChatServer/bin/pad/prac2/MySocket.class
No preview for this file type
JChatServer/bin/pad/prac2/Server.class
No preview for this file type
JChatServer/bin/pad/prac2/Worker.class deleted
No preview for this file type
JChatServer/src/pad/prac2/Connection.java
1 1 package pad.prac2;
2 2  
3   -public class Connection
  3 +public class Connection extends Thread
4 4 {
  5 + private MySocket socket;
  6 + private Server serv;
  7 + private boolean sleep, kill;
  8 +
  9 + public Connection(Server s)
  10 + {
  11 + serv = s;
  12 + kill = false;
  13 + sleep = true;
  14 + }
  15 +
  16 + public void sendMessage(String message)
  17 + {
  18 + socket.sendMsg(message);
  19 + }
  20 +
  21 + public void awake()
  22 + {
  23 + synchronized(this)
  24 + {
  25 + sleep = false;
  26 + this.notify();
  27 + }
  28 + }
  29 +
  30 + public void finish()
  31 + {
  32 + kill = true;
  33 + sleep = false;
  34 + socket.close();
  35 + this.notify();
  36 + }
  37 +
  38 + public void setSock(MySocket s)
  39 + {
  40 + socket = s;
  41 + }
  42 +
  43 + public void run()
  44 + {
  45 + while(!kill)
  46 + {
  47 + while(sleep)
  48 + {
  49 + try
  50 + {
  51 + synchronized(this)
  52 + {
  53 + wait();
  54 + }
  55 + }
  56 + catch (InterruptedException e)
  57 + {
  58 + e.printStackTrace();
  59 + }
  60 + }
  61 + String str = socket.recvMsg();
  62 + serv.addToChatroom(this, str);
  63 + if(!kill)
  64 + {
  65 + while(true)
  66 + {
  67 + str = socket.recvMsg();
  68 + if(str != null)
  69 + {
  70 + if(str == "/disconnect")
  71 + {
  72 + socket.sendMsg("DISC_OK");
  73 + kill = true;
  74 + System.out.println(serv.getNickname(this) + " disconnected");
  75 + }
  76 + else if(str == "/exit")
  77 + {
  78 + socket.sendMsg("EXIT_OK");
  79 + kill = true;
  80 + System.out.println(serv.getNickname(this) + " disconnected");
  81 + }
  82 + else
  83 + {
  84 + System.out.println("FROM " + serv.getNickname(this) + ": " + str);
  85 + serv.sendToChat(this,str);
  86 + }
  87 + }
  88 + else
  89 + {
  90 + break;
  91 + }
  92 + }
  93 + sleep = true;
  94 + }
  95 + serv.finishWorker(this);
  96 + }
  97 + }
5 98  
6 99 }
... ...
JChatServer/src/pad/prac2/JChat.java
... ... @@ -6,23 +6,29 @@ public class JChat
6 6 {
7 7 public static void main(String[] args)
8 8 {
  9 +
9 10 String ip;
10 11 int port, roomSize;
11   - Scanner in = new Scanner(System.in);
  12 + /*Scanner in = new Scanner(System.in);
12 13 System.out.print("IP: ");
13 14 ip = in.nextLine();
14 15 System.out.print("Port: ");
15 16 port = in.nextInt();
16 17 System.out.print("Size of chatroom: ");
17 18 roomSize = in.nextInt();
18   - in.close();
19   - Server serv = new Server(ip,port,roomSize);
  19 + in.close();*/
  20 + ip = "localhost";
  21 + port = 3001;
  22 + roomSize = 3;
  23 + final Server serv = new Server(ip,port,roomSize);
  24 + Runtime.getRuntime().addShutdownHook(new Thread()
  25 + {
  26 + public void run()
  27 + {
  28 + System.out.println("JChat: interrupt catched, killing server...");
  29 + serv.killServer();
  30 + }
  31 + });
20 32 serv.startServer();
21 33 }
22   - /*
23   - * TODO
24   - *
25   - * capture SIGINT
26   - *
27   - */
28 34 }
... ...
JChatServer/src/pad/prac2/MyServerSocket.java
... ... @@ -16,7 +16,9 @@ public class MyServerSocket extends ServerSocket
16 16 {
17 17 try
18 18 {
19   - MySocket incoming = (MySocket)super.accept();
  19 + MySocket incoming = new MySocket();
  20 + super.implAccept(incoming);
  21 + incoming.initializeStreams();
20 22 return incoming;
21 23 }
22 24 catch(IOException ioExc)
... ... @@ -31,7 +33,7 @@ public class MyServerSocket extends ServerSocket
31 33 SocketAddress addr = new InetSocketAddress(ip,port);
32 34 try
33 35 {
34   - super.bind(addr);
  36 + super.bind(addr, 5);
35 37 }
36 38 catch(IOException ioExc)
37 39 {
... ...
JChatServer/src/pad/prac2/MySocket.java
... ... @@ -16,27 +16,32 @@ public class MySocket extends Socket
16 16 public MySocket()
17 17 {
18 18 super();
  19 + }
  20 +
  21 + public void connect(String host, int port)
  22 + {
  23 + SocketAddress addr = new InetSocketAddress(host,port);
19 24 try
20 25 {
21   - output = new PrintWriter(super.getOutputStream());
22   - input = new BufferedReader(new InputStreamReader(super.getInputStream()));
  26 + super.connect(addr);
  27 + initializeStreams();
23 28 }
24 29 catch(IOException ioExc)
25 30 {
26   - System.out.println("TCP: Error initializing socket");
  31 + System.out.println("TCP: Error occured while connecting to remote host");
27 32 }
28 33 }
29 34  
30   - public void connect(String host, int port)
  35 + public void initializeStreams()
31 36 {
32   - SocketAddress addr = new InetSocketAddress(host,port);
33 37 try
34 38 {
35   - super.connect(addr);
  39 + output = new PrintWriter(super.getOutputStream());
  40 + input = new BufferedReader(new InputStreamReader(super.getInputStream()));
36 41 }
37 42 catch(IOException ioExc)
38 43 {
39   - System.out.println("TCP: Error occured while connecting to remote host");
  44 + System.out.println("TCP: Error initializing socket");
40 45 }
41 46 }
42 47  
... ... @@ -54,6 +59,27 @@ public class MySocket extends Socket
54 59 }
55 60 }
56 61  
  62 + public void sendMsg(String msg)
  63 + {
  64 + String length = new Integer(msg.length()).toString();
  65 + this.write(length+'\0', length.length()+1);
  66 + this.write(msg,msg.length());
  67 + }
  68 +
  69 + public String recvMsg()
  70 + {
  71 + String len,str;
  72 + int length;
  73 + len = this.readLine();
  74 + if(len == null)
  75 + {
  76 + return len;
  77 + }
  78 + length = Integer.parseInt(len);
  79 + str = this.read(length);
  80 + return str;
  81 + }
  82 +
57 83 public void write(String str, int bytes)
58 84 {
59 85 output.print(str.substring(0,bytes));
... ... @@ -78,7 +104,18 @@ public class MySocket extends Socket
78 104 {
79 105 try
80 106 {
81   - return input.readLine();
  107 + String line = "";
  108 + char[] c = new char[1];
  109 + while(true)
  110 + {
  111 + input.read(c,0,1);
  112 + if(c[0] == '\0')
  113 + {
  114 + break;
  115 + }
  116 + line += c[0];
  117 + }
  118 + return line;
82 119 }
83 120 catch(IOException ioExc)
84 121 {
... ...
JChatServer/src/pad/prac2/Server.java
1 1 package pad.prac2;
2 2  
3   -import java.io.BufferedReader;
4 3 import java.io.IOException;
5   -import java.io.InputStreamReader;
6   -import java.io.PrintWriter;
7   -import java.util.Collection;
8 4 import java.util.Iterator;
  5 +import java.util.Set;
9 6 import java.util.concurrent.ConcurrentHashMap;
  7 +import java.util.concurrent.locks.Condition;
  8 +import java.util.concurrent.locks.Lock;
  9 +import java.util.concurrent.locks.ReentrantLock;
10 10  
11 11 public class Server
12 12 {
13 13 private MyServerSocket ss;
14   - private BufferedReader stdin;
15   - private PrintWriter stdout;
16 14 private int roomSize;
17   - private boolean run;
18   -
19   - private Worker[] rWorkerPool;
20   - private Worker[] wWorkerPool;
21   -
22   - private ConcurrentHashMap<String,MySocket> activeConnections;
  15 + private boolean kill;
  16 + private Connection[] workerPool;
  17 + private int freeWorkers;
  18 + private Lock lock;
  19 + private Condition availableWorkers;
  20 + private ConcurrentHashMap<Connection,String> activeConnections;
23 21  
24 22 public Server(String ip, int port, int rS)
25 23 {
26 24 try
27 25 {
28 26 ss = new MyServerSocket();
29   - stdout = new PrintWriter(System.out);
30   - stdin = new BufferedReader(new InputStreamReader(System.in));
  27 + lock = new ReentrantLock();
  28 + activeConnections = new ConcurrentHashMap<Connection,String>();
31 29 roomSize = rS;
32   - rWorkerPool = new Worker[roomSize];
33   - wWorkerPool = new Worker[roomSize];
  30 + freeWorkers = roomSize;
  31 + kill = false;
  32 + availableWorkers = lock.newCondition();
  33 + workerPool = new Connection[roomSize];
  34 + for(int i = 0; i < roomSize; i++)
  35 + {
  36 + workerPool[i] = new Connection(this);
  37 + workerPool[i].start();
  38 + }
  39 + ss.bind(ip, port);
34 40 }
35 41 catch(IOException ioExc)
36 42 {
... ... @@ -38,39 +44,96 @@ public class Server
38 44 }
39 45 }
40 46  
41   - public void startServer()
  47 + public void sendToChat(Connection origin, String message)
42 48 {
43   -
  49 + lock.lock();
  50 + String nickname = activeConnections.get(origin);
  51 + Set<Connection> connections = activeConnections.keySet();
  52 + Iterator<Connection> it = connections.iterator();
  53 + Connection conn;
  54 + while(it.hasNext())
  55 + {
  56 + conn = it.next();
  57 + if(conn != origin)
  58 + {
  59 + conn.sendMessage(nickname + ": " + message);
  60 + }
  61 + }
  62 + lock.unlock();
44 63 }
45 64  
46   - public void startWorker(Worker r, Worker w, MySocket s)
  65 + public void startServer()
47 66 {
48   - if(r == null)
  67 + while(!kill)
49 68 {
50   - r = new Worker(s,null,stdout);
  69 + MySocket incoming = ss.accept();
  70 + if(incoming != null)
  71 + {
  72 + System.out.println("Accepted connection from " + incoming.getInetAddress());
  73 +
  74 + startWorker(incoming);
  75 + }
51 76 }
52   - r.awake();
53   - if(w == null)
  77 +
  78 + }
  79 +
  80 + public void startWorker(MySocket s)
  81 + {
  82 + lock.lock();
  83 + while(freeWorkers == 0)
54 84 {
55   - w = new Worker(s,stdin,null);
  85 + try
  86 + {
  87 + lock.unlock();
  88 + availableWorkers.await();
  89 + lock.lock();
  90 + }
  91 + catch(InterruptedException intExc)
  92 + {
  93 + intExc.printStackTrace();
  94 + }
56 95 }
57   - w.awake();
  96 + workerPool[roomSize - freeWorkers].setSock(s);
  97 + workerPool[roomSize - freeWorkers].awake();
  98 + workerPool[roomSize - freeWorkers] = null;
  99 + freeWorkers--;
  100 + lock.unlock();
  101 + }
  102 +
  103 + public String getNickname(Connection c)
  104 + {
  105 + return activeConnections.get(c);
  106 + }
  107 +
  108 + public void finishWorker(Connection c)
  109 + {
  110 + lock.lock();
  111 + freeWorkers++;
  112 + workerPool[roomSize - freeWorkers] = c;
  113 + availableWorkers.signal();
  114 + lock.unlock();
  115 + }
  116 +
  117 + public void addToChatroom(Connection c, String nickName)
  118 + {
  119 + activeConnections.put(c, nickName);
  120 + System.out.println(nickName + " has entered the room");
58 121 }
59 122  
60   - public void finishWorkers()
  123 + public void finishConnections()
61 124 {
62   - Collection<Worker> worerke= activeConnections.values();
63   - Iterator<MySocket> it = sockets.iterator();
  125 + Set<Connection> conns = activeConnections.keySet();
  126 + Iterator<Connection> it = conns.iterator();
64 127 while(it.hasNext())
65 128 {
66   - it.next().close();
  129 + it.next().finish();
67 130 }
68 131 }
69 132  
70 133 public void killServer()
71 134 {
72   - run = false;
  135 + kill = true;
73 136 ss.close();
74   - finishWorkers();
  137 + finishConnections();
75 138 }
76 139 }
... ...
JChatServer/src/pad/prac2/Worker.java deleted
1   -package pad.prac2;
2   -
3   -import java.io.BufferedReader;
4   -import java.io.IOException;
5   -import java.io.PrintWriter;
6   -
7   -public class Worker extends Thread
8   -{
9   - private PrintWriter output;
10   - private BufferedReader input;
11   - private MySocket sock;
12   - private boolean run;
13   - private boolean kill;
14   - private boolean sleep;
15   - private Server serv;
16   -
17   - public Worker(Server srv, MySocket s, BufferedReader i, PrintWriter o)
18   - {
19   - sock = s;
20   - output = o;
21   - input = i;
22   - run = false;
23   - kill = false;
24   - sleep = true;
25   - serv = srv;
26   - }
27   -
28   - public void finish()
29   - {
30   - kill = true;
31   - run = false;
32   - sleep = false;
33   - sock.close();
34   - }
35   -
36   - public void run()
37   - {
38   - while(!kill)
39   - {
40   - while(sleep)
41   - {
42   - try
43   - {
44   - wait();
45   - }
46   - catch (InterruptedException e)
47   - {
48   - e.printStackTrace();
49   - }
50   - }
51   - while(run)
52   - {
53   - if(output == null && input != null)
54   - {
55   - String str, length;
56   - while(true)
57   - {
58   - try
59   - {
60   - str = input.readLine();
61   - length = new Integer(str.length()).toString();
62   - sock.write(length, length.length());
63   - sock.write(str, str.length());
64   - }
65   - catch(IOException ioExc)
66   - {
67   - run = false;
68   - sleep = true;
69   - break;
70   - }
71   - }
72   - }
73   - else if(input == null && output != null)
74   - {
75   - String len, str;
76   - while((len = sock.readLine()) != null)
77   - {
78   - int length = Integer.parseInt(len);
79   - str = sock.read(length);
80   - output.println(str);
81   - }
82   - run = false;
83   - sleep = true;
84   - }
85   - }
86   - }
87   - }
88   -
89   - public void awake()
90   - {
91   - run = true;
92   - sleep = false;
93   - this.notify();
94   - }
95   -}