每次有客户端连接时选择当前连接数(CR)最小的http服务器进行连接,然后转发请求和应答,用线程实现:
#include "unp.h"
#include <semaphore.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <time.h>
#include <syslog.h>
#define gettid() syscall(__NR_gettid)
#define SESSIONNUM 10000
int myreadline(int fd, char *buf, int n);
static void *http(void* connfd);
void init();
struct httpServerInfo
{
char ip[20];
char port[10];
char OS[10];
volatile int CR;
double ACR;
double cpuUse;
int memUse;
} httpServer[4];
struct SessionAdhesions
{
int ip;
int choice;
} sessionList[SESSIONNUM];
int sessionIndex;
char balanceServerIp[20];
char balanceServerPort[10];
volatile int CR;
double ACR;
double cpuUse;
int memUse;
static pthread_mutex_t mutex;
struct eachThreadInfo
{
int choice;
int fd;
};
int main(int argc, char **argv)
{
int listenfd, connfd;
pthread_t tid;
socklen_t clilen;
struct sockaddr_in cliaddr, servaddr;
listenfd = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
//-------------------初始化结构体----------------------------
init();
//----------------------------------------------------------
inet_pton(AF_INET,balanceServerIp,&servaddr.sin_addr);
servaddr.sin_port=htons(atoi(balanceServerPort));
Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));
Listen(listenfd, LISTENQ);
signal(SIGPIPE,SIG_IGN);
for ( ; ; )
{
clilen = sizeof(cliaddr);
if ( (connfd = accept(listenfd, (SA *) &cliaddr, &clilen)) < 0)
{
if (errno == EINTR) continue;
else err_sys("accept error");
}
// printf("connected from %s:%u...http\n",inet_ntoa(cliaddr.sin_addr),cliaddr.sin_port);
struct eachThreadInfo *arg=malloc(sizeof(struct eachThreadInfo));
arg->fd=connfd;
//-------------------------------------SessionAdhesions---------------------------------------------------------
/* int j=0;
int clientIp=cliaddr.sin_addr.s_addr;
for(j=0; j<sessionIndex; j++)
{
if(clientIp!=sessionList[j].ip)
{
arg->choice=sessionList[j].choice;
break;
}
}
if(j==sessionIndex)
{
sessionList[sessionIndex].ip=clientIp;*/
//---------------------------------------balance connect--------------------------------------------------------
int i;
int eachCR=99999;
for(i=0; i<4; i++)
{
if(httpServer[i].CR<eachCR)
{
arg->choice=i;
eachCR=httpServer[i].CR;
}
}
sessionList[sessionIndex].choice=arg->choice;
sessionIndex=(sessionIndex+1)%SESSIONNUM;
printf("choose httpServer %d!\n\n",arg->choice);
pthread_create(&tid,NULL,http,(void*)arg);
}
}
static void *http(void* arg)
{
pthread_detach(pthread_self());
struct eachThreadInfo *each=arg;
pthread_mutex_lock(&mutex);
httpServer[each->choice].CR++;
CR++;
pthread_mutex_unlock(&mutex);
int httpd;
struct sockaddr_in httpservaddr;
httpd = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&httpservaddr, sizeof(httpservaddr));
httpservaddr.sin_family = AF_INET;
httpservaddr.sin_port = htons(atoi(httpServer[each->choice].port));
Inet_pton(AF_INET, httpServer[each->choice].ip, &httpservaddr.sin_addr);
connect(httpd, (SA *) &httpservaddr, sizeof(httpservaddr));
//perror("connect");
char receiveline[MAXLINE];
ssize_t n;
char temp[50];
while((n=myreadline(each->fd,receiveline,MAXLINE))>2)
{
sscanf(receiveline,"%s",temp);
writen(httpd,receiveline,n);
}
writen(httpd,"\r\n",2);
char judge[100];
unsigned long int fileLength=0;
while((n=myreadline(httpd,receiveline,MAXLINE))>2)
{
writen(each->fd,receiveline,n);
sscanf(receiveline,"%s",judge);
if(!strcmp(judge,"Content-Length:"))
{
sscanf(receiveline,"%*s%lu",&fileLength);
}
}
writen(each->fd,"\r\n",2);
while(1)
{
if(MAXLINE<fileLength)
{
fileLength-=read(httpd, receiveline, MAXLINE);;
writen(each->fd,receiveline,MAXLINE);
}
else
{
read(httpd, receiveline, fileLength);
writen(each->fd,receiveline,fileLength);
break;
}
}
pthread_mutex_lock(&mutex);
httpServer[each->choice].CR--;
CR--;
pthread_mutex_unlock(&mutex);
close(each->fd);
close(httpd);
free(arg);
return NULL;
}
int myreadline(int fd, char *buf, int n)
{
char ch;
char *base=buf;
while(1)
{
if(read(fd, &ch, 1)!=1)
{
if(errno==EINTR) continue;
return -1;
}
if((*(buf++)=ch)=='\n') break;
}
*buf='\0';
return buf-base;
}
void init()
{
int conf=open("balance.conf",O_RDONLY);
char temp[40];
myreadline(conf,temp,40);
sscanf(temp,"%*s%s",balanceServerIp);
myreadline(conf,temp,40);
sscanf(temp,"%*s%s",balanceServerPort);
int i=0,j=0;
int num=4;
num=num*2;
for(; i<num; i++)
{
myreadline(conf,temp,30);
if(!(i%2)) sscanf(temp,"%*s%s",httpServer[j].ip);
else sscanf(temp,"%*s%s",httpServer[j++].port);
}
close(conf);
}
把webbench改为线程版本,用10W连接测试1300k.jpg请求,时间50秒,结果如下: