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

预先创建线程之accept之前获得锁

预先创建线程是由一个主线程创建多个工作线程,然后工作线程通过互斥机制处理每个客户的连接。有两种常见的方法可以实现,一种是工作线程调用accept,并在调用accept加入锁保护。第二种是主线程调用accept函数,当一个客户端连接服务器后,主线程通知工作线程处理客户请求。这两种实现方法将分进行说明。

在第一种方式中,工作线程调用accept之前就必须获得锁,获得锁的工作线程阻塞在accept函数处,当有连接请求时accept函数返回,然后释放掉锁,并调用请求处理函数进行处理,其它在等锁的工作线程中的一个获得锁被阻塞致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 <pthread.h>

#include <stdlib.h>

 

#define SERV_PORT 2003

#define MAXLINE 1024

#define LISTENQ 4

#define CLIENTNUM 5

 

int listenfd;

pthread_t *child;

pthread_mutex_t mutex;

socklen_t addLen;

 

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

void requestProcessFunc(int connfd)

{

   char buf[MAXLINE];

   int n;

 

   for(;;) {

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

          printf("clientis 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)

{

   socklen_t tmpAddLen;

   int connfd;

 

   tmpAddLen = addLen;

   for(;;) {

       /* accept之前先获得锁 */

       pthread_mutex_lock(&mutex);

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

       if(connfd <= 0) {

            printf("accept funcerror!");

            exit(0);

       }

       /* 返回后马上释放锁 */

       pthread_mutex_unlock(&mutex);

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

       requestProcessFunc(connfd);

       close(connfd);

   }

}

 

/* 创建工作线程 */

void makeThread(int n)

{

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

   return;

}

 

int main(int argc, char **argv)

{

   int i;

 

   pthread_mutex_init(&mutex, NULL);

   addLen = sizeof(struct sockaddr_in);

 

   listenfd = makeListenByPort(SERV_PORT);

 

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

   if(child == NULL) {

       printf("memory malloc error!");

       exit(0);

   }

 

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

       makeThread(i);

   }

 

   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: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_inservaddr;

 

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

        printf("socketerror\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("connecterror\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、付费专栏及课程。

余额充值