[C - Newby] Telnet en C

Telnet en C [C - Newby] - C++ - Programmation

Marsh Posté le 26-10-2003 à 17:22:26    

Voilà mon problème : j'essaie d'écrire un client qui se connecte à un site web à partir d'une socket en tcp. Ensuite l'utilisateur peut taper une requête HTTP vers se serveur. La réponse du serveur est alors affichée à l'écran. Voici mon code :
 

Code :
  1. #include <sys/types.h>
  2. #include <sys/socket.h>
  3. #include <netinet/in.h>
  4. #include <unistd.h>
  5. #include <netdb.h>
  6. main()
  7. {
  8. int sock;
  9. struct hostent* he;
  10. struct sockaddr_in cli, srv;
  11. int size=sizeof(struct sockaddr_in);
  12. char buf[1024];
  13.         char buf2[1024];
  14. sock=socket(AF_INET,SOCK_STREAM,0);
  15. cli.sin_family=AF_INET;
  16. he=gethostbyname("localhost" );
  17. memcpy(&cli.sin_addr,he->h_addr,sizeof(cli.sin_addr));
  18. cli.sin_port=htons(80);
  19.         srv.sin_family=AF_INET;
  20. he=gethostbyname("www.yahoo.fr" );
  21. memcpy(&srv.sin_addr,he->h_addr,sizeof(srv.sin_addr));
  22. srv.sin_port=htons(80);
  23. int a=bind(sock,(struct sockaddr*)&cli,sizeof(cli));
  24. if(a!=0) {perror("Bind : " );exit(0);}
  25. int b=connect(sock,(struct sockaddr*)&srv,size);
  26. if(b!=0) {perror("Connect : " );exit(0);}
  27. printf("Entrer la requete :\n" );
  28. scanf("%s",buf);
  29.         send(sock,buf,sizeof(buf),0);
  30. recv(sock,buf2,sizeof(buf),0);
  31. printf("%s\n",buf2);
  32. close(sock);
  33. }


 
avec ce code j'essaie de me connecter sur yahoo pour envoyer ma requête mais j'ai une erreur au niveau du connect : Invalid argument et je ne voit pas d'où ça vient : de la construction de srv, des ports???
Quelqu'un peut m'aider?

Reply

Marsh Posté le 26-10-2003 à 17:22:26   

Reply

Marsh Posté le 26-10-2003 à 17:25:08    

il y a une rubrique c, et une c++, ici on est dans la c++ :D
 
sinon, tu veux apparement binder ton port local 80, as-tu vérifié qu'il n'etait pas déjà utilisé ?


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 26-10-2003 à 17:27:32    

oups dsl pour la rubrique.
mon port 80 est le port http de ma machine donc je pense que c'est le bon port à utiliser. De plus l'erreur ne viens pas du bind mais du connect.

Reply

Marsh Posté le 26-10-2003 à 19:51:30    

Personne n'a d'idées?

Reply

Marsh Posté le 26-10-2003 à 19:54:39    

tu compiles sous quel OS ?


---------------
J'ai un string dans l'array (Paris Hilton)
Reply

Marsh Posté le 26-10-2003 à 20:14:58    

Linux Red Hat 8 avec gcc

Reply

Marsh Posté le 26-10-2003 à 21:09:59    

pour détereminer les pbs et débuguer plus facilement ton application, sécurise la déjà : par exemple, vérifie la valeur de retour de tes fonctions, style :  
if(sock = socket(...) == false)
// affiche message
 
ça t'aidera à savoir ce qui marche ou pas. Prendre cette habitude est primordiale en prod, et spécialement en socket où ça ne marche jamais comme on veut

Reply

Marsh Posté le 26-10-2003 à 21:44:17    

Code :
  1. int a=bind(sock,(struct sockaddr*)&cli,sizeof(cli));
  2. if(a!=0) {perror("Bind : " );exit(0);}

 
 

Code :
  1. int b=connect(sock,(struct sockaddr*)&srv,size);
  2. if(b!=0) {perror("Connect : " );exit(0);}


 
C'est grâce à ces tests que j'ai pu voir que le connect ne marche pas : perror() du connect me retourne invalid argument

Reply

Marsh Posté le 26-10-2003 à 23:16:59    

Regarde ces lignes :
 
memcpy(&cli.sin_addr,he->h_addr,sizeof(cli.sin_addr));
memcpy(&srv.sin_addr,he->h_addr,sizeof(srv.sin_addr));
 
Dans la définition de la structure sockaddr_in, le membre sin_addr est une structure de type in_addr. T'as pas l'impression de faire un peu n'importe quoi là ? Pas étonnant que je me prenne une segmentation fault si je lance ton programme en n'étant pas connecté au net... :sarcastic:
 
Pour info, le membre qui contient les adresses est sockaddr_in.sin_addr.s_addr.
 
Ce qui nous donne :

Code :
  1. memcpy(&cli.sin_addr.s_addr,he->h_addr,sizeof(struct in_addr));
  2. memcpy(&srv.sin_addr.s_addr,he->h_addr,sizeof(struct in_addr));


 
Regarde au moins la définition des structures la prochaine fois...


Message édité par Harkonnen le 26-10-2003 à 23:17:22
Reply

Marsh Posté le 27-10-2003 à 14:43:07    

ok mais pourquoi ça fonctionne parfaitement lorsque l'on fait tourner le serveur et le client sur la même machine? j'ai compilé avec ce que tu m'as gentiment conseillé mais j'ai toujours la même erreur : Connect:Invalid Argument (et un segmentation fault quand je ne suis pas connecté à Internet :wahoo: )

Reply

Marsh Posté le 27-10-2003 à 14:43:07   

Reply

Marsh Posté le 27-10-2003 à 22:40:23    

J'ai repris ton source un peu plus en détail, je l'ai modifié et il marche. Ne compte pas sur moi pour te donner le source, ça serait trop facile. Je te donne juste quelques pistes :
 
- il te faut 2 sockets : 1 client et 1 serveur. Pourquoi 2 sockets ? Tout simplement parce que le 1er paramètre de la fonction socket() change selon qu'il s'agit d'un client ou d'un serveur et leur fonction n'est pas la même
- les memset() pour vider la structure sockaddr_in, c'est bien, manges en
- si tu veux éviter la segmentation fault en n'étant pas connecté au net, je te conseille de tester la valeur de retour de gethostbyname("www.yahoo.fr" )
- la valeur que tu donnes au membre sin_family de ta structure sockaddr_in n'est pas bon. regarde plutot du coté de he->h_addrtype
- si tu tiens vraiment à utiliser le membre sin_addr de ta structure sockaddr_in, tape plutot un truc du genre :

Code :
  1. memcpy((char *)&srv.sin_addr,he->h_addr,he->h_length);


 
voici ce que j'obtiens :

Citation :


[harkonnen@localhost Documents]# ./socket
Entrer la requete :
GET index.html
The document has moved <A HREF="http://de.docs.yahoo.com/notfound.html">here</A>.<P>


 
à toi de jouer maintenant...


Message édité par Harkonnen le 27-10-2003 à 22:41:48
Reply

Marsh Posté le 28-10-2003 à 05:55:27    

Heu pourquoi deux sockets ? :heink:

Reply

Marsh Posté le 28-10-2003 à 09:17:56    

Il n'a besoin que d'un socket effectivement, mais je suppose que s'il a mis le socket "localhost", c'est qu'il compte l'utiliser par la suite [:sinclaire]
Mais c'est clair que tel qu'il est codé dans son source, il ne sert à rien du tout (il est bindé, mais sans listen() ou connect() derrière, etc..)


---------------
J'ai un string dans l'array (Paris Hilton)
Reply

Marsh Posté le 28-10-2003 à 09:38:56    

je vois pas pourquoi il faudrait 2 sockets. Le listen est géré par le serveur. Ce code fonctionne parfaitement lorsque je fais tourner un serveur sur une machine du même réseau que le client.

Reply

Marsh Posté le 28-10-2003 à 09:52:05    

Alors à quoi te servent ces lignes ?

Code :
  1. sock=socket(AF_INET,SOCK_STREAM,0);
  2. cli.sin_family=AF_INET;
  3. he=gethostbyname("localhost" );
  4. memcpy(&cli.sin_addr,he->h_addr,sizeof(cli.sin_addr));
  5. cli.sin_port=htons(80);
  6. [...]
  7. int a=bind(sock,(struct sockaddr*)&cli,sizeof(cli));


Pourquoi bindes tu un socket avec localhost si ensuite tu utilises ce socket pour te connecter sur yahoo ?
J'ai supprimé ces lignes et ça fonctionne très bien, en faisant les modifs que je t'ai donné plus haut, j'arrive à me connecter sur le serveur de yahoo sans problème


---------------
J'ai un string dans l'array (Paris Hilton)
Reply

Marsh Posté le 28-10-2003 à 10:59:24    

il faut bien construire la structure sockaddr_in cli pour savoir sur quel port on travaille sur la machine local nan?
le bind est là pour associer un port à la socket.


Message édité par dudul51 le 28-10-2003 à 11:02:43
Reply

Marsh Posté le 28-10-2003 à 11:07:31    

pourquoi veux tu indiquer le port sur lequel travaille la machine locale ?
moi j'ai enlevé de ton source toute la partie qui concerne la structure cli (les lignes de mon post précédent), et ça marche bien [:sinclaire]
 
edit: le bind() serait utile si tu faisais un listen() derrière, pour un connect(), à mon avis c'est inutile


Message édité par Harkonnen le 28-10-2003 à 11:15:16

---------------
J'ai un string dans l'array (Paris Hilton)
Reply

Marsh Posté le 28-10-2003 à 11:16:16    

parce qu'une socket à toujours un numéro de port associé!  
de toute façon l'erreur ne vient pas de là.
 
edit: en tcp on a:
 
client : bind puis connect (il est vrai que le bind n'est pas obligatoire que le connect s'en charge).
serveur : listen puis accept
 
le client ne fait jamais de listen et donc jamais d'accept.


Message édité par dudul51 le 28-10-2003 à 11:18:41
Reply

Marsh Posté le 28-10-2003 à 11:19:50    

dudul51 a écrit :

parce qu'une socket à toujours un numéro de port associé!  
de toute façon l'erreur ne vient pas de là.


 
J'en suis pas si sûr... Déjà ton utilisation du port 80 pour le client est louche, j'essairai avec un port > 1024, et puis la plus part du temps on se fout de savoir quel port on utilise pour sortir  [:spamafote]


---------------
Le Tyran
Reply

Marsh Posté le 28-10-2003 à 11:20:59    

Harkonnen a écrit :

pourquoi veux tu indiquer le port sur lequel travaille la machine locale ?
moi j'ai enlevé de ton source toute la partie qui concerne la structure cli (les lignes de mon post précédent), et ça marche bien [:sinclaire]
 
edit: le bind() serait utile si tu faisais un listen() derrière, pour un connect(), à mon avis c'est inutile


 
Si j'ai bien tout compris à la chose, c utile si tu veux utiliser un port spécifique pour sortir... mais la son port 80 c'est une mauvaise idée.


---------------
Le Tyran
Reply

Marsh Posté le 28-10-2003 à 11:49:53    

dudul51 a écrit :

parce qu'une socket à toujours un numéro de port associé!  


oui merci je le sais ;)
mais si tu ne fais aucun listen(), je vois pas l'utilité de binder ton socket à localhost
 

dudul51 a écrit :


de toute façon l'erreur ne vient pas de là.


Non elle ne vient pas de là. J'ai corrigé ton source selon les indications que je t'ai donné plus haut, et ça fonctionne très bien, avec ou sans le bind() de toute façon. Essaie de trouver l'erreur par toi même, je ne t'aiderais pas si je te donne le source tout fait.


---------------
J'ai un string dans l'array (Paris Hilton)
Reply

Marsh Posté le 28-10-2003 à 16:29:08    

LetoII a écrit :


 
Si j'ai bien tout compris à la chose, c utile si tu veux utiliser un port spécifique pour sortir... mais la son port 80 c'est une mauvaise idée.


 
c'est le port http le port 80 et je veux me connecter à un serveur pour exécuter une requête http.

Reply

Marsh Posté le 28-10-2003 à 16:34:04    

dudul51 a écrit :


 
c'est le port http le port 80 et je veux me connecter à un serveur pour exécuter une requête http.


 
Oui mais tu ton client peut utiliser n'importe quel port pour sortir.


---------------
Le Tyran
Reply

Marsh Posté le 28-10-2003 à 16:41:44    

c'est vrai, je viens d'essayer avec un port différent et ça marche. Je pensais que la socket du client devait être associée elle aussi au port 80. Merci.

Reply

Marsh Posté le 28-10-2003 à 16:41:58    

De toute façon, un bind() est inutile si tu cherches à te connecter à un site web, à mon avis. Un connect() suffit, et ensuite tu utilises les fonctions send() et recv() pour dialoguer avec le site.


---------------
J'ai un string dans l'array (Paris Hilton)
Reply

Marsh Posté le 28-10-2003 à 16:46:52    

pour info, voici ce que j'ai fait :

Code :
  1. #include <sys/types.h>
  2. #include <sys/socket.h>
  3. #include <netinet/in.h>
  4. #include <unistd.h>
  5. #include <netdb.h>
  6. #include <string.h>
  7. #include <stdio.h>
  8. int main(int argc, char **argv)
  9. {
  10. int sock;
  11. struct hostent* he;
  12. struct sockaddr_in srv;
  13. char buf[1024];
  14. char buf2[1024];
  15. memset(&srv,0,sizeof(struct sockaddr_in));
  16. he=gethostbyname("www.yahoo.fr" );
  17. if (he == NULL) {
  18.  perror("www.yahoo.fr" );
  19.  return (-1);
  20. }
  21. srv.sin_family=he->h_addrtype;
  22. memcpy((char *)&srv.sin_addr,he->h_addr,he->h_length);
  23. srv.sin_port=htons(80);
  24. socksrv = socket(he->h_addrtype,SOCK_STREAM,0);
  25. int b=connect(socksrv,(struct sockaddr*)&srv,size);
  26. if(b != 0) {
  27.  perror("Connect" );
  28.  return(-1);
  29. }
  30. printf("Entrer la requete :\n" );
  31. scanf("%s",buf);
  32. send(socksrv,buf,sizeof(buf),0);
  33. recv(socksrv,buf2,sizeof(buf),0);
  34. printf("%s\n",buf2);
  35. close(socksrv);
  36. }


Message édité par Harkonnen le 28-10-2003 à 16:49:46

---------------
J'ai un string dans l'array (Paris Hilton)
Reply

Marsh Posté le 28-10-2003 à 17:51:39    

Sinon tres bon site ici

Reply

Marsh Posté le 28-10-2003 à 21:44:50    

Il est vrai que sans le bind() ça marche aussi. Merci pour ton aide.

Reply

Marsh Posté le 29-10-2003 à 04:25:42    

Pour info, si tu ne fais pas de bind(), alors le connect() prend un numéro de port aléatoire au dessus de 1024. Et c'est la bonne façon de faire, sauf besoin particulier (du genre un firewall qui ne laisse sortir que quelques ports bien particuliers).
 
Au final tu as côté serveur une socket bindée sur le port 80, et côté client une socket bindée sur un port arbitraire au dessus de 1024.

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

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