Unix网络编程服务器设计方式之四

预先创建子进程的方式

预先创建子进程的方式比为每个客户端创建一个进程的方式优越的地方在于当服务器启动时就将子进程创建好,当一个客户端连接至服务器时选择一个可用的子进程处理,这样可以节省到创建子进程的消耗。有一个弊端是需要事先确定子进程的个数,当客户端多于子进程的个数时,基于的客户端只能等待可用的子进程。有一种解决方法就是动态的分配子进程的个数,当可用的子进程小于事先设定的阀值时,增加一定数量的子进程,相持当可用子进程多于事先设定的阀值时,减少一定数量的子进程。

这种方式的实现是利用了UNIX内核对文件描述符的实现,让所有的子进程全部监听处于Listen状态的描述符(即调用accept函数),当一个客户端连接进来时所有的子进程被激活,但是只有一个进程可以与客户端进行连接,其它的进程继续进入阻塞状态。为了防止这种竞争发生错误,可以加入锁机制,只有得到锁的进程才能与客户端进行连接,可以用文件锁或线程锁等机制实现。

 

例子:回射服务器,即服务器端接收客户端来的数据,并将数据原样返回给客户端,代码在CentOS5.0测试通过

服务器端代码:

#include <stdio.h>

#include <sys/socket.h>

#include <sys/types.h>

#include <netinet/in.h>

#include <sys/time.h>

#include <sys/select.h>

#include <strings.h>

#include <errno.h>

#include <stdlib.h>

 

#define SERV_PORT 2003

#define MAXLINE 1024

#define LISTENQ 4

 

int makeListenByPort(short port)

{

   int listenfd;

   struct sockaddr_in servaddr;

 

   listenfd = socket(AF_INET, SOCK_STREAM, 0);

 

   bzero(&servaddr, sizeof(servaddr));

   servaddr.sin_family = AF_INET;

   servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

   servaddr.sin_port = htons(port);

 

   bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

 

   listen(listenfd, LISTENQ);

 

   return listenfd;

}

 

/*  客户请求处理函数 */

void requestProcessFunc(int connfd)

{

  char buf[MAXLINE];

  int n;

 

  for(;;) {

      if((n = read(connfd, buf, MAXLINE)) == 0) {

         printf("client is quit\n");

         break;

      }else{

           write(connfd, buf, n);

      }

   }

}

 

int main(int argc, char **argv)

{

   int listenfd, connfd, maxfd, sockfd;

   char buf[MAXLINE];

   struct sockaddr_in cliaddr;

   int i;

   int clilen, adrlen;

   pid_t child;

 

    /*根据端号建立监听 */

    listenfd= makeListenByPort(SERV_PORT);

   adrlen = sizeof(struct sockaddr);

 

   /*创建5个子进程 */

  for(i = 0; i < 5; i++) {

      if((child = fork()) == 0) {

           /* 每个子进程都循环的监听 */

           for(;;) {

                clilen = adrlen;

               if((connfd = accept(listenfd,(struct sockaddr *)&cliaddr, &clilen)) < 0){

                    if(errno == EINTR)

                        continue;

                    else{

                        printf("accepterror!");

                        exit(0);

                     }

                }

                requestProcessFunc(connfd);

                close(connfd);

           }

       }

   }

   /*父进程不做任何操作 */

  for(;;)   pause();

}

 

客户端代码:

#include <stdio.h>

#include <stdlib.h>

#include <sys/socket.h>

#include <sys/types.h>

#include <netinet/in.h>

#include <strings.h>

#include <string.h>

 

#define MAXLINE 1024

#define SERV_PORT 2003

 

void cli_str(FILE *fp, int sockfd)

{

   char sendline[MAXLINE];

   char recvline[MAXLINE];

 

   memset(recvline, 0x00, sizeof(recvline));

   memset(sendline, 0x00, sizeof(sendline));

   printf("cli#");

   while((fgets(sendline, MAXLINE, fp)) != NULL) {

       write(sockfd, sendline, strlen(sendline));

       if(read(sockfd, recvline, MAXLINE) == 0) {

            printf("str_cli:serverterminated prematurely\n");

           exit(0);

       }

       fputs(recvline, stdout);

       fflush(stdout);

       memset(recvline, 0x00, sizeof(recvline));

       printf("cli#");

    }

}

 

int main(int argc, char **argv)

{

   int sockfd;

   struct sockaddr_in servaddr;

 

   if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {

       printf("socket error\n");

       exit(0);

    }

 

   bzero(&servaddr, sizeof(servaddr));

   servaddr.sin_family = AF_INET;

    inet_pton(AF_INET, argv[1],&servaddr.sin_addr);

   servaddr.sin_port = htons(SERV_PORT);

   if((connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)))== -1) {

       printf("connect error\n");

       exit(0);

    }

 

   cli_str(stdin, sockfd);

   exit(0);

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值