2010-04-16 2 views
3

Salut à tous, je suis sur le point de m'arracher les cheveux. J'ai ce client qui essaie de se connecter à un serveur, tout semble bien se passer, en utilisant gethostbyname(), socket(), bind(), mais en essayant de connect() il se bloque juste là et le serveur ne voit rien du client. Je sais que le serveur fonctionne parce qu'un autre client (aussi en C) peut se connecter très bien. Qu'est-ce qui fait que le serveur ne voit pas cette connexion entrante? Je suis au bout de mes peines ici. Les deux clients différents sont assez similaires aussi je suis encore plus perdu.C socket programmation: connect() se bloque

if (argc == 2) { 
    host = argv[1];   // server address 
} 
else { 
    printf("plz read the manual\n"); 
    exit(1); 
} 

hserver = gethostbyname(host); 
if (hserver) { 
    printf("host found: %p\n", hserver); 
    printf("host found: %s\n", hserver->h_name); 
} 
else { 
    printf("host not found\n"); 
    exit(1); 
} 

bzero((char *) &server_address, sizeof(server_address)); // copy zeroes into string 
server_address.sin_family = AF_INET; 
server_address.sin_addr.s_addr = htonl(hserver->h_addr); 
server_address.sin_port = htons(SERVER_PORT); 

bzero((char *) &client_address, sizeof(client_address)); // copy zeroes into string 
client_address.sin_family = AF_INET; 
client_address.sin_addr.s_addr = htonl(INADDR_ANY); 
client_address.sin_port = htons(SERVER_PORT); 

sockfd = socket(AF_INET, SOCK_STREAM, 0); 
if (sockfd < 0) 
    exit(1); 
else { 
    printf("socket is opened: %i \n", sockfd); 
    info.sock_fd = sockfd; 
    rv = fcntl(sockfd, F_SETFL, O_NONBLOCK); // socket set to NONBLOCK 
    if(rv < 0) 
     printf("nonblock failed: %i %s\n", errno, strerror(errno)); 
    else 
     printf("socket is set nonblock\n"); 
} 

timeout.tv_sec = 0;  // seconds 
timeout.tv_usec = 500000; // micro seconds (0.5 seconds) 
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)); 

rv = bind(sockfd, (struct sockaddr *) &client_address, sizeof(client_address)); 
if (rv < 0)  { 
    printf("MAIN: ERROR bind() %i: %s\n", errno, strerror(errno)); 
    exit(1); 
} 
else 
    printf("socket is bound\n"); 

rv = connect(sockfd, (struct sockaddr *) &server_address, sizeof(server_address)); 
printf("rv = %i\n", rv); 
if (rv < 0)  { 
    printf("MAIN: ERROR connect() %i: %s\n", errno, strerror(errno)); 
    exit(1); 
} 
else 
    printf("connected\n"); 

Toute idée ou idée est profondément grandement appréciée.

-Fourier

EDIT: Si la prise est pas mis sur la non-bloc, puis il se bloque. Si la prise est réglée sur la non-bloc, je reçois ERROR connect() 115: Operation now in progress

[EINPROGRESS] O_NONBLOCK est défini pour le descripteur de fichier pour la prise et la connexion ne peut pas être immédiatement établie; la connexion doit être établie de manière asynchrone.

Je voudrais également mentionner que le serveur et le client tournent sur des ordinateurs les uns à côté des autres, connectés par un routeur.

+0

Pouvez-vous nous donner la valeur de errno? – ereOn

+0

errno est 115 mais il est résolu maintenant. Merci beaucoup –

+0

Stupide pensée: le serveur permet-il à plusieurs clients de se connecter? Après le "accept()" cela engendre-t-il un thread, un childprocess ou utilise select() pour redémarrer acceptant() des connexions entrantes ET gérer le trafic du client qui vient de se connecter? – haavee

Répondre

3

La fonction gethostbyname() produit des adresses dans l'ordre des octets du réseau, vous n'avez donc pas besoin de les passer par htonl(). En outre, l'entrée hostent->h_addr est un pointeur vers l'adresse. Remplacez cette ligne:

server_address.sin_addr.s_addr = htonl(hserver->h_addr); 

avec:

memcpy(&server_address.sin_addr, hserver->h_addr, hserver->h_length); 
+0

J'ai également supprimé le non-bloc, et il ne se bloque plus mais donne 111: connexion refusée. C'est étrange parce que je cours l'autre client sur la même machine (en tant que client cassé) et le serveur accepte la connexion juste très bien. –

+0

Eh bien "connexion refusée" est assez claire. Peut-être que votre 'SERVER_PORT' est également faux. – caf

+0

oui je ne peux pas croire que je n'ai pas attrapé ça. 12345 et 12346 ont semblé sacrés semblables grâce à ma vue inexistante. –

0

Vérifiez que vous pouvez vous connecter avec le programme telnet (il accepte un nom de serveur et un numéro de port). Si cela fonctionne, le bug doit être dans votre code. Si telnet se bloque également, vérifiez les paramètres de votre pare-feu.

+0

Si je comprends bien, il a deux clients et l'un d'eux peut déjà se connecter avec succès. – ereOn

1

Je vois que vous réglez votre socket en mode O_NONBLOCK.

Ainsi, connect doit renvoyer -1 et définir errno sur EAGAIN en fonction de the man page of connect.

Vous pouvez alors savoir quand la connexion a réussi en utilisant select() sur le socket.

Il s'agit d'un modèle très courant pour contrôler le délai de connexion (car select() doit être alimenté avec un délai d'expiration).

0

Si vous souhaitez connecter deux fois de la même machine que je peux voir la raison de votre problème.

Vous liez le clientocket. Votre code lie le socket client très spécifiquement à un port fixe (le port du serveur). Cela laisse l'O/S pas libre dans le choix d'un port disponible pour faire la connexion FROM. Si un port est affecté au port (il a lié() et connected() au serveur), l'autre processus ne peut pas utiliser ce port.

S'il n'y a aucune raison impérieuse pour l'envoi de trafic d'un port spécifique, laissez le O/S trouver un port disponible en changeant cette ligne

client_address.sin_port = htons(SERVER_PORT); 

à

client_address.sin_port = 0; 
+0

C'est un bon conseil, mais je ne pense pas que ce soit le problème, parce que le 'bind()' échouerait (et l'OP a une vérification d'erreur sur cet appel). – caf

+0

Serait intéressant d'obtenir la valeur de SO_REUSEADDR. Si elle est définie sur true ("1"), bind() n'échouera pas. – haavee