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

预先创建线程之由主线程分发连接请求

此种方式是由主线程预先创建多个工作线程,并且主线程不断的监听连接请求,当有连接请求时先获得锁,并将连接放入到连接数组中,并通知空闲的工作线程(即阻塞在条件等待处的工作线程)进行请求处理,工作线程得到通知后先在连接数组中拿一个可用的连接,并将其标记为已处理,然后释放锁,执行请求处理函数。此方式处理的开销要比前一种的方式大,因为要工作线程获得一个连接要同时处理锁及条件变量,而前一种方式只需要维护一个锁即可。

 

例子:回射服务器,即服务器端接收客户端来的数据,并将数据原样返回给客户端,代码在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 <pthread.h>

#include <stdlib.h>

 

#define SERV_PORT 2003

#define MAXLINE 1024

#define LISTENQ 4

#define CLIENTNUM 5

#define MAXNCLI 20

 

int listenfd;

pthread_t *child;

pthread_mutex_t mutex;

pthread_cond_t cond;

int clifd[MAXNCLI], iput, iget;

 

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

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 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 * threadMain(void *arg)

{

   int connfd;

 

pthread_mutex_lock(&mutex);

/* 如果连接数组中没有有效的连接,即进入阻塞状态 */

   while(iget == iput)

       pthread_cond_wait(&cond, &mutex);

   /* 当条件被激活,工作线程从连接数据中拿到一个有效连接,移动有效连接的下标 */

   connfd = clifd[iget++];

   if(iget == MAXNCLI)

       iget = 0;

   pthread_mutex_unlock(&mutex);

 

   /* 调用请求处理函数 */

   requestProcessFunc(connfd);

   close(connfd);

}

 

void makeThread(int n)

{

pthread_create(&child[n],NULL, threadMain, (void *)n);

    return;

}

 

int main(intargc, char **argv)

{

    int i;

    socklen_t tmpAddLen, addLen;

    int connfd;

 

    pthread_mutex_init(&mutex, NULL);

    pthread_cond_init(&cond, NULL);

    addLen = sizeof(struct sockaddr_in);

 

    listenfd = makeListenByPort(SERV_PORT);

 

    child = (pthread_t*)malloc(sizeof(pthread_t) * CLIENTNUM);

    if(child == NULL) {

        printf("memory mallocerror!");

        exit(0);

    }

 

    /* 创建工作线程 */

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

        makeThread(i);

    }

    iget = iput = 0;

 

    for(;;) {

        tmpAddLen = addLen;

 

        connfd = accept(listenfd, NULL,&tmpAddLen);

        pthread_mutex_lock(&mutex);

        clifd[iput++] = connfd;

        if(iput == MAXNCLI)

            iput = 0;

 

        /* 通知工作线程已经有连接请求 */

        pthread_cond_signal(&cond);

        pthread_mutex_unlock(&mutex);

    }

}

 

客户端代码:

#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:server terminated 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);

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值