[Débutant] Socket

Socket [Débutant] - C++ - Programmation

Marsh Posté le 13-02-2006 à 19:36:37    

Bonjour,
 
J'esseye de faire un script qui vérifie si un proxy fonctionne, voici mon code:
 

Code :
  1. #include <iostream>
  2. #include <winsock2.h>
  3. #pragma comment(lib, "ws2_32.lib" )
  4. using namespace std;
  5. int main(){
  6. WSADATA WSAData;
  7. WSAStartup(MAKEWORD(2,0), &WSAData);
  8. SOCKET sock;
  9. SOCKADDR_IN sin;
  10. sin.sin_addr.s_addr = inet_addr("81.242.92.251" );
  11. sin.sin_family  = AF_INET;
  12. sin.sin_port  = htons(80);
  13. sock = socket(AF_INET,SOCK_STREAM,0);
  14. bind(sock, (SOCKADDR *)&sin, sizeof(sin));
  15. if (connect(sock, (SOCKADDR *)&sin, sizeof(sin))==-1)
  16. {
  17.  cout<<"Mauvais proxy"<<endl;
  18. }else
  19. {
  20.  cout<<"Bon proxy"<<endl;
  21. }
  22. WSACleanup();
  23. return 0;
  24. }


 
Mes 2 questions:
1) Quand le proxy ne fonctionne pas, il faut environ 20 secondes avant qu'il me dise : "Mauvais proxy" : il y a t'il moyen de mettre une limite de temps et quel limite de temps me conseilleriez-vous pour tester un proxy ?
2) Y a-til moyen de rendre ce code compatible avec Linux sans changer trop de chose dans le code source ?
 
Merci d'avance...

Reply

Marsh Posté le 13-02-2006 à 19:36:37   

Reply

Marsh Posté le 14-02-2006 à 23:59:49    

1) sous linux j'utiliserai les signaux, avec SIGALARM
 
2) c'est quasi identique, juste les structures et 1 ou 2 fonction changent(c dans sys/socket.h je crois )

Reply

Marsh Posté le 16-02-2006 à 17:06:33    

Merci de ta réponse mais existe t-il quelque chose de similaire à sigalarm sous Windows ?

Reply

Marsh Posté le 16-02-2006 à 19:08:51    

alors la, aucune idée.
 
Mais je pense plutot qu'au bout de 20 secondes, il recoit une réponse du proxy qui dit qu'il ne possede pas de service sur le port 80.
 
Regarde les trames que tu recoit avec ethereal, tu saura d'ou vient l'attente.

Reply

Marsh Posté le 16-02-2006 à 19:18:46    

Peu importe d'où vient le problème de temps : je veux juste trouver un truc qui permet de stopper la fonction "connect" après x seconde.

Reply

Marsh Posté le 17-02-2006 à 00:19:39    

utilise une socket non bloquante
tu crée une socket, tu la rends non bloquante avec fcntl, tu la connecte avec connect, si connect te retourne EINPROGRESS, tu utilises alors un select pour savoir si elle est connecté, tu peux préciser le timeout dans le select
 
tu trouvera une explication plus détaillée ici :
http://www.faqs.org/faqs/unix-faq/socket/


Message édité par fat le 17-02-2006 à 00:20:00
Reply

Marsh Posté le 21-02-2006 à 20:21:33    

Merci (avec en peu de retard) de ta réponse.
 
Je vien d'esseyer de comprendre en peu ce que faisait fcntl mais j'ai un petit problème lors de la compilation de mon programme sous windows:

Code :
  1. #include <iostream>
  2. #include <winsock2.h>
  3. #include <fcntl.h>
  4. #include <unistd.h>
  5. #pragma comment(lib, "ws2_32.lib" )
  6. using namespace std;
  7. int main(){
  8. ....
  9. sock = socket(AF_INET,SOCK_STREAM,0);
  10. fcntl (sock, F_SETFL, O_NONBLOCK);
  11. }


 
Et les erreurs:
proxy.cpp: In function `int main()':
proxy.cpp:18: error: `F_SETFL' undeclared (first use this function)
proxy.cpp:18: error: (Each undeclared identifier is reported only once for each function it appears in.)
proxy.cpp:18: error: `O_NONBLOCK' undeclared (first use this function)
proxy.cpp:18: error: `fcntl' undeclared (first use this function)
 
 
Merci d'avance...


Message édité par casafa le 21-02-2006 à 20:28:06
Reply

Marsh Posté le 21-02-2006 à 20:53:32    

Avec linux:
WSADATA et fonctions relatives n existent pas,
 
SOCKADDR s appelle:
struct sockaddr
 
SOCKADDR_IN s appelle:
struct sockaddr_in *
 
Pour `F_SETFL' et `O_NONBLOCK':
essaye les includes:
<sys/fcntl.h>
<sys/ioctl.h>
<sys/types.h>
<sys/stat.h>
Il est aussi possible sur ton système que O_NONBLOCK s appelle O_NDELAY (ancien nom).

Reply

Marsh Posté le 21-02-2006 à 22:00:32    

Merci de ta réponse mais.....dans mon deuxième message, je dit que je cherche quelque chose qui permet de ne pas attendre 20 seconde pour que mon programme m'affiche "mauvais proxy" pour WINDOWS...
-On m'a proposer la solution de SIGALARM mais apparment c'est compatible que Linux.
-Maintenant on me propose un socket non-bloquant encore pour Linux.
 
Avez-vous une solution compatible Windows/linux ?
 
Ha la la si tout le monde serait sur Linux, la vie des programmeurs seraient bien plus simple, lol

Reply

Marsh Posté le 22-02-2006 à 05:55:29    

je vais être légérement hors sujet mais,
 
aurais tu des liens intéressants sur les sockets ?


---------------
http://www.blastmanu.info
Reply

Marsh Posté le 22-02-2006 à 05:55:29   

Reply

Marsh Posté le 22-02-2006 à 06:12:46    

blast, va voir sur le site perso de Sve@r, il a écrit des docs très utiles, mais je ne sais pas si les winsocks fonctionnent de la même manière, rien n'est moins sûr.


Message édité par el muchacho le 22-02-2006 à 06:17:08
Reply

Marsh Posté le 22-02-2006 à 09:06:29    

ok merci


---------------
http://www.blastmanu.info
Reply

Marsh Posté le 23-02-2006 à 17:03:34    

Personne n'a de solution ? :(

Reply

Marsh Posté le 23-02-2006 à 17:33:18    

La dernière fois que j ai fait une socket sous windoz, ça date! tu peut toujours aller voir du côté du site de krosoft.
 
Sous linux man 7 socket mentionne:
SO_RCVTIMEO/SO_SNDTIMEO (timeout),
SO_RCVLOWAT/SO_SNDLOWAT (buffer mémoire),
SO_SNDBUF/SO_RCVBUF (buffer socket)
 
Vaguement relatif:
SO_LINGER (timeout fermeture)
SO_PRIORITY (priorité IP)
 
Ioctls:
SIOCGSTAMP (timestamp du dernier octet reçu)
 
Si tu trouve pas mais que ton code marche sous linux, tu peut toujours essayer d installer Cygwin (émulateur+compilateur linux sous windoz).
 

Reply

Marsh Posté le 23-02-2006 à 19:01:21    

Je ne suis pas très interresser par le solution de Cygwin surtout si je veut distribuer mon programme !!
Avez-vous une solution compatible windows/linux ? je commence a désespérer :(

Reply

Marsh Posté le 23-02-2006 à 21:58:31    

Je viens de trouver une fonction similaire à fctnl mais pour windows:
 

Code :
  1. int main(){
  2. fd_set readfds;
  3. struct timeval tv;
  4.         tv.tv_sec = 2;
  5.         tv.tv_usec = 500000;
  6. int nonblocking=0;
  7. WSADATA WSAData;
  8. WSAStartup(MAKEWORD(2,0), &WSAData);
  9. SOCKET sock;
  10. SOCKADDR_IN sin;
  11. sin.sin_addr.s_addr = inet_addr("213.121.209.15" );
  12. sin.sin_family  = AF_INET;
  13. sin.sin_port  = htons(80);
  14. sock = socket(AF_INET,SOCK_STREAM,0);
  15. bind(sock, (SOCKADDR *)&sin, sizeof(sin));
  16. //fcntl (sock, F_SETFL, O_NONBLOCK);         /* LINUX */
  17. ioctlsocket(sock, FIONBIO, (unsigned long*) &nonblocking);  /* WINDOWS */
  18. connect(sock, (SOCKADDR *)&sin, sizeof(sin));
  19. select(sock, &readfds, NULL, NULL, &tv);
  20. WSACleanup();
  21. return 0;
  22. }


 
Le problème c'est que la fonction "connect" bloque quand même mon programme pendant 20 secondes comme si mon socket n'était pas non-bloquant !

Reply

Marsh Posté le 23-02-2006 à 22:23:58    

Quelques suggestions:
 
Sur un vieux code linux que j ai retrouvé, j utilise inet_aton plûtot que inet_addr:

Code :
  1. struct sockaddr_in addr;
  2.   addr.sin_family=AF_INET;
  3.   addr.sin_port=port;
  4.   if (!inet_aton((const char*)hostip,&addr.sin_addr))
  5.     addr.sin_addr.s_addr=0; // error!


 
D après man inet_addr:

Citation :


This is an obsolete interface to inet_aton


 
Autre chose: vérifie les appels à bind, connect et select?

Reply

Marsh Posté le 23-02-2006 à 22:25:38    

Il y a la fonction perror(NULL); qui affiche la dernière erreure système survenue.

Reply

Marsh Posté le 23-02-2006 à 22:39:41    

1) Apparament inet_aton n'existe pas sur windows !
 
2) Je vien de vérifier l'appel de "bind":

Code :
  1. if(bind(sock, (SOCKADDR *)&sin, sizeof(sin))){
  2.  cout<<"Erreur 1"<<endl;
  3.  exit(0);
  4. }


 
Et lors de l'éxécution du programme il m'affiche "Erreur 1", pourquoi ?

Reply

Marsh Posté le 23-02-2006 à 23:36:37    

essaye plutot:
(include stdio.h)

Code :
  1. if(bind(sock, (SOCKADDR *)&sin, sizeof(sin))){
  2.               perror(NULL);
  3.               exit(0);
  4.           }


 
... pour avoir une description de l erreure.

Reply

Marsh Posté le 23-02-2006 à 23:37:37    

sous linux, inet_aton est quelque part dans:
       #include <sys/socket.h>
       #include <netinet/in.h>
       #include <arpa/inet.h>

Reply

Marsh Posté le 23-02-2006 à 23:43:35    

quelques erreures possibles:
 
*       EBADF  sockfd is not a valid descriptor.
*       EACCES The address is protected, and the user is not the super-user.
*       EINVAL The socket is already bound to an address.

Reply

Marsh Posté le 24-02-2006 à 15:32:47    

Merci pour toutes vos réponses, voici comment j'ai fait:
 

Code :
  1. sock = socket(AF_INET,SOCK_STREAM,0);
  2. if(bind(sock, (SOCKADDR *)&sin, sizeof(sin))==EBADF){
  3.  cout<<"EBADF\n"<<endl;
  4.  exit(0);
  5. }else if(bind(sock, (SOCKADDR *)&sin, sizeof(sin))==EACCES){
  6.  cout<<"EACCES\n"<<endl;
  7.  exit(0);
  8. }else if(bind(sock, (SOCKADDR *)&sin, sizeof(sin))==EINVAL){
  9.  cout<<"EINVAL\n"<<endl;
  10.  exit(0);
  11. }
  12. //fcntl (sock, F_SETFL, O_NONBLOCK);         /* LINUX */
  13. ioctlsocket(sock, FIONBIO, (unsigned long*) &nonblocking);  /* WINDOWS */
  14. if(connect(sock, (SOCKADDR *)&sin, sizeof(sin))==-1){
  15.  cout<<"Erreur 2: "<<endl;
  16.  perror(NULL);
  17.  exit(0);
  18. }
  19. if(select(sock, &readfds, NULL, NULL, &tv) == SOCKET_ERROR){
  20.  cout<<"Erreur 3: "<<endl;
  21.  perror(NULL);
  22.  exit(0);
  23. }
  24. cout<<"Le proxy fonctionne.\n";


 
1) Si je teste mon programme sur une ip qui n'est pas un proxy, j'ai le droit à ce message 20 secondes après l'éxécution:
$ ./proxy.exe  
Erreur 2:  
No error
==> Pourquoi lui faut-il 20 secondes avant de m'afficher "Erreur 2.." alors que j'ai un socket non-bloquant ?
 
2) Si je teste mon programme sur une ip qui est un proxy:
$ ./proxy.exe  
Erreur 3:  
No error
==> Pourquoi m'affiche t'il cette erreur ?!
 
Autre petite question : Il me semble que windows (contrairement à Linux) n'est pas très évolué pour la programmation de socket, non ? Est-ce normal ? !
 
Merci d'avance...

Reply

Marsh Posté le 24-02-2006 à 16:08:23    

OOps, tu n est pas habitué à programmer en C...
 
La dernière erreure système se situe dans la variable <<errno>> (include errno.h). Chaque appel système met une valeur dans cette variable, soit 0 si pas d erreure, soit un numéro d erreure. L appel système retourne toujours -1 en cas d erreure.
 
Donc, d une part, ce n est pas le retour d un appel système qu il faut tester pour connaitre l erreure, mais la variable errno. En cas d erreure le retour sera -1 et errno contient le code d erreure.
 
Dautre part, lorsque tu écrit quelquechose à l aide de cout<<blabla<<endl;, celà change le code d erreure contenu dans errno, car cela fait appel au système. Dans ton cas il a réussi à écrire <<Erreure2:>> donc tout s est bien passé, donc pas d erreure.
 
Ok, le plus simple, je réécris le programme, fais du copier/coller:
 

Code :
  1. if(bind(sock, (SOCKADDR *)&sin, sizeof(sin))<0){
  2.         perror("L ouverture de socket a foiré car" );
  3.         exit(1);
  4.     }
  5. /* LINUX: */
  6.     //fcntl (sock, F_SETFL, O_NONBLOCK);                                     
  7. /* WINDOWS: */
  8.   if(ioctlsocket(sock, FIONBIO, (unsigned long*) &nonblocking)<0){
  9.         perror("La socket ne peut être rendu non-bloquante car" );
  10.         cerr<<"On continue quand même avec socket bloquante. Patience."<<endl;
  11.     }
  12.     if(connect(sock, (SOCKADDR *)&sin, sizeof(sin))<0){
  13.         perror("La connexion à l hôte distant a foiré car" );
  14.         exit(1);
  15.     }
  16.     int r=select(sock, &readfds, NULL, NULL, &tv);
  17.     if(r<0){
  18.         perror("La réponse de connexion a foiré car" );
  19.         exit(1);
  20.     }
  21.     else if(r==0){
  22.         cerr<<"Le proxy ne semble pas en route."<<endl;
  23.         exit(1);
  24.     }
  25.     else
  26.         cout<<"Le proxy a répondu favorablement. Tout semble ok."<<endl;


 
 
 
 

Reply

Marsh Posté le 24-02-2006 à 16:28:41    

Merci pour cette correction d'erreurs mais quelques soit l'ip, j'ai le droit au message suivant:
$ ./proxy.exe  
L ouverture de socket a foiré car: No error

Reply

Marsh Posté le 24-02-2006 à 17:03:43    

inclus <errno.h> et teste la variable errno avec les valeurs:
EPROTONOSUPPORT: protocole non supporté
EAFNOSUPPORT: famille non supporté
ENFILE: plus sockets libres
EMFILE: plus de fichiers libres
EACCES: accès interdit à ce type/protocol
ENOBUFS: plus de mémoire
ENOMEM: plus de mémoire
EINVAL: protocole ou famille inconnu

Reply

Marsh Posté le 24-02-2006 à 17:04:13    

Note: testes la avant perror()

Reply

Marsh Posté le 24-02-2006 à 17:21:35    

Voici ma fonctions erreurs:
 

Code :
  1. void erreurs(int erreur){
  2. switch(erreur){
  3.  case ENFILE:
  4.   cerr<<"plus sockets libres"<<endl;
  5.   exit(1);
  6.  case EMFILE:
  7.   cerr<<"plus de fichiers libres"<<endl;
  8.   exit(1);
  9.  case EACCES:
  10.   cerr<<"accès interdit à ce type/protocol "<<endl;
  11.   exit(1);
  12.  case ENOMEM:
  13.   cerr<<"plus de mémoire"<<endl;
  14.   exit(1);
  15.  case EINVAL:
  16.   cerr<<"protocole ou famille inconnu"<<endl;
  17.   exit(1);
  18.  default:
  19.   cout<<"Pas d'erreur"<<endl;
  20. }
  21. return ;
  22. }


 
Si j'appelle ma fonction erreurs(errno); avant ou après la fonction "bind" il m'affiche toujours : "Pas d'erreur".
Par contre EPROTONOSUPPORT, EAFNOSUPPORT et ENOBUFS ne semble pas exister sur windows !


Message édité par casafa le 24-02-2006 à 17:23:41
Reply

Marsh Posté le 24-02-2006 à 18:45:03    

Ok, mais teste aussi:
case 0: // pas d erreure
default: // erreure inconnue, afficher le numéro d erreure
 

Reply

Marsh Posté le 24-02-2006 à 18:46:35    

cerr<<"Erreure inconnue de numéro:"<<erreur<<endl;

Reply

Marsh Posté le 24-02-2006 à 19:04:05    

J'ai refait la fonction:
 

Code :
  1. void erreurs(int erreur){
  2. switch(erreur){
  3.  case 0:
  4.   cout<<"Pas d'erreur"<<endl;
  5.   break;
  6.  case ENFILE:
  7.   cerr<<"plus sockets libres"<<endl;
  8.   exit(1);
  9.  case EMFILE:
  10.   cerr<<"plus de fichiers libres"<<endl;
  11.   exit(1);
  12.  case EACCES:
  13.   cerr<<"accès interdit à ce type/protocol "<<endl;
  14.   exit(1);
  15.  case ENOMEM:
  16.   cerr<<"plus de mémoire"<<endl;
  17.   exit(1);
  18.  case EINVAL:
  19.   cerr<<"protocole ou famille inconnu"<<endl;
  20.   exit(1);
  21.  default:
  22.   cerr<<"Erreure inconnue de numéro:"<<erreur<<endl;
  23. }
  24. return ;
  25. }


 
Et voici le bout de code:

Code :
  1. erreurs(errno);
  2. if(bind(sock, (SOCKADDR *)&sin, sizeof(sin))<0){
  3.         perror("L ouverture de socket a foiré car" );
  4.         exit(1);
  5. }


 
Et voici le résultat spectaculaire que j'ai su produire  :wahoo: :
$ ./proxy.exe  
Pas d'erreur
L ouverture de socket a foiré car: No error
 
 
Qu'est ce que j'ai encore fait comme bétise ?


Message édité par casafa le 24-02-2006 à 19:05:13
Reply

Marsh Posté le 24-02-2006 à 19:39:25    

[code]
    if(bind(sock, (SOCKADDR *)&sin, sizeof(sin))<0){
           erreurs(errno);
           exit(1);
    }  
[/quote]

Reply

Marsh Posté le 24-02-2006 à 23:37:26    

Même en mettant le "erreurs(errorno);" après le bind, j'ai le même message : "Pas d'erreur".

Reply

Marsh Posté le 25-02-2006 à 17:14:44    

J'ai su afficher le numéro de l'erreur avec  : WSAGetLastError().
Le numéro de l'erreur est : 10049 : mais qu'est ce que ça signifie ?
 
[edit]
10049 ==> Impossible d'allouer l'adresse demandée.
J'ai cette erreur avec toutes les ips sauf 127.0.0.1 et 192.168.0.2 (celle de mon pc où j'éxécute mon programme), pourquoi ai-je une erreur 10049 avec les autres ip ?
[edit]


Message édité par casafa le 25-02-2006 à 17:28:08
Reply

Marsh Posté le 25-02-2006 à 20:14:13    

Après une longue recherche sur google:j'ai trouvé un post en anglais qui disait qu'il ne fallait pas utiliser bind pour un programme client (si j'ai bien compris pcq moi et l'anglais...) : http://www.codeguru.com/forum/show [...] did=259574 !
 
Quand j'éxécute se programme il faut environ 20 secondes avant qu'il m'affiche le numéro d'erreur 10060 qui signifie Délai de connection dépassé : ça me semble beaucoup pour un socket non-bloquant !!! Avez-vous une explication ?
 

Code :
  1. sock = socket(AF_INET,SOCK_STREAM,0);
  2.     /* LINUX: */
  3.     //fcntl (sock, F_SETFL, O_NONBLOCK);                                     
  4.     /* WINDOWS: */
  5.     if(ioctlsocket(sock, FIONBIO, (unsigned long*) &nonblocking)<0){
  6.         perror("La socket ne peut être rendu non-bloquante car" );
  7.         cerr<<"On continue quand même avec socket bloquante. Patience."<<endl;
  8.     }
  9.     if(connect(sock, (SOCKADDR *)&sin, sizeof(sin))<0){
  10.  cout<<WSAGetLastError()<<endl;
  11.         exit(1);
  12.     }


Message édité par casafa le 25-02-2006 à 20:15:22
Reply

Marsh Posté le 26-02-2006 à 22:12:47    

Pourquoi est ce qu il y a
bind(sock, (SOCKADDR *)&sin, sizeof(sin));
c est pour les serveurs pas les clients ?

Reply

Marsh Posté le 27-02-2006 à 09:53:22    

eviljojo ==> re-lie mon message juste au dessus du tien:  je dit exactement la même chose que toi.

Reply

Marsh Posté le 27-02-2006 à 20:38:13    

Oups désolé.

Reply

Marsh Posté le 19-04-2006 à 09:28:43    

Salut à tous !
 
Il est peut-être un peu tard pour toi mais je me dis que ça peut servir à d'autres.
Je crois que ton souci provient de la variable nonblocking que tu initialises à 0 alors qu'elle doit valoir 1 si tu veux rendre tes sockets non-bloquantes par un ioctlsocket. C'est la raison pour laquelle tu bloques toujours sur le connect.
 
Hope that helps !

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed