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、运行,试试吧
阅读(984) | 评论(0) | 转发(0) |