2016-04-22 2 views
4

Je suis donc en train de jouer avec l'idée des ports et de la communication client/serveur.Communication d'E/S lire et écrire du programme client au serveur

J'ai un programme server.c qui peut ouvrir un port, ouvrir un descripteur d'écoute et, lors de la réception d'une connexion, un fork pour gérer la communication avec un client connecté. J'ai un programme client.c qui prend 5 arguments en ligne de commande. Fondamentalement, les 3 premiers arguments sont des chaînes de pratique à envoyer au serveur et le 4ème est nom d'hôte et le 5ème est le numéro de port. Jusqu'à présent, la connexion de ces deux a bien fonctionné, cependant, lorsque le client essaie d'écrire les 3 chaînes différentes (argv [1], argv [2], et argv [3]) sur server.c, server.c semble être seulement capable de lire le premier puis il semble être bloqué et ne pas continuer avec les lectures supplémentaires même si le client finira d'écrire toutes les chaînes dans le descripteur de fichier de communication. J'ai été bloqué pendant plus de 4 heures essayant de comprendre ce qui aurait dû être un programme d'entraînement simple pour mieux apprendre les serveurs et les clients. Je ne veux plus être perdu alors je le suis déjà, j'espère que quelqu'un pourrait me donner des conseils sur la façon de gérer ce problème ou ce que je fais de mal.

client.c

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <string.h> 
#include "uici.h" 
#include "func.h" 


int main(int argc, char *argv[]){ 
    int fd; 
    u_port_t portnum; 

    if(argc != 6){ 
    fprintf(stderr, "Usage: %s string1 string2 string3 host port\n",argv[0]); 
    return -1; 
    } 
    portnum = (u_port_t)atoi(argv[5]); 
    if((fd = u_connect(portnum, argv[4])) == -1){ 
    perror("Failled to establish connection"); 
    return 1; 
    } 
    fprintf(stderr, "[%ld]:connection made to %s\n", (long)getpid(), argv[4]); 
    if((write(fd, argv[3], strlen(argv[3])+1)) == -1){ 
    fprintf(stderr, "Failed to write %s to fd", argv[3]); 
    r_close(fd); 
    return 0; 
    } 
    if((write(fd, argv[1], strlen(argv[1])+1)) == -1){ 
    fprintf(stderr, "Failed to write %s to fd", argv[1]); 
    r_close(fd); 
    return 0; 
    } 
    if((write(fd, argv[2], strlen(argv[2])+1)) == -1){ 
    fprintf(stderr, "Failed to write %s to fd", argv[2]); 
    close(fd); 
    return 0; 
    } 
    fprintf(stderr, "Everything has been written\n"); 
    return 0; 
} 

server.c

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <limits.h> 
#include <sys/types.h> 
#include <sys/wait.h> 
#include "func.h" 
#include "uici.h" 

int main(int argc, char *argv[]) 
{ 
    u_port_t portnumber; 
    int listenfd; 
    int fd; 
    char client[MAX_CANON]; 
    int bytes_copied; 
    pid_t child; 

    if (argc != 2) { 
     fprintf(stderr, "Usage: %s port\n", argv[0]); 
     return 1; 
    } 

    portnumber = (u_port_t) atoi(argv[1]); 
    if ((listenfd = u_open(portnumber)) < 0) { 
     perror("Listen endpoint creation failed"); 
     return 1; 
    } 

    fprintf(stderr, "[%ld]: Waiting for the first connection on port %d\n", 
        (long)getpid(), (int)portnumber); 
    for (; ;) { 
     if ((fd = u_accept(listenfd, client, MAX_CANON)) != -1) { 
     fprintf(stderr, "[%ld]: A connection has been received from %s\n", 
       (long) getpid(), client); 
     if ((child = fork()) == -1) 
      perror("Could not fork a child"); 

     if (child == 0) {       /* child code */ 
      r_close(listenfd); 
      int MAXSZ = 1024; 
      char str3[MAXSZ]; 
      char str1[MAXSZ]; 
      char str2[MAXSZ]; 
      int bytesread = 0; 
      fprintf(stderr, "Beginning the reads\n"); 
      read(fd,str3, MAXSZ); 
      fprintf(stderr, "Finished 1st read\n"); 
      read(fd,str1, MAXSZ); 
      fprintf(stderr, "Finished 2nd read\n"); 
      read(fd,str2, MAXSZ); 
      fprintf(stderr, "str3: %s\n",str3); 
      fprintf(stderr, "str1 = %s\n",str1); 
      fprintf(stderr, "str2 = %s\n",str2); 
      close(fd); 
      return 0; 
     } else {         /* parent code */ 
      close(fd); 
      while (waitpid(-1, NULL, WNOHANG) > 0) ; /* clean up zombies */ 
     } 
     } 
     else 
     perror("Accept failed"); 
    } 
} 
+0

Problème secondaire: belle distribution de '(long) getpid()' avec 'fprintf (stderr," [% ld]: A ... ' – chux

+0

Idée: Plutôt que d'imprimer la chaîne, imprimez la longueur des données reçues avec 'fprintf (stderr," [% ld]: Une connexion a été reçue de% d \ n ", (long) getpid(), fd);' Serait-ce que toute la chaîne n'est pas reçue? ('client' vous n'avez pas de caractère nul?) – chux

+0

Vous avez du code pour écrire des messages délimités par zéro octet, mais vous n'avez pas de code pour * lire * les messages délimités par zéro octet Avez-vous oublié de l'écrire –

Répondre

0

Note: Il n'y a aucune garantie que read ou write va lire ou écrire toutes les données de/vers le descripteur de fichier, et pas garantir que les blocs de données que le client est en train d'écrire seront lus de la même manière sur le serveur.

Vous devez vous assurer de vérifier les octets écrits et continuer à écrire des données dans le fd jusqu'à ce que vous les ayez toutes écrites. Lors de la lecture, vous devez demander au client d'envoyer des données d'en-tête décrivant la quantité de données à attendre, ou dans votre cas, vous pouvez lire 1 octet à la fois et rechercher un caractère '\0', indiquant la fin de un string.

Étant donné que MAXSZ est probablement plus grand que les chaînes que vous envoyez, le serveur peut lire toutes les chaînes à la fois dans le premier tampon, puis bloquer la lecture suivante.

+0

L'utilisation de r_write est pour s'assurer qu'il écrit Existe-t-il un moyen d'utiliser quelque chose comme sondage de quoi que ce soit pour améliorer ce travail? Je ne sais pas grand-chose de cette fonction mais je me demandais si quelqu'un avait plus d'informations sur l'utilisation de ces outils – JGc

+0

Je ne pense pas r_write est une fonction POSIX standard, et je n'ai pas Je vois que vous en fournissez une implémentation. Je doute cependant que l'écriture soit le problème, car les petites écritures tendent à être envoyées non fragmentées. Vérifiez la lecture des octets de votre premier appel r_read, si ce nombre est supérieur à la longueur de votre première chaîne, vous pouvez être sûr qu'il lit plus que prévu.Il lit probablement les trois chaînes à la fois, et puisque printf ne s'imprime que jusqu'au premier caractère '\ 0', vous ne voyez que la première chaîne imprimée sur la console. – chrisd1100

+0

Merci, je vais essayer ça :) – JGc

0

premier enfant fourchue ferme l'auditeur avec r_close(listenfd);

Ensuite, lorsque le client envoie argv[1] aucun écouteur sont disponibles et, je pense, u_accept(listenfd, client, MAX_CANON) retourner une erreur à cause de listenfd n'est pas valide.

+0

J'ai essayé différents exemples avec un corps différent dans le serveur forked. Ceux-ci ne renvoient pas une erreur et fonctionnent bien, le problème est la lecture dans l'enfant forké et l'écriture dans le client – JGc