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.