welcome: please sign in

Cerca

Link Dipartimentali

Link Esterni

Allegato "Socket.h"

Scarica

   1 #ifndef SOCKET_H_
   2 #define SOCKET_H_
   3 
   4 #include <iostream>
   5 #include <string.h>
   6 #include <stdlib.h>
   7 #include <exception>
   8 #include <errno.h>
   9 
  10 #include <sys/types.h>       // per data types
  11 #include <sys/socket.h>      // per socket(), connect(), send(), e recv()
  12 #include <netdb.h>           // per gethostbyname()
  13 #include <arpa/inet.h>       // per inet_addr()
  14 #include <unistd.h>          // per close()
  15 #include <netinet/in.h>      // per sockaddr_in
  16 using namespace std;
  17 
  18 typedef void raw_type; // tipo di base utilizzato nel seguito
  19 
  20 
  21 /**
  22  *   Segnala un problema nell'esecuzione di una socket call.
  23  */
  24 class SocketException: public exception {
  25 
  26 private:
  27 	string userMessage;
  28 
  29 public:
  30 
  31 	/**
  32 	 *  Costruisce una SocketException con un messaggio informativo.
  33 	 *  @param message è il messaggio
  34 	 *  @param incSysMsg true se si tratta di un messaggio di sistema (strerror(errno))
  35 	 */
  36 	SocketException(const string &message, bool inclSysMsg) throw () :
  37 		userMessage(message) {
  38 		if (inclSysMsg) {
  39 			userMessage.append(": ");
  40 			userMessage.append(strerror(errno));
  41 		}
  42 	}
  43 
  44 	~SocketException() throw () {
  45 	}
  46 
  47 	/**
  48 	 * Restituisce il messaggio di eccezione
  49 	 */
  50 	const char *what() const throw () {
  51 		return userMessage.c_str();
  52 	}
  53 
  54 };
  55 
  56 /**
  57  *   Astrazione per l'input stream associato ad un socket.
  58  */
  59 class InputStream {
  60 
  61 private:
  62 	int sockDesc; //identificativo o descrittore del socket
  63 
  64 public:
  65 	InputStream(int sd) {
  66 		sockDesc = sd;
  67 	}
  68 
  69 	virtual ~InputStream() {
  70 	}
  71 
  72 	/**
  73 	 * Legge e restituisce un carattere ricevuto sullo stream di input di un socket.
  74 	 * Puo' essere usato solo in presenza di una connessione.
  75 	 */
  76 	char read() {
  77 		int rtn;
  78 
  79 		//il risultato ottenuto e' contenuto nella memoria puntata da "input"
  80 		char * input = new char[1];
  81 
  82 		if ((rtn = ::recv(sockDesc, (raw_type *) input, 1, 0)) < 0) {
  83 			throw SocketException("Received failed (recv())", true);
  84 			//Il risultato della chiamata a questa funzione, in caso di errore, e' "-1",
  85 			//altrimenti e' il numero di caratteri ricevuti
  86 		}
  87 		return input[0];
  88 	}
  89 
  90 	/**
  91 	 * Legge e restituisce una linea ricevuta sullo stream di input di un socket.
  92 	 * Puo' essere usato solo in presenza di una connessione.
  93 	 */
  94 	string readLine() {
  95 		int rtn;
  96 		string str = "";
  97 
  98 		//il risultato ottenuto e' contenuto nella memoria puntata da "input"
  99 		char * input = new char[1];
 100 
 101 		//costruisce il risultato un carattere per volta fino a che non
 102 		//trova un carattere di '\n'
 103 		do {
 104 			if ((rtn = ::recv(sockDesc, (raw_type *) input, 1, 0)) < 0) {
 105 				throw SocketException("Received failed (recv())", true);
 106 				//Il risultato della chiamata a questa funzione, in caso di errore, e' "-1",
 107 				//altrimenti e' il numero di caratteri ricevuti
 108 			}
 109 			str += input[0];
 110 		} while (input[0] != '\n');
 111 
 112 		return str;
 113 	}
 114 };
 115 
 116 /**
 117  *   Astrazione per l'output stream associato ad un socket.
 118  */
 119 class OutputStream {
 120 
 121 private:
 122 	int sockDesc; //identificativo o descrittore del socket
 123 
 124 	char *convertStringToChar(const string &str) {
 125 
 126 		char *retPtr(new char[str.length() + 1]);
 127 		copy(str.begin(), str.end(), retPtr);
 128 		retPtr[str.length()] = '\0';
 129 		return retPtr;
 130 	}
 131 public:
 132 
 133 	OutputStream(int sd) {
 134 		sockDesc = sd;
 135 	}
 136 
 137 	virtual ~OutputStream() {
 138 	}
 139 
 140 	/**
 141 	 * Scrive un carattere sullo stream di output associato ad un socket.
 142 	 * Puo' essere usato solo in presenza di una connessione.
 143 	 */
 144 	void write(char c) {
 145 
 146 		char *output = new char[1];
 147 		output[0] = c;
 148 
 149 		//Questa funzione invia messaggi dal socket rappresentato dal descrittore
 150 		//"sockDesc" al socket con cui e' connesso.
 151 		if (::send(sockDesc, (raw_type *) output, 1, 0) < 0) {
 152 			throw SocketException("Send failed (send())", true);
 153 			//In caso di errore, la funzione "send" restituisce il valore "-1",
 154 			//altrimenti restituisce "0".
 155 		}
 156 	}
 157 
 158 	/**
 159 	 * Scrive una stringa sullo stream di output associato ad un socket.
 160 	 * Puo' essere usato solo in presenza di una connessione.
 161 	 */
 162 	void writeBytes(string str) {
 163 
 164 		char *output(convertStringToChar(str));
 165 
 166 		//Questa funzione invia messaggi dal socket rappresentato dal descrittore
 167 		//"sockDesc" al socket con cui e' connesso.
 168 		if (::send(sockDesc, (raw_type *) output, str.length(), 0) < 0) {
 169 			throw SocketException("Send failed (send())", true);
 170 			//In caso di errore, la funzione "send" restituisce il valore "-1",
 171 			//altrimenti restituisce "0".
 172 		}
 173 	}
 174 
 175 };
 176 
 177 class Socket {
 178 
 179 private:
 180 
 181 	InputStream *is;
 182 	OutputStream *os;
 183 
 184 	void connect(const string &foreignAddress, unsigned short foreignPort)
 185 			throw (SocketException) {
 186 
 187 		sockaddr_in destAddr;
 188 		fillAddr(foreignAddress, foreignPort, destAddr);
 189 
 190 		//Cerca di effettuare la connessione fra il socket passato come parametro
 191 		//con il socket in ascolto all'indirizzo specificato.
 192 		if (::connect(sockDesc, (sockaddr *) &destAddr, sizeof(destAddr)) < 0) {
 193 			throw SocketException("Connect failed (connect())", true);
 194 		}
 195 	}
 196 
 197 	static void fillAddr(const string &address, unsigned short port,
 198 			sockaddr_in &addr) {
 199 		memset(&addr, 0, sizeof(addr)); // Zero out address structure
 200 		addr.sin_family = AF_INET; // Internet address
 201 
 202 		hostent *host; // Resolve name
 203 		if ((host = gethostbyname(address.c_str())) == NULL) {
 204 			throw SocketException("Failed to resolve name (gethostbyname())",
 205 					true);
 206 		}
 207 		addr.sin_addr.s_addr = *((unsigned long *) host->h_addr_list[0]);
 208 		addr.sin_port = htons(port); // Assign port in network byte order
 209 	}
 210 
 211 protected:
 212 	int sockDesc; // Socket descriptor
 213 
 214 	void setLocalAddressAndPort(const string &localAddress,
 215 			unsigned short localPort) throw (SocketException) {
 216 
 217 		sockaddr_in localAddr;
 218 		fillAddr(localAddress, localPort, localAddr);
 219 
 220 		if (bind(sockDesc, (sockaddr *) &localAddr, sizeof(sockaddr_in)) < 0) {
 221 			throw SocketException(
 222 					"Set of local address and port failed (bind())", true);
 223 		}
 224 	}
 225 
 226 	void setLocalPort(unsigned short localPort) throw (SocketException) {
 227 
 228 		sockaddr_in localAddr;
 229 		memset(&localAddr, 0, sizeof(localAddr));
 230 		localAddr.sin_family = AF_INET;
 231 		localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
 232 		localAddr.sin_port = htons(localPort);
 233 
 234 		if (bind(sockDesc, (sockaddr *) &localAddr, sizeof(sockaddr_in)) < 0) {
 235 			throw SocketException("Set of local port failed (bind())", true);
 236 		}
 237 	}
 238 public:
 239 
 240 	Socket() throw (SocketException) {
 241 		if ((sockDesc = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
 242 			throw SocketException("Socket creation failed (socket())", true);
 243 		}
 244 		is = new InputStream(sockDesc);
 245 		os = new OutputStream(sockDesc);
 246 	}
 247 
 248 	Socket(const string &foreignAddress, unsigned short foreignPort)
 249 			throw (SocketException) {
 250 
 251 		if ((sockDesc = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
 252 			throw SocketException("Socket creation failed (socket())", true);
 253 		}
 254 		is = new InputStream(sockDesc);
 255 		os = new OutputStream(sockDesc);
 256 
 257 		connect(foreignAddress, foreignPort);
 258 	}
 259 
 260 	Socket(int type, int protocol) throw (SocketException) {
 261 
 262 		if ((sockDesc = socket(PF_INET, type, protocol)) < 0) {
 263 			throw SocketException("Socket creation failed (socket())", true);
 264 		}
 265 		is = new InputStream(sockDesc);
 266 		os = new OutputStream(sockDesc);
 267 	}
 268 
 269 	Socket(int sockDesc) {
 270 		this->sockDesc = sockDesc;
 271 
 272 		is = new InputStream(sockDesc);
 273 		os = new OutputStream(sockDesc);
 274 	}
 275 
 276 	/**
 277 	 *   Chiude e dealloca il socket
 278 	 */
 279 
 280 	~Socket() {
 281 		::close(sockDesc);
 282 		sockDesc = -1;
 283 		delete is;
 284 		delete os;
 285 	}
 286 
 287 	/**
 288 	 * Restituisce l'OutputStream in cui scrivere i messaggi da inviare tramite il socket.
 289 	 *
 290 	 */
 291 	OutputStream* getOutputStream() {
 292 		return os;
 293 	}
 294 
 295 	/**
 296 	 * Restituisce l' InputStream da cui leggere i messaggi provenienti dal socket.
 297 	 *
 298 	 */
 299 	InputStream* getInputStream() {
 300 		return is;
 301 	}
 302 
 303 	/**
 304 	 * Consente di chiudere la comunicazione sul socket identificato dal
 305 	 * descrittore "sockDesc".
 306 	 */
 307 	void close() {
 308 		::close(sockDesc);
 309 		sockDesc = -1;
 310 	}
 311 
 312 	/**
 313 	 *   Restituisce l'indirizzo locale a cui il socket è associato
 314 	 *   @return local address
 315 	 *   @exception SocketException se fallisce il recupero dell'indirizzo
 316 	 */
 317 	string getLocalAddress() throw (SocketException) {
 318 		sockaddr_in addr;
 319 		unsigned int addr_len = sizeof(addr);
 320 
 321 
 322 		if (getsockname(sockDesc, (sockaddr *) &addr, (socklen_t *) &addr_len)
 323 				< 0) {
 324 			throw SocketException(
 325 					"Fetch of local address failed (getsockname())", true);
 326 		}
 327 		return inet_ntoa(addr.sin_addr);
 328 	}
 329 
 330 	/**
 331 	 *   Restituisce la porta locale a cui il socket è associato
 332 	 *   @return local port
 333 	 *   @exception SocketException se fallisce il recupero dell'indirizzo
 334 	 */
 335 	unsigned short getLocalPort() throw (SocketException) {
 336 		sockaddr_in addr;
 337 		unsigned int addr_len = sizeof(addr);
 338 
 339 		//Permette di ottenere tramite "addr" le informazioni sull'indirizzo locale del socket
 340 		if (getsockname(sockDesc, (sockaddr *) &addr, (socklen_t *) &addr_len)
 341 				< 0) {
 342 			throw SocketException("Fetch of local port failed (getsockname())",
 343 					true);
 344 		}
 345 		return ntohs(addr.sin_port);
 346 	}
 347 
 348 };
 349 
 350 class ServerSocket: public Socket {
 351 
 352 private:
 353 	void setListen(int queueLen) throw (SocketException) {
 354 		//Mentre il socket e' in ascolto, puo' ricevere delle richieste di connessione.
 355 		//Mentre viene servita una di queste richieste, ne possono arrivare altre.
 356 		//Il procedimento adottato per tenere conto di questo fatto, e' di mettere le richieste in una coda di attesa.
 357 		//Listen si occupa di definire la dimensione massima di questa coda ("dimensione_coda").
 358 		if (listen(sockDesc, queueLen) < 0) {
 359 			throw SocketException("Set listening socket failed (listen())",
 360 					true);
 361 		}
 362 	}
 363 public:
 364 	ServerSocket(unsigned short localPort, int queueLen)
 365 			throw (SocketException) :
 366 		Socket(SOCK_STREAM, IPPROTO_TCP) {
 367 		setLocalPort(localPort);
 368 		setListen(queueLen);
 369 	}
 370 
 371 	ServerSocket(const string &localAddress, unsigned short localPort,
 372 			int queueLen) throw (SocketException) :
 373 		Socket(SOCK_STREAM, IPPROTO_TCP) {
 374 		setLocalAddressAndPort(localAddress, localPort);
 375 		setListen(queueLen);
 376 	}
 377 
 378 	ServerSocket(unsigned short localPort) throw (SocketException) :
 379 		Socket(SOCK_STREAM, IPPROTO_TCP) {
 380 		int queueLen = 5;
 381 		setLocalPort(localPort);
 382 		setListen(queueLen);
 383 	}
 384 
 385 	/**
 386 	 * Ha il compito di accettare una connessione, prendendo la prima connessione
 387 	 * disponibile sulla coda delle connessioni pendenti (vedi listen),
 388 	 * crea un nuovo socket con le stesse proprieta' di quello rappresentato dal
 389 	 * descrittore "sockDesc" e restituisce un nuovo descrittore.
 390 	 * La connessione puo', allora, essere gestita con questo nuovo socket.
 391 	 */
 392 	Socket *accept() throw (SocketException) {
 393 		int newConnSD;
 394 		if ((newConnSD = ::accept(sockDesc, NULL, 0)) < 0) {
 395 			throw SocketException("Accept failed (accept())", true);
 396 		}
 397 
 398 		return new Socket(newConnSD);
 399 	}
 400 };
 401 
 402 #endif /* SOCKET_H_ */
 403 

Allegati

Non è consentito inserire allegati su questa pagina.