您的位置:首页 > 运维架构 > Linux

并发服务器模型:IO复用循环服务器

2011-07-15 11:24 381 查看
1、简介

前面的服务器模型主要集中在并发服务器上,并发服务器有个比较大的缺陷,它需要建立多个并行的处理单元。当客户端增加时,随着处理单元的增加,系统的负载会逐渐转移到并行单元的现场切换上。因此有一个比较新型的IO复用循环服务器。该模型在系统开始时,建立多个不同工作类型的处理单元,当客户端的请求到来时,将客户端的连接放到一个状态池中,对所有客户端的连接状态在一个处理单元中进行轮询处理。

2、tcp模型





3、服务器源代码(concurrency-server5.c):

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <errno.h>

#include <sys/socket.h>

#include <arpa/inet.h>

#include <netinet/in.h>

#include <sys/types.h>

#include <unistd.h>

#include <time.h>

#include <pthread.h>

#define BUFLEN 1024

#define THREADNUM 2

#define CLIENTNUM 1024

int connect_host[CLIENTNUM];

int connect_num = 0;

/*******************并发服务器模型之五:IO复用循环服务器**********************/

static void *handle_request(void *argv){

char buf[BUFLEN];

int len;

time_t now;

int maxfd = -1;

fd_set rfds;

struct timeval tv;

tv.tv_sec = 1;

tv.tv_usec = 0;

int i =0;

int err = -1;

while(1){

FD_ZERO(&rfds);

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

if(connect_host[i] != -1){

FD_SET(connect_host[i],&rfds);

if(maxfd < connect_host[i])

maxfd = connect_host[i];

}

}

err = select(maxfd+1, &rfds, NULL, NULL, &tv);

switch(err){

case 0: break;

case -1: break;

default:

if (connect_num < 0)

break;

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

if(connect_host[i] != -1){

if(FD_ISSET(connect_host[i],&rfds)){

/******处理客户端请求*******/

bzero(buf,BUFLEN);

len = recv(connect_host[i],buf,BUFLEN,0);

if(len >0 && !strncmp(buf,"TIME",4)){

bzero(buf,BUFLEN);

/*获取系统当前时间*/

now = time(NULL);

/*ctime将系统时间转换为字符串,sprintf使转化后的字符串保存在buf*/

sprintf(buf,"%24s\r\n",ctime(&now));

//******发送系统时间*******/

send(connect_host[i],buf,strlen(buf),0);

}

/*关闭通讯的套接字*/

close(connect_host[i]);

/*更新文件描述符在数组中的值*/

connect_host[i] = -1;

connect_num--;

}

}

}

break;

}

}

return NULL;

}

static void *handle_connect(void *arg){

int sockfd = *((int *)arg);

int newfd;

struct sockaddr_in c_addr;

socklen_t len;

int i;

while(1){

len = sizeof(struct sockaddr);

if((newfd = accept(sockfd,(struct sockaddr*) &c_addr, &len)) >0){

printf("\n*****************通信开始***************\n");

printf("正在与您通信的客户端是:%s: %d\n",inet_ntoa(c_addr.sin_addr),ntohs(c_addr.sin_port));

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

if(connect_host[i] == -1){

connect_host[i] = newfd;

/*客户端计数器*/

connect_num++;

/*继续等待新的客户端*/

break;

}

}

}

}

return NULL;

}

int main(int argc, char **argv)

{

int sockfd;

struct sockaddr_in s_addr;

unsigned int port, listnum;

pthread_t thread_s[2];

/**/

memset(connect_host,-1,CLIENTNUM);

/*建立socket*/

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

perror("socket");

exit(errno);

}else

printf("socket create success!\n");

/*设置服务器端口*/

if(argv[2])

port = atoi(argv[2]);

else

port = 4567;

/*设置侦听队列长度*/

if(argv[3])

listnum = atoi(argv[3]);

else

listnum = 3;

/*设置服务器ip*/

bzero(&s_addr, sizeof(s_addr));

s_addr.sin_family = AF_INET;

s_addr.sin_port = htons(port);

if(argv[1])

s_addr.sin_addr.s_addr = inet_addr(argv[1]);

else

s_addr.sin_addr.s_addr = INADDR_ANY;

/*把地址和端口帮定到套接字上*/

if((bind(sockfd, (struct sockaddr*) &s_addr,sizeof(struct sockaddr))) == -1){

perror("bind");

exit(errno);

}else

printf("bind success!\n");

/*侦听本地端口*/

if(listen(sockfd,listnum) == -1){

perror("listen");

exit(errno);

}else

printf("the server is listening!\n");

/*创建线程处理客户端的连接*/

pthread_create(&thread_s[0],NULL,handle_connect,(void *)&sockfd);

/*创建线程处理客户端的请求*/

pthread_create(&thread_s[1],NULL,handle_request, NULL);

/*等待线程结束*/

int i;

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

pthread_join(thread_s[i],NULL);

}

/*关闭服务器的套接字*/

close(sockfd);

return 0;

}

4、客户端源代码(concurrency-client.c)与之前的一样。

5、编译源代码:

new@new-desktop:~/linux/c$ gcc -Wall –lpthread concurrency-server5.c -o server

new@new-desktop:~/linux/c$ gcc -Wall concurrency-client.c -o client

6、运行,试试吧
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Linux 服务器 休闲