View Full Version : Dev-C++ e programmazione di rete
Marinelli
04-03-2005, 16:19
Buongiorno a tutti, avrei un problema a compilare un programma sotto Dev-C++... il programma è un client che tenta di connettersi ad un server. Il codice è il seguente:
#include <stdio.h>
#include <winsock.h>
#include <windows.h>
#define close closesocket
#define PORT 4000
void addr_initialize (struct sockaddr_in *indirizzo, int port, long IPaddr)
{
indirizzo->sin_family=AF_INET;
indirizzo->sin_port=htons((u_short)port);
indirizzo->sin_addr.s_addr=IPaddr;
}
int main (int argc, char *argv[])
{
int sd;
struct sockaddr_in server_addr;
struct sockaddr_in mio_addr;
int mio_addr_len=sizeof(mio_addr);
int error;
addr_initialize (&server_addr, PORT, inet_addr(argv[1]));
sd=socket(AF_INET, SOCK_STREAM, 0);
error=connect(sd, (struct sockaddr*)&server_addr, sizeof(server_addr));
if (0==error)
{
printf ("Ho eseguito la connessione\n");
getsockname(sd, (struct sockaddr*)&mio_addr, &mio_addr_len);
printf ("La mia porta è: %d\n\n", ntohs(mio_addr.sin_port));
}
else printf ("%s", "Errore di connect\n\n");
close(sd);
system("PAUSE");
return 0;
}
Gli errori restituiti nella compilazione sono:
C:\DOCUME~1\ALBERT~1\IMPOST~1\Temp\ccSAaaaa.o(.text+0x1a) In function `Z15addr_initializeP11sockaddr_inil':
[Linker error] undefined reference to `htons@4'
C:\DOCUME~1\ALBERT~1\IMPOST~1\Temp\ccSAaaaa.o(.text+0xde) In function `main':
[Linker error] undefined reference to `WSAStartup@8'
[Linker error] undefined reference to `inet_addr@4'
[Linker error] undefined reference to `socket@12'
[Linker error] undefined reference to `connect@12'
[Linker error] undefined reference to `getsockname@12'
[Linker error] undefined reference to `ntohs@4'
[Linker error] undefined reference to `closesocket@4'
Credo di dover linkare la libreria libws2_32.a, ma non ho idea di come farlo. Qualcuno saprebbe darmi una mano?
Grazie mille.
Alberto
Fenomeno85
04-03-2005, 16:26
Alberto cmq le modifiche che ti messo ti servono almeno
#ifdef WIN32
WSADATA wsaData;
WSAStartup (0x0101,&wsaData);
#endif
la devi mettere se no fallisce la creazione della socket.
~§~ Sempre E Solo Lei ~§~
Marinelli
04-03-2005, 16:45
Ok, scusa... pensavo valessero solo per la compilazione sotto Visual C.
Il codice allora è questo:
#include <stdio.h>
#include <winsock.h>
#include <windows.h>
#define close closesocket
#define PORT 4000
void addr_initialize (struct sockaddr_in *indirizzo, int port, long IPaddr)
{
indirizzo->sin_family=AF_INET;
indirizzo->sin_port=htons((u_short)port);
indirizzo->sin_addr.s_addr=IPaddr;
}
int main (int argc, char *argv[])
{
int sd;
struct sockaddr_in server_addr;
struct sockaddr_in mio_addr;
int mio_addr_len=sizeof(mio_addr);
int error;
#ifdef WIN32
WSADATA wsaData;
WSAStartup (0x0101,&wsaData);
#endif
addr_initialize (&server_addr, PORT, inet_addr(argv[1]));
sd=socket(AF_INET, SOCK_STREAM, 0);
error=connect(sd, (struct sockaddr*)&server_addr, sizeof(server_addr));
if (0==error)
{
printf ("Ho eseguito la connessione\n");
getsockname(sd, (struct sockaddr*)&mio_addr, &mio_addr_len);
printf ("La mia porta è: %d\n\n", ntohs(mio_addr.sin_port));
}
else printf ("%s", "Errore di connect\n\n");
close(sd);
system("PAUSE");
return 0;
}
Marinelli
04-03-2005, 17:56
Ok, ho risolto... :)
E' sufficiente aggiungere "C:/Programmi/Vari/Dev-Cpp/lib/libws2_32.a" nelle opzioni di compilazione, aggiungi questi comandi alla linea di comando del linker.
Ciao ciao :)
nightwolf
04-03-2005, 22:05
A che servono le istruzioni:
WSADATA wsaData;
WSAStartup (0x0101,&wsaData);
e quando vanno incluse?
Ho notato che rispetto a linux le strutture e le chiamate alle funzioni di rete non cambiano;mi chiedevo:sarà cosi anche per tutte le altre che faremo (se ne faremo...)?
Servono ad inizializzare il Winsock per quella applicazione...
io sotto win non riesco a compilare nonostante abbia incluso la libreria, mi da errori sui file di libreria inclusi (winsock e windows.h)
Marinelli tu sei riuscito a compilarlo?
Fenomeno85
05-03-2005, 09:52
che compilatore usi ster?
sul vc6 / vc.net basta che vai nelle proprietà ;) e aggiungi nel linker la libreria ws2_32.lib.
Le funzioni che useremo son sempre identiche.
~§~ Sempre E Solo Lei ~§~
Fenomeno85
05-03-2005, 09:54
Originariamente inviato da nightwolf
A che servono le istruzioni:
WSADATA wsaData;
WSAStartup (0x0101,&wsaData);
e quando vanno incluse?
Ho notato che rispetto a linux le strutture e le chiamate alle funzioni di rete non cambiano;mi chiedevo:sarà cosi anche per tutte le altre che faremo (se ne faremo...)?
per la portabilità del codice oltre che definire anche le librerie in modo appropriato è meglio se metti quelle due istruzioni sotto #ifdef come postato.
Come detto da cionci serve a inizializzare e poter utilizzare il socket.
~§~ Sempre E Solo Lei ~§~
Fenomeno85
05-03-2005, 10:12
Originariamente inviato da cionci
Servono ad inizializzare il Winsock per quella applicazione...
cionci tre cose sul programma:
1) non è meglio sempre verificare che il descrittore del socket creato sia un valore >= 0? Alle superiori mi dicevano che era meglio ... all'uni nisba.
2) le costanti AF_INET e PF_INET non sono due cose differenti?? Io sapevo che AF_INET si riferiva al tipo di indirizzi IP della pila TCP/IP mentre PF_INET identificava la pila TCP/IP. All'uni è la stessa cosa.
3) quando si fa il connect non bisogna vedere per la precisione se è anche qui >= 0 il valore restituito e non solo =?
~§~ Sempre E Solo Lei ~§~
Fenomeno85
05-03-2005, 10:15
quindi per il codice tranne che per le librerie che non ho voglia di fare i casi quando si è sotto win che sotto linux
#include <stdio.h>
#include <winsock.h>
#include <windows.h>
#define close closesocket
#define PORT 6000
void addr_initialize (struct sockaddr_in *indirizzo, int port, long IPaddr){
indirizzo->sin_family=AF_INET;
indirizzo->sin_port=htons((u_short)port);
indirizzo->sin_addr.s_addr=IPaddr;
}
int main (int argc, char *argv[]){
int sd;
struct sockaddr_in server_addr;
struct sockaddr_in mio_addr;
int mio_addr_len=sizeof(mio_addr);
int error;
#ifdef WIN32
WSADATA wsaData;
WSAStartup (0x0101,&wsaData);
#endif
/* clear structure */
memset ((char*)&server_addr, 0, sizeof(server_addr));
memset ((char*)&mio_addr, 0, sizeof(mio_addr));
addr_initialize (&server_addr, PORT, inet_addr("127.0.0.1"));
sd=socket(AF_INET, SOCK_STREAM, 0);
if (sd < 0) {
printf ("\nSocket fallita.\n");
system ("PAUSE");
return (-1);
}
if (connect(sd, (struct sockaddr*)&server_addr, sizeof(server_addr))>=0){
printf ("Ho eseguito la connessione\n");
getsockname(sd, (struct sockaddr*)&mio_addr, &mio_addr_len);
printf ("La mia porta è: %d\n\n", ntohs(mio_addr.sin_port));
}
else printf ("%s", "Errore di connect\n\n");
system ("PAUSE");
close(sd);
return 0;
}
~§~ Sempre E Solo Lei ~§~
/* clear structure */
memset ((char*)&server_addr, 0, sizeof(server_addr));
memset ((char*)&mio_addr, 0, sizeof(mio_addr));
qual'è l'utilità di queste due memset ? :confused:
ciao ;)
Fenomeno85
05-03-2005, 11:11
Originariamente inviato da VICIUS
/* clear structure */
memset ((char*)&server_addr, 0, sizeof(server_addr));
memset ((char*)&mio_addr, 0, sizeof(mio_addr));
qual'è l'utilità di queste due memset ? :confused:
ciao ;)
è quella di azzerare tutta la struttura.
~§~ Sempre E Solo Lei ~§~
Originariamente inviato da Fenomeno85
è quella di azzerare tutta la struttura.
perchè azzerare la struttura quando con la chiamata di funzione successiva i dati vengono inizializati. ?
ciao ;)
Fenomeno85
05-03-2005, 11:32
perchè non inizializzi tutta la struttura.
~§~ Sempre E Solo Lei ~§~
Originariamente inviato da Fenomeno85
perchè non inizializzi tutta la struttura.
~§~ Sempre E Solo Lei ~§~
Ci sono solo quelle tre cose da inserire il resto è padding.
struct sockaddr_in {
short int sin_family; // Address family
unsigned short int sin_port; // Port number
struct in_addr sin_addr; // Internet address
unsigned char sin_zero[8]; // Same size as struct sockaddr
};
ciao ;)
Fenomeno85
05-03-2005, 12:36
mmm il bello è che si usa :mbe:
SOCKADDR_IN StructureSee Also
Structures, Styles, Callbacks, and Message Maps | SOCKADDR
In the Internet address family, the SOCKADDR_IN structure is used by Windows Sockets to specify a local or remote endpoint address to which to connect a socket.
struct sockaddr_in{
short sin_family;
unsigned short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
Parameters
sin_family
Address family (must be AF_INET).
sin_port
IP port.
sin_addr
IP address.
sin_zero
Padding to make structure the same size as SOCKADDR.
Remarks
This is the form of the SOCKADDR structure specific to the Internet address family and can be cast to SOCKADDR.
The IP address component of this structure is of type IN_ADDR. The IN_ADDR structure is defined in Windows Sockets header file WINSOCK.H as follows:
struct in_addr {
union {
struct{
unsigned char s_b1,
s_b2,
s_b3,
s_b4;
} S_un_b;
struct {
unsigned short s_w1,
s_w2;
} S_un_w;
unsigned long S_addr;
} S_un;
};
questo è quello che c'è anche su VC.NET ... cmq dato che sin_zero[8] deve valere 0 in conversione di struttura te glieli metti.
~§~ Sempre E Solo Lei ~§~
Originariamente inviato da Fenomeno85
questo è quello che c'è anche su VC.NET ... cmq dato che sin_zero[8] deve valere 0 in conversione di struttura te glieli metti.
:eek: e perché mai dovrebbe valere zero ?
scusate se continuo a rompervi ma questa cosa proprio non riesco a capirla.
ciao ;)
Fenomeno85
05-03-2005, 13:24
Originariamente inviato da VICIUS
:eek: e perché mai dovrebbe valere zero ?
scusate se continuo a rompervi ma questa cosa proprio non riesco a capirla.
ciao ;)
ti riporto le parole del mio libro delle superiori ("Internet e reti di calcolatori")
... anche se un indirizzo TCP/IP è lungo 6 byte,
la struttura sockaddr ne prevede 14 per memorizzare
gli indirizzi. Per questo motivo, l'ultimo campo di sockaddr_in
è costituito da 8 byte nulli, in modo che la lunghezza totale
della struttura sia pari a quella a quella di sockaddr.
~§~ Sempre E Solo Lei ~§~
Fenomeno85
05-03-2005, 13:30
cercando con google:
Come si nota nel listato, è necessario porre a zero 8 bytes della
struttura dove l'indirizzo IP è stato caricato.
Perchè azzerare 8 bytes? Perchè poi proprio 8 bytes?
Per compatibilità all'indietro con la vecchia sockaddr
(senza _in ).
E' facile fare il cast di un puntatore se le strutture hanno la stessa dimensione (ragion per cui
sono 8 bytes)
e poiché i dati non sono posti a zero dopo la loro allocazione e necessario azzerarli a mano.
quindi avevo ragione la struttura va azzerata o almento devi azzera gli 8 byte... quindi se azzeri tutta la struttura è lu stess .. bye
~§~ Sempre E Solo Lei ~§~
Fenomeno85
05-03-2005, 13:33
intanto aspettiamo che cionci mi illumini con i miei tre problemi :D
cionci batti un colpo se ci sei :D
~§~ Sempre E Solo Lei ~§~
Originariamente inviato da Fenomeno85
cionci tre cose sul programma:
1) non è meglio sempre verificare che il descrittore del socket creato sia un valore >= 0? Alle superiori mi dicevano che era meglio ... all'uni nisba.
2) le costanti AF_INET e PF_INET non sono due cose differenti?? Io sapevo che AF_INET si riferiva al tipo di indirizzi IP della pila TCP/IP mentre PF_INET identificava la pila TCP/IP. All'uni è la stessa cosa.
3) quando si fa il connect non bisogna vedere per la precisione se è anche qui >= 0 il valore restituito e non solo =?
1) su Windows la socket ritorna un valore di tipo SOCKET di conseguenza non è logico confrontarlo con un intero...anche se è comunque rappresentato da un intero... Su Windows devi confrontarlo con INVALID_SOCKET per verificarne la correttezza...
2) A* si usano nelle strutture dati relative agli indirizzi... P* si usano all'interno delle chiaamte a socket... Comunque almeno adesso le costanti P* sono uguali alle costanti A*...
3) devi solo controllare il valroe 0 perchè la connect ha avuto successo solo se ritorna 0...
Fenomeno85
05-03-2005, 13:54
Originariamente inviato da cionci
1) su Windows la socket ritorna un valore di tipo SOCKET di conseguenza non è logico confrontarlo con un intero...anche se è comunque rappresentato da un intero... Su Windows devi confrontarlo con INVALID_SOCKET per verificarne la correttezza...
2) A* si usano nelle strutture dati relative agli indirizzi... P* si usano all'interno delle chiaamte a socket... Comunque almeno adesso le costanti P* sono uguali alle costanti A*...
3) devi solo controllare il valroe 0 perchè la connect ha avuto successo solo se ritorna 0...
ottimo grazie
~§~ Sempre E Solo Lei ~§~
Originariamente inviato da Fenomeno85
cercando con google:
Come si nota nel listato, è necessario porre a zero 8 bytes della
struttura dove l'indirizzo IP è stato caricato.
Perchè azzerare 8 bytes? Perchè poi proprio 8 bytes?
Per compatibilità all'indietro con la vecchia sockaddr
(senza _in ).
E' facile fare il cast di un puntatore se le strutture hanno la stessa dimensione (ragion per cui
sono 8 bytes)
e poiché i dati non sono posti a zero dopo la loro allocazione e necessario azzerarli a mano.
quindi avevo ragione la struttura va azzerata o almento devi azzera gli 8 byte... quindi se azzeri tutta la struttura è lu stess .. bye
~§~ Sempre E Solo Lei ~§~
Come puo il valore di 8 byte di padding influire sul cast di una variabile ? Continuo a non vedere una singola valida ragione per impostare quei byte a 0.
ciao ;)
Sul cast di un puntatore la dimensione non ha alcuna influenza...ma sull'interpretazione della struttura intera da parte dei programmi scritti in maniera obsoleta sì... Se le due strutture hanno dimensione uguale, anche se ad una funzione gli viene passata la struttura vecchia, la conversione alal nuova ha costo zero... Un po' come succede con una union...
Marinelli
06-03-2005, 00:18
Originariamente inviato da SteR9
io sotto win non riesco a compilare nonostante abbia incluso la libreria, mi da errori sui file di libreria inclusi (winsock e windows.h)
Marinelli tu sei riuscito a compilarlo?
Sì, sono riuscito a compilarlo... utilizzo il Dev-C++ 4.9.9.2
Ciao
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.