如何使用fork()使用C并行调用子例程

时间:2013-09-23 06:07:57

标签: c sockets fork

我有以下代码,其中我使用TCP端口运行服务器。我需要分叉并调用子程序来调用客户端,以便它们可以并行运行并与服务器连接。

截至目前,我刚刚能够通过循环进行调用的串行实现,我似乎已经遇到了障碍,如果有人可以忍受痛苦,那将会很棒代码并指导我。

以下是主要内容。客户端子例程只驻留在client.c中,似乎工作正常。如果需要,我也可以粘贴。

main(int argc, char *argv[])
{
  struct sockaddr_in manager, client;
  struct hostent *cp;
  int sockdescriptor, td;
  int len;
  char buf[BLEN];
  int j; 
  int n; 
  int num_nodes;
  pid_t pid;


  key_t key;
  int shmid;
  int *port_num;

  sockdescriptor = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

  memset((char *) &manager, 0, sizeof(struct sockaddr_in));
  manager.sin_family = AF_INET;
  manager.sin_addr.s_addr = INADDR_ANY;
  manager.sin_port = htons((u_short) 0); /* dynamically assigning port */

  bind(sockdescriptor, (struct sockaddr *) &manager, sizeof(struct sockaddr_in));

    len = sizeof(struct sockaddr_in);
    listen(sockdescriptor, QUELEN);

/***************************** Getting port by getsockname() **********************************/
/*                                                                                            */
/*                                                                                            */
  if(getsockname(sockdescriptor, (struct sockaddr *) &manager, &len) == -1){
    perror("getsockname failed!");
    return -1;
  }
/*                                                                                            */    
/*                                                                                            */
/**********************************************************************************************/  
    printf("manager port %d\n", (int) ntohs(manager.sin_port));


/********************************* Creating Shared Memory *************************************/
/*                                                                                            */    
/*                                                                                            */

    key = 1234;

    if ((shmid = shmget(key, SHMSZ, IPC_CREAT | 0666)) < 0){
        perror("shmget is broken!");
        exit(1);
    }

    if ((port_num = shmat(shmid, NULL, 0)) == (int *) -1){
        perror("shmat is broken!");
        exit(1);
    }

    *port_num = (int) ntohs(manager.sin_port);
/*                                                                                            */    
/*                                                                                            */
/**********************************************************************************************/  


   for(j = 0; j < num_nodes ; j++){
    if((pid = fork()) == 0){            // child process

          while(1) {

            len = sizeof(struct sockaddr_in);
            td = accept(sockdescriptor, (struct sockaddr *) &client, &len);

//                    close(sockdescriptor);            //closing listening socket

                cp = gethostbyaddr((char *) &client.sin_addr, sizeof(struct in_addr), AF_INET);
//              printf("Connected from %s\n", cp->h_name);

                client_num++;   
                    printf("client %d port %d\n",client_num, *port_num);

                sprintf(buf, "%d",nonce);
                send(td, buf, strlen(buf), 0);

                n = recv(td, buf, sizeof(buf), 0);

                printf("client %d says %s\n",client_num, buf);

                close(td); /* client request processed, close this client's socket */
                close(sockdescriptor);
                exit(0);
          } // end of while loop
    }
//  else if((pid = fork()) > 0){

    client_prog();  // Calls to this subroutine need to be via forked processes

//  close(td);
//  exit(0);

//  } // else if ends here

} // end of the for loop

1 个答案:

答案 0 :(得分:1)

要拥有num_nodes个客户,请执行:

for(j = 0; j<num_nodes; j++)
    if (fork() == 0) {
        close(sockdescriptor);
        client_prog();
        exit(0);
    }

然后要有一个单独的进程处理每个客户端连接,这样多个客户端可以并行进行,我建议你用这样的东西替换整个for循环:

while(1) {
    td = accept(sockdescriptor, ...);
    client_num++;
    if (fork() == 0) {
        close(sockdescriptor);

        /* handle client interaction here */
        send(...) / receive(...)

        exit(0);
    } else {
        close(td);
    }
}

请注意,存在竞争条件:如果num_nodes大于SOMAXCONN,则可能会断开连接。首先产生服务器进程并不能消除竞争条件。这种东西对于管道是更安全的,在叉子之前预先打开。