[C/C++] Non-Blocking Read

Dieses Thema im Forum "Programmierung & Entwicklung" wurde erstellt von Smokers, 27. Januar 2011 .

Schlagworte:
  1. 27. Januar 2011
    Non-Blocking Read

    Hallöchen,

    also ich habe folgendes Problem.
    Ich hatte eine Übung zum Thema pipes zu erledigen die ich durch :
    Spoiler
    client.c
    Code:
    #include <unistd.h>
    #include <stdio.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <signal.h>
    #include <stdlib.h>
    #include <errno.h>
    
    int checkPipe(char*);
    
    int main(int argc, char* argv[]) {
     int i=0;
     char tempname[100];
     mode_t mode;
     struct stat buf;
     int rc,fd;
     char input[100], data[100];
     
     printf("Client: Service was started....\n\n");
     for(i=1;i<=10;i++){
     char c_int[4];
     sprintf(c_int,"%i",i);
     
     strcpy(tempname,"pipe");
     strcat(tempname,c_int);
     
     printf("Client: Checking pipename: %s !\n",tempname);
     if(checkPipe(tempname) == 0){
     rc = stat (tempname, &buf);
     if (rc < 0) {
     if (errno != ENOENT) {
     perror("stat");
     exit (1);
     }
     mode = 0644;
     rc = mkfifo (tempname, mode);
     if (rc < 0) {
     perror("Client: Can't open pipe!\n");
     exit (-1);
     } 
     else {
     printf ("Client: Pipe %s wurde angelegt\n", tempname);
     }
     fd = open(tempname, O_WRONLY);
     printf("Client: Your input: ");
     while (fgets(input, sizeof(input), stdin) != NULL) {
     sprintf(data, "%s", input);
     printf("Client: Sending data: %s", data);
     write(fd, data, sizeof(data));
     printf("Client: Your input: ");
     }
     close(fd);
     printf("\nPipe %s was closed!\n", tempname);
     
     exit(0);
     }
     }
     }
     printf("Client: No free pipename was found!\n");
     
    }
    int checkPipe(char* pipeName){
     mode_t mode;
     int rc;
     struct stat buf;
     rc = stat (pipeName, &buf);
     if (rc < 0) {
     if (errno != ENOENT) {
     perror("Client: Struct-Object can't be created!\n");
     exit (-1);
     }
     return 0;
     } 
     else {
     return 1;
     }
    }
    
    server.c
    Code:
    #include <unistd.h>
    #include <stdio.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <signal.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <unistd.h>
    #include <stdio.h>
    
    
    int checkPipe(char*);
    void child(int i);
    void handleSIGTSTP();
    void handleSIGCHLD();
    
    int field[] = {2,0,0,0,0,0,0,0,0,0,0};
    
    int main(int argc, char* argv[]) { 
     sigset(SIGTSTP, handleSIGTSTP);
     sigset(SIGCHLD,handleSIGCHLD);
     int i=0;
     char tempname[100];
     pid_t pid[10];
     
     printf("Master: Service was started....\n\n");
    
     while(1){
     //printf("Master: Checking possible pipenames (max 10 pipes).\n");
     for(i=1;i<=10;i++){
     char c_int[4];
     sprintf(c_int,"%i",i);
     
     strcpy(tempname,"pipe");
     strcat(tempname,c_int);
     //printf("Master: Checking pipename: %s !\n",tempname);
     
     if(checkPipe(tempname) == 1 && field[i] == 0){
     //printf("Master: Starting child to handle pipe: %s!\n",tempname);
     field[i]=1;
     pid[i] = fork();
     switch(pid[i]){
     case 0 : child(i);
     exit(0);
     case -1 : perror("Can't create child.\n");
     exit(-1);
     default : break;
     }
     }
     }
     }
    }
    void child(int pipenr){
     char pipename[255];
     char input[100];
     int fd;
     
     char c_int[4];
     sprintf(c_int,"%i",pipenr);
     strcpy(pipename,"pipe");
     strcat(pipename,c_int);
     
     fd = open(pipename, O_RDONLY);
     
     printf("\tSERVER%i: Waiting for incoming messages on pipe: %s\n",pipenr,pipename);
     while ((read(fd, input, sizeof(input)) > 0)) {
     input[strlen(input)-1] = '\0';
     printf("\tSERVER%i: Recieved '%s' from pipe : %s\n",pipenr, input,pipename);
     }
     close(fd);
     unlink(pipename);
     printf("\tSERVER%i: Stopping service on pipe: %s\n",pipenr,pipename);
     return;
    }
    int checkPipe(char* pipeName){
     mode_t mode;
     int rc;
     struct stat buf;
     rc = stat (pipeName, &buf);
     if (rc < 0) {
     if (errno != ENOENT) {
     perror("Stat Obj konnte nicht erzeugt werden");
     exit (-1);
     }
     return 0;
     } 
     else {
     return 1;
     }
    }
    void handleSIGTSTP(){
     printf("\nMaster: Service was stopped....\n");
     exit(0);
     return;
    }
    void checkAll(){
     int i;
     for(i=1;i<=10;i++){
     if(field[i]==1){
     char tempname[100];
     char c_int[4];
     sprintf(c_int,"%i",i);
     strcpy(tempname,"pipe");
     strcat(tempname,c_int);
     if(checkPipe(tempname) == 0){
     field[i] = 0;
     break;
     }
     }
     }
     sleep(1);
    }
    void handleSIGCHLD(){
     checkAll();
     return;
    }
    
    
    löste. (Einfache Anwendung : Server checkt genreisch pipes ab und stellt möglichen Inhalt dar (dazu sind unterprozesse zu erzeugen) Clients erzeugen pipe, schreiben in die pipe und löschen diese nach Beendigung)

    In der nächsten Übung soll das Programm lediglich umgeschrieben werden.
    Es sollen hierzu statt Unterprozesse im Server zu erzeugen, ein NON-Blocking Read verwendet werden.


    Meine Idee war folgende (client bleibt gleich):

    Code:
    #include <unistd.h>
    #include <stdio.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <signal.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <unistd.h>
    #include <stdio.h>
    
    
    int checkPipe(char*);
    void handleSIGTSTP();
    void checkAll();
    
    int field[] = {2,0,0,0,0,0,0,0,0,0,0};
    int fd[11];
    
    int main(int argc, char* argv[]) { 
     sigset(SIGTSTP, handleSIGTSTP);
     int i=0,flags,test;
     char tempname[100];
     pid_t pid[10];
     char input[100];
     
     printf("Master: Service was started....\n\n");
    
     while(1){
     checkAll();
     //printf("Master: Checking possible pipenames (max 10 pipes).\n");
     for(i=1;i<=10;i++){
     char c_int[4];
     sprintf(c_int,"%i",i);
     
     strcpy(tempname,"pipe");
     strcat(tempname,c_int);
     //printf("Master: Checking pipename: %s !\n",tempname);
     
     if(checkPipe(tempname) == 1 && field[i] == 0){
     //printf("Master: Starting to handle pipe: %s!\n",tempname);
     //printf("\tSERVER%i: Creating fd for pipe %s",i,tempname);
     fd[i] = open(tempname, O_RDONLY);
     flags = fcntl(fd[i], F_GETFL); 
     flags = flags | O_NONBLOCK; 
     fcntl(fd[i], F_SETFL, flags);
     field[i]=1;
     }
     if(field[i] == 1){ 
     //printf("\tSERVER%i: Reading fof pipe %s",i,tempname);
     test = read(fd[i], input, sizeof(input));
     //printf("Master: read>0!\n");
     if(test>0){
     input[strlen(input)-1] = '\0';
     printf("\tSERVER%i: Recieved '%s' from pipe : %s\n",i, input,tempname);
     }
     }
     }
     }
    }
    int checkPipe(char* pipeName){
     mode_t mode;
     int rc;
     struct stat buf;
     rc = stat (pipeName, &buf);
     if (rc < 0) {
     if (errno != ENOENT) {
     perror("Stat Obj konnte nicht erzeugt werden");
     exit (-1);
     }
     return 0;
     } 
     else {
     return 1;
     }
    }
    void handleSIGTSTP(){
     printf("\nMaster: Service was stopped....\n");
     int i;
     for(i=1;i<=10;i++){
     close(fd[i]);
     }
     exit(0);
     return;
    }
    void checkAll(){
     int i;
     for(i=1;i<=10;i++){
     if(field[i]==1){
     char tempname[100];
     char c_int[4];
     sprintf(c_int,"%i",i);
     strcpy(tempname,"pipe");
     strcat(tempname,c_int);
     if(checkPipe(tempname) == 0){
     field[i] = 0;
     close(fd[i]);
     break;
     }
     }
     }
     sleep(1);
    }
    
    Ich weiß das das gemurkse ist, nur es muss leider ehrlich gesagt zügig sein und ich hab noch andere Prüfungen nebenher zu erledigen ^^°

    Mein einziges Problem ist, das die Pipes nicht mehr gelöscht werden.Dadurch spackt das Programm auch nach einem Neustart dann ab.
    Beim vorherigen Programm ging das Reibungslos, nun irgendwie nicht mehr.

    Dadurch werden immer höher indexiertere Pipes erstellt, aber keine mehr "freigegeben".
    Jemand eine Idee?^^°

    Ich weiß ist vllt ein wenig viel verlangt den Code durchzusehen :-/


    lg
     
  2. 27. Januar 2011
    AW: Non-Blocking Read

    Denke mal, dass select() dir weiterhelfen könnte:
    select(2): synchronous I/O multiplexing - Linux man page

    Habe mich neulich mit Sockets beschäftigt und da kann man select nutzen, damit man auf Lesen und Schreiben auf dem Socket reagieren kann ohne, dass man nach nem festen Schema (erst lesen dann schreiben usw.) vorgehen muss..

    PHP:
    fd_set fds ;
    Erstellt einen neuen File-Descriptor-Set
    PHP:
    FD_ZERO (& fds );
    Leert diesen (Zur Sicherheit, damit kein Müll drin steht)
    PHP:
    FD_SET ( s , & fds );
    Schmeißt einen File-Descriptor in das Set (in meinem Fall den Socket s)
    PHP:
    FD_ISSET ( s , & fds )
    Damit guckst du, ob das File-Descriptor schon im Set ist

    Rest steht im Manual noch drin...
    Hier mal nen Beispiel Code für nen Server...
    Davon hab ich mir auch was zum Lernen abgeguckt..
    Spoiler
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <winsock2.h>
    #include <sys/time.h>
    #include <sys/types.h>
    #include <sys/fcntl.h>
    
    struct list_entry {
     int sock;
     struct list_entry *next;
    };
    
    struct list_type {
     struct list_entry *data;
     unsigned count;
    };
    
    #define BUF_SIZ 4096
    #define PORT 33
    
    void init_list(struct list_type *list)
    {
     list->data = NULL;
     list->count = 0;
    }
    
    int add_client(struct list_type *list, int sock)
    {
     struct list_entry *n;
    
     n = (struct list_entry*)malloc(sizeof(*n));
     if (!n)
     {
     perror("malloc() failed");
     return 1;
     }
    
     n->sock = sock;
     n -> next = list->data;
    
     list->data = n;
     list->count++;
     printf("Client added on Socket %d\n", sock);
     return 0;
    }
    
    int remove_client(struct list_type *list, int sock)
    {
     struct list_entry *lz, *lst = NULL;
    
     if (!list->count)
     return 1;
    
     for (lz = list->data; lz; lz = lz->next)
     {
     if (lz->sock == sock)
     break;
     lst = lz;
     }
    
     if (!lz)
     return 1;
    
     if (lst)
     lst->next = lz->next;
     else
     list->data = lz->next;
    
     free(lz);
     list->count--;
    
     return 0;
    }
    
    int fill_set(fd_set *fds, struct list_type *list)
    {
     int max = 0;
     struct list_entry *lz;
    
     for (lz = list->data; lz; lz = lz->next)
     {
     if (lz->sock > max)
     max = lz->sock;
     FD_SET(lz->sock, fds);
     }
    
     return max;
    }
    
    int get_sender(fd_set *fds)
    {
     int i = 0;
    
     while(!FD_ISSET(i, fds))
     i++;
    
     return i;
    }
    
    int send_all(char *msg, int len, struct list_type *list, int sender)
    {
     struct list_entry *lz;
    
     for (lz = list->data; lz; lz = lz->next)
     {
     /* if (lz->sock == sender)
     continue;*/
     int size = strlen(msg);
     send(lz->sock, msg, strlen(msg), 0);
     }
    
     return 0;
    }
    
    int main_loop(int s)
    {
     int c, max, sender, bytes;
     fd_set fds;
     struct list_type list;
     char buf[BUF_SIZ];
     char buffer2[BUF_SIZ];
    
     init_list(&list);
     //add_client(&list, STDIN_FILENO); UNIX ONLY
    
     for(;;)
     {
     FD_ZERO(&fds);
     max = fill_set(&fds, &list);
    
     FD_SET(s, &fds);
     if (s > max)
     max = s;
    
     select(max + 1, &fds, NULL, NULL, NULL);
    
     if (FD_ISSET(s, &fds))
     {
     c = accept(s, NULL, 0);
     add_client(&list, c);
     }
     else
     {
     sender = get_sender(&fds);
     sender = c;
     bytes = recv(sender, buf, sizeof(buf), 0);
     buf[bytes] = '\0';
     printf("Received: %s", buf);
     if (bytes == 0)
     remove_client(&list, sender);
     else
     send_all(buf, bytes, &list, sender);
     }
     }
    }
    
    int main(void)
    {
     int s;
     struct sockaddr_in addr;
    
     WSADATA wsa;
     if (WSAStartup(MAKEWORD(1, 1), &wsa))
     {
     printf("WSAStartup() failed, %lu\n", (unsigned long)GetLastError());
     return EXIT_FAILURE;
     }
    
     s = socket(PF_INET, SOCK_STREAM, 0);
     if (s == -1)
     {
     perror("socket() failed");
     return 1;
     }
    
     addr.sin_addr.s_addr = INADDR_ANY;
     addr.sin_port = htons(PORT);
     addr.sin_family = AF_INET;
    
     if (bind(s, (struct sockaddr*)&addr, sizeof(addr)) == -1)
     {
     perror("bind() failed");
     return 2;
     }
    
     if (listen(s, 3) == -1)
     {
     perror("listen() failed");
     return 3;
     }
    
     return main_loop(s);
    }
    

    Ist zwar keine direkte Lösung für dein Problem, aber evtl behebt das dein Problem..
    Und ist denke ich nen wenig eleganter, als deine Checkpipe-Funktion und deine Schleife..
    Weil damit kannst du wesentlich mehr Pipes gleichzeit haben als nur 10..

    MfG
     
  3. Video Script

    Videos zum Themenbereich

    * gefundene Videos auf YouTube, anhand der Überschrift.