Thread: I need help for socket reading using multithreaded pipes

  1. #1
    Registered User
    Join Date
    Oct 2016
    Posts
    3

    Question I need help for socket reading using multithreaded pipes

    Hello all,

    after searching for documentation and tutorials along the web (including this forum) I was not able to find a solution to an issue I am having with a linux server.

    The idea is to have a server which will handle sockets using multithreading processes.

    The child will handle socket connection and later the data should be sent to the parent process.

    For some reason, it's only handling 1 client.

    I want the parent process to handle data so the "kid" should be able to manage connections.
    Once the data is being handled, the parent will send away the data directly to client and not through child process.

    Here I have a basic scheme:

    incoming data:
    CLIENT --><SOCKET>-->CHILD PROCESS--><PIPE>-->PARENT PROCESS
    outgoing data:
    PARENT PROCESS --> <SOCKET> --> CLIENT

    So far I got this code:
    Code:
    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h> 
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <sys/msg.h>
    #include <wait.h>
    
    
    // Max number of clients
    int max_cli=5;
    
    
    // Future menu options
    char *opt;
    
    
    // Error messages
    void error(const char *msg){
        perror(msg);
        exit(-1);
    }
    
    
    // --------> Multithreading
        /* ChildProcess */
        pid_t idProcess;
        /* Returned balue by ChildProcess */
        int childStatus;
    
    
    // --------> PIPES code
    
    
    //
    // Structure for messages that are going to be sent/received. They must
    // have "long" field to have an identifier of message.
    // Following fields are information to be transmitted in the message.
    // Later once we type cast the value (struct msgbuf *), all the fields will be seen as an unique (char *)
    //
    typedef struct
    {
        long Id_Message;
        char Message[1024];
    } A_Message_Type;
    
    
        key_t Key1;
        int Id_Message_Queue;
        A_Message_Type A_Message;
    
    
    void SonTasks(int); /* function prototype */
    void ParentTasks(); /* function prototype */
    
    
        /* Before calling fork(), we create the pipe with 2 descriptors, 
         * for I/O purposes */
        /* We will set values: 0->IN 1->OUT */
        int pipeDescriptor[2];    
        /* This will be our buffer to write in the PIPE */
        char buffer[1024];
    
    
    // --------> Main
    int main(int argc, char *argv[]){ 
        printf("Loading server...\n\n");
    
    
    //********************* SOCKETS
         int sockfd, newsockfd, portno, pid;
         socklen_t clilen;
         struct sockaddr_in serv_addr, cli_addr;
    
    
         if (argc < 2) {
             error("ERROR, no port provided");
         }
    
    
         sockfd = socket(AF_INET, SOCK_STREAM, 0);
         if (sockfd < 0) 
            error("ERROR opening socket");
         bzero((char *) &serv_addr, sizeof(serv_addr));
         portno = atoi(argv[1]);
         serv_addr.sin_family = AF_INET;
         serv_addr.sin_addr.s_addr = INADDR_ANY;
         serv_addr.sin_port = htons(portno);
         if (bind(sockfd, (struct sockaddr *) &serv_addr,
                  sizeof(serv_addr)) < 0) 
                  error("ERROR on binding");
         listen(sockfd,max_cli);
         clilen = sizeof(cli_addr);
    //*****************************
     
        //
        // As in other shared resource (Shared memory, Semaphor 
        //  or queues) we get a key from an exiting file 
        //  and an integer number. All the processes who want to share this
        //  semaph. should use same file and same integer number.
        //
        printf("Creating key for queues... ");
        Key1 = ftok ("/bin/ls", 33);
        if (Key1 == (key_t)-1){
            error("Error");
        }
        printf("[OK]\n");
    
    
        //
        //    We create a queue for messages.
        //
        printf("Getting identifier for queues... ");
        Id_Message_Queue = msgget (Key1, 0600 | IPC_CREAT);
        if (Id_Message_Queue == -1){
            error("Error");
        }
        printf("[OK]\n");
    
    
        if (pipe (pipeDescriptor) == -1){
            error("Error");
        }
    
    
        while(opt!="shutdown"){
             newsockfd = accept(sockfd, 
                   (struct sockaddr *) &cli_addr, &clilen);
             if (newsockfd < 0) 
                 printf("ERROR on accept\n"); // Even if we find an error the server must not stop
    
    
            idProcess = fork();
    
    
            switch (idProcess){ 
                case -1: 
                error("Failed to create process");
                break;
                case 0: 
                //close(sockfd);
                SonTasks(newsockfd);
    
    
                break;
                default:
                //close(newsockfd);
                ParentTasks();
                break;
            }
        }
    
    
        close(sockfd);
        return 0; /* We will never reach this point */
    }
    
    
    /******** SonTasks() *********************
     There is a separate instance of this function 
     for each connection.  It handles all communication
     once a connnection has been established.
     *****************************************/
    void SonTasks(int sock){
       char BufferChild[1024];
    
    
    // ****** SOCKETS
       int n;      
    // **************
    while(1){
        // ************ SOCKETS
           bzero(BufferChild,1024);
           n = read(sock,BufferChild,1023);
           if (n < 0) printf("ERROR reading from socket\n");
           printf("Received from socket: %s",BufferChild);
           //if (n < 0) printf("ERROR writing to socket for client %d", sock);
        // ********************
    
    
    
    
        // **** SENDING DATA THROUGH PIPE
            /* Close reading descriptor since we are not going to use it for child process */
            close (pipeDescriptor[0]);
    
    
            /* We write through the "writing" descriptor */
            write (pipeDescriptor[1], BufferChild, strlen(BufferChild)+1);
    }}
    
    
    
    
    /******** ParentTasks() *********************
     There is only one instance of this function 
     for all connections.
     *****************************************/
    void ParentTasks(){
        char buffer[1024];
    
    
        while(1){
            bzero(buffer,1024);
    
    
            /* Close writing descriptor since we are not going to use it for parent process */
            close (pipeDescriptor[1]);
    
    
            /* We read all characters from reading descriptor and will print it on screen */
            read (pipeDescriptor[0], buffer, 1023);    
            printf ("Received from my son: %s", buffer);
    
    
            /* We wait until the son dies and we leave (parricide??) */
            wait (&childStatus);
        }
    }
    What could I do with this?

    thanks in advance

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    Lines 104 to 120 seem to serve no purpose at all.
    IPC is a completely different mechanism to sockets or pipes.
    Besides, you should be using a file you own in the call to ftok().

    > /* We wait until the son dies and we leave (parricide??) */
    > wait (&childStatus);
    And then what?
    You're still stuck in a while(1) loop.

    To be honest, you need to change this code so there are no messy global variables.

    > while(opt!="shutdown")
    This is a very basic mistake of how not to compare two strings.
    Use strcmp()
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Oct 2016
    Posts
    3
    Thanks for your reply.

    Lines 104 to 120 serves for the purpose of communication between processes using pipes. If you remove them, then there's no communication between child process and parent process. (already tested)

    for "wait (&childStatus)" I cannot see if that will allow (or not) the processes to be able to communicate properly between them while the "child" is attending sockets.
    Either commenting that line or not, no more than 1 client will be attended (and that's the point).

    and then... Remove the "while(1)" loop and we are still stuck.
    In addition, any attempt to remove the "while(1) loop" for parent process and the code will stop attending the child process.

    Talking about global variables:
    In this code there are no global variables but for "Buffer" which are only accessed by the parent process.

    Either way I take your advise won't work, already tested (and still testing).
    Last edited by Ernie~; 10-23-2016 at 10:39 AM.

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    Strange, I seem to be able to make it work - at least in the single client case (despite all the wheezing from you).
    Code:
    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <sys/msg.h>
    #include <wait.h>
    
    
    // Max number of clients
    int max_cli = 5;
    
    
    // Future menu options
    char *opt = "";
    
    
    // Error messages
    void error(const char *msg)
    {
      perror(msg);
      exit(-1);
    }
    
    void SonTasks(int sock, int pipeWrite);             /* function prototype */
    void ParentTasks(int pipeRead);             /* function prototype */
    
    // --------> Main
    int main(int argc, char *argv[])
    {
      printf("Loading server...\n\n");
      int pipeDescriptor[2];
    
    //********************* SOCKETS
      int sockfd, newsockfd, portno;
      socklen_t clilen;
      struct sockaddr_in serv_addr, cli_addr;
    
    
      if (argc < 2) {
        error("ERROR, no port provided");
      }
    
    
      sockfd = socket(AF_INET, SOCK_STREAM, 0);
      if (sockfd < 0)
        error("ERROR opening socket");
      bzero((char *) &serv_addr, sizeof(serv_addr));
      portno = atoi(argv[1]);
      serv_addr.sin_family = AF_INET;
      serv_addr.sin_addr.s_addr = INADDR_ANY;
      serv_addr.sin_port = htons(portno);
      if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
        error("ERROR on binding");
      listen(sockfd, max_cli);
      clilen = sizeof(cli_addr);
    
      if (pipe(pipeDescriptor) == -1) {
        error("Error");
      }
    
      while ( strcmp(opt,"shutdown") != 0 ) {
        newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
        if (newsockfd < 0)
          printf("ERROR on accept\n");  // Even if we find an error the server must not stop
    
    
        pid_t idProcess = fork();
    
    
        switch (idProcess) {
        case -1:
          error("Failed to create process");
          break;
        case 0:
          //close(sockfd);
          SonTasks(newsockfd,pipeDescriptor[1]);
    
    
          break;
        default:
          //close(newsockfd);
          ParentTasks(pipeDescriptor[0]);
          break;
        }
      }
    
    
      close(sockfd);
      return 0;                     /* We will never reach this point */
    }
    
    
    /******** SonTasks() *********************
     There is a separate instance of this function 
     for each connection.  It handles all communication
     once a connnection has been established.
     *****************************************/
    void SonTasks(int sock, int pipeWrite)
    {
      char BufferChild[1024];
    
    
    // ****** SOCKETS
      int n;
    // **************
      while (1) {
        // ************ SOCKETS
        bzero(BufferChild, 1024);
        n = read(sock, BufferChild, 1023);
        if (n < 0)
          printf("ERROR reading from socket\n");
        printf("Received from socket: %s", BufferChild);
        //if (n < 0) printf("ERROR writing to socket for client %d", sock);
        // ********************
    
        // **** SENDING DATA THROUGH PIPE
        /* Close reading descriptor since we are not going to use it for child process */
        //close(pipeDescriptor[0]);
    
        /* We write through the "writing" descriptor */
        write(pipeWrite, BufferChild, strlen(BufferChild) + 1);
      }
    }
    
    /******** ParentTasks() *********************
     There is only one instance of this function 
     for all connections.
     *****************************************/
    void ParentTasks(int pipeRead)
    {
      char buffer[1024];
      int childStatus;
    
      while (1) {
        bzero(buffer, 1024);
    
        /* Close writing descriptor since we are not going to use it for parent process */
        //close(pipeDescriptor[1]);
    
        /* We read all characters from reading descriptor and will print it on screen */
        read(pipeRead, buffer, 1023);
        printf("Received from my son: %s", buffer);
    
        /* If the child exits, then so should we */
        if ( waitpid(-1,&childStatus,WNOHANG) != 0 )
          break;
      }
    }
    
    // Console 1
    $ ./a.out 22222
    Loading server...
    
    Received from socket: hello
    Received from my son: hello
    Received from socket: world
    Received from my son: world
    Received from socket: hey
    Received from my son: hey
    Received from socket: this
    Received from my son: this
    Received from socket: works
    Received from my son: works
    
    // Console 2
    $ telnet localhost 22222
    Trying 127.0.0.1...
    Connected to localhost.
    Escape character is '^]'.
    hello
    world
    hey
    this
    works
    The rest of the problems you can fix yourself.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #5
    Registered User
    Join Date
    Oct 2016
    Posts
    3
    Thanks, that was not the issue.

    Anyways the issue is solved (after reviewing the code I noticed that the problem was in the parent process, so it was the child who needed to be attending sockets)

    Apparently it was properly coded (despite of that strcmp() that I will need to remove since I won't need to do a menu after all)

    Despite of your reading comprehension of a matter, I really appreciate your effort. I was able also to compile it with no issues before posting it here.

    "at least in the single client case" matches perfectly with my sentence "it's only handling 1 client." and that was the point of the main issue.

    I wanted to use IPC since I planned at the beginning to use shared memory to be used by all processes, but as you said, it's a really bad idea and confusing to use global variables (or even shared memory).
    Later I have no choice but to use RPC to communicate with other server we have.

    Already changed strcmp() since I didn't notice that could be more effective than directly compare two strings.

    Changed the son's tasks to be the parent's tasks and that solved the issue and now it's managing all incoming connections.

    Thanks for standing these wheezings up.

    Regards.

  6. #6
    Registered User
    Join Date
    Oct 2016
    Posts
    1
    hello

    sorry for writing comment in unappropriate way.I am new user.I cannot find button to post my question please help me

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Reading + socket communication
    By DA93 in forum C Programming
    Replies: 5
    Last Post: 06-23-2015, 11:20 AM
  2. Question about reading from socket
    By raczzoli in forum C Programming
    Replies: 3
    Last Post: 05-18-2011, 04:05 PM
  3. UDP socket partial reading
    By mynickmynick in forum Networking/Device Communication
    Replies: 0
    Last Post: 03-25-2009, 11:43 AM
  4. Question about reading from pipes.
    By Ironic in forum C Programming
    Replies: 7
    Last Post: 11-30-2008, 11:19 PM
  5. reading and writing structures to pipes
    By netwizio in forum Linux Programming
    Replies: 3
    Last Post: 01-06-2004, 01:28 AM

Tags for this Thread