2015-04-21 4 views
0

Je suis en train d'écrire un protocole de couche d'application simple en utilisant tcp et je rencontre un problème. Je veux faire la fragmentation dans l'envoi de message parce que les messages sont si longs. Mais je ne peux pas synchroniser le processus et le client lit le tampon vide avant que le serveur n'écrive les données. Les messages sont d'environ 4mb. Comment puis-je écrire ces méthodes?Unix Socket envoyer/recevoir des messages longs

Pour le client

void send_message(string message); 

string receive_message() 

Pour le serveur

void send_message(int sock,string message) 

string receive_message(int sock) 

Mes fonctions sont inférieures

void send_fragment(char* buffer,int length){ 

    int n = write(sockfd, buffer, length); 

    if (n < 0) 
    { 
     perror("ERROR writing to socket"); 
     exit(1); 
    } 

} 

string receive_fragment(){ 
    char buffer[FRAGMENT_LENGTH]; 
    bzero(buffer,FRAGMENT_LENGTH); 

    int n = read(sockfd, buffer, FRAGMENT_LENGTH-1); 

    if (n < 0) 
    { 
     perror("ERROR reading from socket"); 
     exit(1); 
    } 

    return string(buffer); 

} 

void send_message(string message){ 

    char buffer[FRAGMENT_LENGTH]; 
    bzero(buffer,FRAGMENT_LENGTH); 

    int message_length = message.length(); 

    //computes the number of fragment 
    int number_of_fragment = ceil((double)message_length/FRAGMENT_LENGTH); 

    sprintf(buffer,"%d",number_of_fragment); 

    //sends the number of fragment 
    send_fragment(buffer,strlen(buffer)); 

    for(int i=0;i<number_of_fragment;++i){ 

     bzero(buffer,FRAGMENT_LENGTH); 

     //fragment interval 
     int start = i*FRAGMENT_LENGTH; 
     int end = (i+1)*FRAGMENT_LENGTH; 

     if(i==number_of_fragment-1){ 
      end = min(end,message_length); 
     } 


     //creates a fragment 
     const char* fragment = message.substr(start,end).c_str(); 

     sprintf(buffer,"%s",fragment); 

     //sends the fragment 
     send_fragment(buffer,strlen(buffer)); 
    } 

} 

string receive_message(){ 

    //receive and computes the number of fragment 
    string number_of_fragment_string = receive_fragment(); 
    int number_of_fragment = atoi(number_of_fragment_string.c_str()); 


    string message =""; 
    for(int i=0;i<number_of_fragment;++i){ 

     //concatenating fragments 
     message += receive_fragment(); 

    } 

    return message; 

} 
+0

Qu'avez-vous essayé? Qu'est-ce qui vous a causé des problèmes? Avez-vous regardé appel 'select'? – Eregrith

+0

no. comment puis-je utiliser? J'ai ajouté les codes ci-dessus. –

+0

Après y avoir réfléchi, 'select' n'est nécessaire que lorsque vous avez plusieurs connexions à différents clients. Vous n'en avez pas besoin pour un simple modèle d'envoi/réception – Eregrith

Répondre

2

Vous devez implémenter le cadrage dans votre propre code. TCP est un "flux" qui signifie qu'il envoie juste des octets sans aucune sorte d'indication de début/fin. (UDP est basé sur les paquets, mais ne convient pas aux paquets de votre taille.)

La méthode la plus simple consisterait à écrire une longueur de 4 octets dans le socket et de demander au destinataire de lire ces octets, sachant que endianess pose problème (utilisez htonl() et ntohl() pour convertir les représentations locales en "ordre de réseau").

Ensuite, lisez ce nombre d'octets. Lorsque cela est fait, vous avez reçu votre message.

Si vous utilisez des lectures bloquantes, ce sera assez simple - si vous obtenez moins, la connexion est rompue. Si vous utilisez des lectures non bloquantes, vous devez assembler les pièces que vous obtenez (vous pouvez même obtenir la longueur en morceaux, bien que peu probable) à chaque appel en lecture.

Il existe d'autres façons de cadrer vos données, mais c'est la plus simple.

-2

1) Créer send_message() et receive_message() en utilisant send() et recv().

2) Sélectionnez les drapeaux appropriés dans recv() Lisez la page de manuel recv() pour les drapeaux. http://linux.die.net/man/2/recv.

3) Utilisez un délimiteur au début et à la fin du message transmis à chaque fois pour marquer le début et la fin afin que la vérification puisse être effectuée du côté du récepteur.

+0

TCP n'est pas basé sur un message. Il n'y a pas moyen d'attendre ça. –

+0

Définir des drapeaux appropriés tels que quoi? – EJP

+0

La réponse originale dit "comme' MSG_WAITALL' ". –

0

Vous ignorez le nombre renvoyé par recv(). Au lieu de construire une chaîne avec le tampon entier, construisez-le à partir de seulement autant d'octets du tampon.

+0

Je l'ai eu. Je suis un développeur Java et c est un peu difficile pour moi :) –

+0

Il n'a rien à voir avec C. Le même problème se pose également en Java. – EJP