多进程和多线程服务器有什么缺点呢?
多进程服务器缺点:
1.内存消耗比较大,每个进程都独立加载完整的应用环境
2.cpu消耗偏高,高并发下,进程之间频繁进行上下文切换,需要大量的内存换页操作
3.很低的io并发处理能力,只适合处理短请求,不适合处理长请求
多线程服务器缺点:
1.不方便操作系统的管理
2.VM对内存的管理要求非常高,GC的策略会影响多线程并发能力和系统吞吐量
3.由于存在对共享资源操作,一旦出现线程"死锁"和线程阻塞,很容易使整个应用失去可用性
用他们编写的服务器,当用户增多时,服务器性能也会下降。
为了解决这个问题,select就出现了。
select服务器的优点:
1.高性能(与多进程和多线程比较)
(1)select一次等待多个文件描述符;
(2)select的cpu压力低;
(3)等待时间变短,提升了性能;
select服务器的缺点:
(1)每次调⽤用select,都需要把fd集合从⽤用户态拷贝到内核态,这个开销在fd很多时会很⼤大
(2)同时每次调⽤用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很⼤大
(3)select⽀支持的⽂文件描述符数量太⼩小了,默认是1024
select服务器代码如下
#include
#include
#include
#include
#include
#include
#include
int array_fds[1024];
int startup(char * _ip, int _port)
{
int sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock < 0)
{
perror("create socket is fail");
return 2;
}
struct sockaddr_in peer;
peer.sin_family = AF_INET;
peer.sin_port = htons(_port);
peer.sin_addr.s_addr = inet_addr(_ip);
int opt = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
if(bind(sock, (struct sockaddr*)&peer, sizeof(peer)) < 0)
{
perror("bind");
return 3;
}
if(listen(sock, 10) < 0)
{
perror("listen");
return 4;
}
return sock;
}
static void Usage(const char* proc)
{
printf("%s[ip][port]\n", proc);
}
int main(int argc, char *argv[])
{
if(argc != 3)
{
Usage(argv[0]);
return 1;
}
int listensock = startup(argv[1], atoi(argv[2]));
int maxfd = 0;
int array_size = sizeof(array_fds)/sizeof(array_fds[0]);
fd_set rfds;
array_fds[0] = listensock;
int i = 1;
for(; i < array_size; i++)
{
array_fds[i] = -1;
}
while(1)
{
struct timeval _timeout = {5, 0};
FD_ZERO(&rfds);
maxfd = -1;
for(i = 0; i < array_size; i++)
{
if(array_fds[i] > 0)
{
FD_SET(array_fds[i], &rfds);
if(array_fds[i] > maxfd)
{
maxfd = array_fds[i];
}
}
}
switch(select(maxfd + 1, &rfds, NULL, NULL, &_timeout))
{
case 0:
printf("timeout....");
break;
case -1:
perror("select");
break;
default:
{
int j = 0;
for(; j < array_size; j++)
{
if(array_fds[j] < 0)
continue;
if(j == 0 && FD_ISSET(array_fds[j], &rfds))
{
struct sockaddr_in client;
socklen_t len = sizeof(client);
int new_fd = accept(array_fds[j], (struct sockaddr*)&client, &len);
if(new_fd < 0)
{
perror("new_fd:accept");
continue;
}else
{
//printf("get a new client:(%s:%d)");
int k = 1;
for(; k < array_size; k++)
{
if(array_fds[k] < 0)
{
array_fds[k] = new_fd;
break;
}
}
if(k == array_size)
{
close(new_fd);
}
}
}
else if(j != 0 && FD_ISSET(array_fds[j], &rfds))
{
char buf[1024];
ssize_t s = read(array_fds[j], buf, sizeof(buf)-1);
if(s > 0)
{
buf[s] = 0;
printf("client say# %s\n", buf);
}else if(s == 0)
{
printf("client is quit!");
close(array_fds[j]);
array_fds[j] = -1;
}else
{
perror("read");
close(array_fds);
array_fds[j] = -1;
}
}
}
}
break;
}
}
return 0;
}