2016-04-22 20 views
4

So spiele ich mit der Idee von Ports und Client/Server-Kommunikation.E/A-Kommunikation Lesen und Schreiben von Client zu Server Programm

Ich habe ein server.c-Programm, das einen Port öffnen kann, einen Abhördeskriptor öffnen und beim Empfangen einer Verbindung ein Kind austeilen, um die Kommunikation mit einem verbindenden Client zu verwalten. Ich habe ein Programm client.c, das 5 Befehlszeilenargumente akzeptiert. Grundsätzlich sind die ersten drei Argumente Übungs-Strings, die an den Server gesendet werden, und der vierte ist der Host-Name und der fünfte ist die Port-Nummer.

Bis jetzt funktioniert die Verbindung dieser beiden jedoch einwandfrei, wenn der Client versucht, die 3 verschiedenen Strings (argv [1], argv [2] und argv [3]) auf server.c, server.c zu schreiben scheint nur in der Lage zu sein, den ersten zu lesen, dann scheint es zu hängen und nicht mit den zusätzlichen Lesevorgängen fortzufahren, obwohl der Client das Schreiben aller Zeichenfolgen in den Kommunikationsdateideskriptor beendet. Ich bin seit über 4 Stunden festgefahren, um herauszufinden, was ein einfaches Übungsprogramm hätte sein sollen, um Server und Clients besser zu lernen. Ich will nicht mehr verloren gehen, dann bin ich schon, also hoffe ich, dass jemand mir irgendeinen Rat geben kann, wie ich mit diesem Thema umgehen soll oder was ich falsch mache.

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

Side-Problem: schöne Besetzung von '(lang) getpid()' mit 'fprintf (stderr," [% ld]: A ... ' – chux

+0

Idee: Drucken Sie die Zeichenfolge der Länge der empfangenen Daten mit 'fprintf (stderr," [% ld]: Eine Verbindung wurde von% d \ n empfangen ", (lang) getpid(), fd);' Könnte es sein, dass nicht die ganze Zeichenfolge empfangen wird? ('client' fehlt ein Null-Zeichen?) – chux

+0

Sie haben Code, um Nachrichten durch Null Bytes zu schreiben. Aber Sie haben keinen Code zu * lesen * Nachrichten durch Nullbytes. Haben Sie vergessen, es zu schreiben? –

Antwort

0

Hinweis: Es gibt keine Garantie dafür, dass read oder write werden alle Daten vom/zum Dateideskriptors lesen oder schreiben, und keine garantieren, dass die Datenblöcke, die der Client schreibt, auf die gleiche Weise auf dem Server gelesen werden.

Sie müssen sicherstellen, dass die geschriebenen Bytes überprüft werden und weiterhin Daten in das fd schreiben, bis Sie alle geschrieben haben. Beim Lesen muss der Client eine Art Kopfdaten senden, die die zu erwartende Datenmenge beschreiben, oder in Ihrem Fall könnten Sie 1 Byte gleichzeitig lesen und nach einem '\0' Zeichen suchen, das das Ende von anzeigt ein Faden.

Da MAXSZ wahrscheinlich größer ist als die Zeichenfolgen, die Sie senden, könnte der Server alle Zeichenfolgen gleichzeitig in den ersten Puffer lesen und dann beim nachfolgenden Lesen blockieren.

+0

Mit r_write ist sicherzustellen, dass es schreiben alle Bytes.Es gibt eine Möglichkeit, etwas wie Umfrage von irgendetwas zu verwenden, um diese Arbeit besser zu machen? Ich weiß nicht viel über diese Funktion, aber ich fragte mich, ob jemand mehr Informationen über die Verwendung dieser Tools hatte – JGc

+0

Ich glaube nicht r_write ist eine POSIX-Standardfunktion, und ich habe nicht Ich sehe, Sie stellen eine Implementierung davon zur Verfügung. Ich bezweifle jedoch, dass das Schreiben das Problem ist, da kleine Schreibvorgänge unfragmentiert gesendet werden. Überprüfen Sie die Bytes, die von Ihrem ersten r_read-Aufruf gelesen wurden. Wenn diese Zahl größer als die Länge Ihrer ersten Zeichenfolge ist, können Sie sicher sein, dass sie mehr als erwartet liest.Wahrscheinlich werden alle drei Zeichenfolgen gleichzeitig gelesen, und da printf nur bis zum ersten Zeichen "\ 0" gedruckt wird, wird nur die erste Zeichenfolge auf der Konsole angezeigt. – chrisd1100

+0

Danke ich werde das versuchen :) – JGc

0

Erstes Kind schließt den Hörer gegabelt mit r_close(listenfd);

dann, wenn der Client argv[1] keine Hörer verfügbar sind senden und, glaube ich, u_accept(listenfd, client, MAX_CANON) einen Fehler zurück, weil der listenfd ist nicht gültig.

+0

Ich habe verschiedene Beispiele mit nur einem anderen Körper im gegabelten Server ausprobiert. Diese geben keinen Fehler zurück und funktionieren gut, das Problem ist das Lesen in dem untergeordneten Kind und die Schreibvorgänge in dem Client – JGc