2009-09-18 6 views
1

J'ai un petit programme qui envoie et reçoit des données du serveur et du client et vice-versa. Tout fonctionne bien, mais je ne peux pas voir les messages reçus des deux côtés et il est toujours 0 octets. Il ne donne aucune erreur de compilation mais ne fonctionne pas comme je le voulais. Pouvez-vous regarder s'il vous plaît, où je me trompe? Merciprogramme client-serveur, problème d'envoi du message du client au serveur et inversement en utilisant TCP

// client

#include <stdio.h> 
#include <unistd.h> 
#include <stdlib.h> 
#include <string.h> 
#include <time.h> 
#include <errno.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netdb.h> 
#include <arpa/inet.h> 

int main(int argc, char* argv[]) 
{ 
    int sockfd; 

    struct addrinfo hints, *servinfo, *p; 
    int rv; 
    int numbytes; 
    char* hostname = "localhost"; 
    char* server = "localhost"; 

    memset(&hints, 0, sizeof(hints)); 
    hints.ai_family = AF_INET; 
    hints.ai_socktype = SOCK_STREAM; 
    if ((rv = getaddrinfo(hostname, "5000", &hints, &servinfo)) != 0) 
    { 
     fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); 
     return 0; 
    } 


    // loop through all the results and make a socket 
    for(p = servinfo; p != NULL; p = p->ai_next) 
    { 
     if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) 
     { 
      perror("client: socket"); 
      continue; 
     } 

     if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) 
     { 
      close(sockfd); 
      perror("client: connect"); 
      continue; 
     } 
     break; 
    } 
    if (p == NULL) 
    { 
     fprintf(stderr, "client: failed to bind socket\n"); 
     return 2; 
    } 

    char message[] = "hi"; 
    if ((numbytes = send(sockfd, message, 2, 0)) == -1) 
    { 
     perror("client: send"); 
     exit(1); 
    } 

    int numbytesRecv; 
    char buf[100]; 
    if ((numbytesRecv = recv(sockfd, buf, 99, 0)) == -1) 
    { 
     perror("client: recv"); 
     exit(1); 
    } 

    freeaddrinfo(servinfo); 
    printf("client: sent %d bytes to %s\n", numbytes, server); 
    printf("client: received %d bytes from %s\n", numbytesRecv, server); 
    buf[numbytesRecv] = '\0'; 
    printf("client: message received is %s\n",buf); 
    close(sockfd); 
    return 0; 
} 

// serveur

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <errno.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <arpa/inet.h> 
#include <netdb.h> 
#define MYPORT "5000"  // the port users will be connecting to 
#define MAXBUFLEN 100 
// get sockaddr, IPv4 or IPv6: 
void *get_in_addr(struct sockaddr *sa) 
{ 
    if (sa->sa_family == AF_INET) { 
      return &(((struct sockaddr_in*)sa)->sin_addr); 
    } 
    return &(((struct sockaddr_in6*)sa)->sin6_addr); 
} 
int main(void) 
{ 
    int sockfdTCP; 
    struct addrinfo hintsTCP, *servinfoTCP, *pTCP; 
    int rv; 
    int numbytes; 
    struct sockaddr_storage their_addr; 
    char buf[MAXBUFLEN]; 

    size_t addr_len; 
    char s[INET6_ADDRSTRLEN]; 

    memset(&hintsTCP, 0, sizeof hintsTCP); 
    hintsTCP.ai_family = AF_UNSPEC; 
    hintsTCP.ai_socktype = SOCK_STREAM; 
    hintsTCP.ai_flags = AI_PASSIVE; 

    if ((rv = getaddrinfo(NULL, MYPORT, &hintsTCP, &servinfoTCP)) != 0) { 
     fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); 
     return 1; 
    } 

    // loop through all the results and bind to the first we can for TCP socket 
    for(pTCP = servinfoTCP; pTCP != NULL; pTCP = pTCP->ai_next) 
    { 
     if ((sockfdTCP = socket(pTCP->ai_family, pTCP->ai_socktype,pTCP->ai_protocol)) == -1) 
     { 
      perror("listener: socket"); 
      continue; 
     } 

     if (bind(sockfdTCP, pTCP->ai_addr, pTCP->ai_addrlen) == -1) 
     { 
      close(sockfdTCP); 
      perror("listener: bind"); 
      continue; 
     } 
     break; 
    } 

    if (pTCP == NULL) 
    { 
     fprintf(stderr, "listener: failed to bind socket\n"); 
     return 2; 
    } 
    freeaddrinfo(servinfoTCP); 

    printf("listener: waiting to recvfrom...\n"); 
    addr_len = sizeof their_addr; 

    const int BACKLOG = 10; 
    if (listen(sockfdTCP, BACKLOG) == -1) { 
     perror("listen"); 
     exit(1); 
    } 

    socklen_t sin_size; 
    int new_fd; 
    sin_size = sizeof their_addr; 
    new_fd = accept(sockfdTCP, (struct sockaddr *)&their_addr, &sin_size); 
    printf("I am here\n"); 
    if (new_fd == -1) 
    { 
     perror("accept"); 
    } 

    if ((numbytes = recv(new_fd, buf, MAXBUFLEN, 0) == -1)) 
{ 
    perror("recv"); 
    exit(1); 
} 

char* msg = " hi i am server"; 
int numbytesSend; 
if ((numbytesSend = send(new_fd, msg,strlen(msg), 0) == -1)) 
{ 
    perror("recv"); 
    exit(1); 
} 

inet_ntop(their_addr.ss_family,get_in_addr((struct sockaddr *)&their_addr), s, sizeof s); 
printf("server: got connection from %s\n", s); 

printf("listener: packet is %d bytes long\n", numbytes); 
buf[numbytes] = '\0'; 
printf("listener: packet contains : %s\n", buf); 

close(sockfdTCP); 
close(new_fd); 
return 0; 

}

// client de sortie

./clientTCP 
client: sent 2 bytes to localhost 
client: received 0 bytes from localhost 
client: message received is 

// serveur de sortie

./serverTCP 
listener: waiting to recvfrom... 
I am here 
server: got connection from 127.0.0.1 
listener: packet is 0 bytes long 
listener: packet contains : 

Répondre

7

Votre problème est cette ligne dans le serveur:

if ((numbytes = recv(new_fd, buf, MAXBUFLEN, 0) == -1)) 

Il devrait être:

if ((numbytes = recv(new_fd, buf, MAXBUFLEN, 0)) == -1) 

Cela permettra numbytes d'être correctement affectés, ce qui permet

buf[numbytes] = '\0'; 

à faites ce que vous voulez et laissez

printf("listener: packet contains : %s\n", buf); 

imprimez ce que vous voulez.

deal Même avec

if ((numbytesSend = send(new_fd, msg, strlen(msg), 0) == -1)) 

mais le bug ne se manifeste pas dans le programme exemple.

+0

+1 - bonne prise –

+0

+1 - En effet une belle prise. – Void

2

Il a été un moment que je l'ai fait la programmation des prises brutes, mais je pense qu'il ya quelque chose de louche avec vos recv() appels. IIRC, recv() jusqu'à ce qu'il lise la taille maximale du tampon ou que la connexion soit fermée. Comme aucune extrémité n'envoie suffisamment de données pour remplir le tampon, et que le socket ne se ferme qu'après les appels recv(), je pense que l'un de vos clients/serveurs devrait se bloquer. Comme ils ne le font pas, l'une des deux choses se passe. Soit les sockets sont configurés pour le mode non-bloquant et vous devez les configurer pour bloquer, ou quelque chose ferme le socket. Je suis désolé je ne peux pas offrir une aide plus détaillée que cela, mais j'espère que cela vous dirigera dans la bonne direction. Vous pouvez également rechercher l'appel shutdown() à utiliser sur les sockets afin de ne pas les fermer avant que toutes les données du tampon ne soient envoyées. Je ne sais pas si cela a quelque chose à voir avec votre problème.

+0

recv() peut retourner avant de lire la taille complète du tampon, c'est-à-dire qu'il se produit une lecture courte. Cependant, les valeurs de retour de zéro impliquent que le socket a été arrêté. C'est un peu étrange. Je suis d'accord qu'un blocage aurait dû se produire. – Void

2

EDIT: Je viens de tester sur OS X. Votre code fonctionne pour moi. Maintenant, je pense vraiment que vous devez avoir quelque chose qui consomme vos octets. Tuez vos processus et faites:

$ netstat -na | grep 5000

Pour voir si vous avez quelque chose à l'écoute sur le port 5000. Si oui, vous devez tuer le serveur.

Aussi, assurez-vous que le super serveur (inetd/xinetd) n'est pas quelque chose de fraie pour traiter les données sur le port 5000.

1

On dirait que vous être mordu par Nagle's Algorithm. Essayez de définir TCP_NODELAY pour autoriser l'envoi immédiat de petits paquets.

Notez que pour le code de production, vous devez profiler avant de décider de désactiver l'algorithme Nagle.

+0

Lorsque j'essaie de compiler en utilisant votre suggestion, j'obtiens cette erreur de compilation, serverTCP.c: Dans la fonction 'main': serverTCP.c: 53: erreur: 'TCP_NODELAY' non déclaré (première utilisation dans cette fonction) serverTCP. c: 53: erreur: (Chaque identifiant non déclaré est signalé une seule fois serverTCP.c: 53: erreur: pour chaque fonction dans laquelle il apparaît.) Dois-je utiliser des bibliothèques supplémentaires autres que lsocket. –

+0

@ seg.server.fault: Vous devez inclure , comme décrit ici: http://www.opengroup.org/onlinepubs/000095399/basedefs/netinet/tcp.h.html HTH ! – Void

Questions connexes