+ -
当前位置:首页 → 问答吧 → 求高手解惑!!

求高手解惑!!

时间:2010-12-19

来源:互联网

公司太穷,给几台P3的客户机让我测8核16G的服务器的并发,没找着开销小的开源软件,只能自己瞎捣鼓
问题是这样的:我的客户机上不管上几个ip都只能建63000个连接的样子,崩溃啊,这个肯定不够的,有没有人
帮我看下为啥上不去呢?谢谢
  1. #a.pl
  2. use IO::Socket;

  3. $localaddr=shift;
  4. @sock=();
  5. for(1..525)
  6. {
  7.         $client = IO::Socket::INET->new(Proto     => "tcp",
  8.                                         PeerAddr  => "172.16.67.252",
  9.                                         LocalAddr => $localaddr,
  10.                                         PeerPort  => '80')
  11.                or die "$!";
  12.         push(@sock, $client);
  13. }
  14. while(1)
  15. {
  16.         foreach $fh (@sock) {
  17.                 print $fh "GET /hostname.txt HTTP/1.1\r\nhost: 172.16.69.195\r\n\r\n";
  18.                 select(undef,undef,undef,0.03);
  19.         }
  20.         sleep 1;

  21.         foreach $fh (@sock) {
  22.                 $fh->recv($data, 1024);
  23.         }
  24. }

  25. #################################
  26. #connections.pl
  27. #
  28. @addr=qw/172.16.64.192 172.16.64.193 172.16.64.194 172.16.64.195 172.16.64.196/;
  29. #@addr=qw/172.16.64.192 172.16.64.193 172.16.64.194 172.16.64.195/;
  30. #@addr=qw/172.16.64.193/;

  31. for(@addr)
  32. {
  33.         connectto($_);
  34.         #sleep 10;
  35. }

  36. waitpid(-1,0);

  37. sub connectto {
  38.         $localaddr=shift;
  39.         for(1..23)
  40.         {
  41.                 $pid=fork();
  42.                 if($pid==0)
  43.                 {
  44.                         exec("perl a.pl $localaddr");
  45.                 }
  46.                 select(undef,undef,undef,0.5);
  47.         }
  48. }
复制代码

作者: meihuaqi   发布时间: 2010-12-19

忘了说了,错误提示是: Address already in use

作者: meihuaqi   发布时间: 2010-12-19

上面这个代码被我调到正好60000个并发,再多就不行了

作者: meihuaqi   发布时间: 2010-12-19

高手是不是还在睡觉。。。,我太苦了

作者: meihuaqi   发布时间: 2010-12-19



QUOTE:
高手是不是还在睡觉。。。,我太苦了
meihuaqi 发表于 2010-12-19 09:07




    K。。linux文件句柄也就6W多个。

作者: 兰花仙子   发布时间: 2010-12-19

端口号不够使了

作者: flw   发布时间: 2010-12-19



QUOTE:
端口号不够使了
flw 发表于 2010-12-19 10:44




    哦 没仔细看 我以为指server端
client端这么跑倒是把端口耗尽。

作者: 兰花仙子   发布时间: 2010-12-19

不能啊,我6个客户端ip啊

作者: meihuaqi   发布时间: 2010-12-19

5个

作者: meihuaqi   发布时间: 2010-12-19

高手别走啊。。。。谢谢,接着解惑

作者: meihuaqi   发布时间: 2010-12-19



QUOTE:
5个
meihuaqi 发表于 2010-12-19 10:49




    你server端程序是怎么模型?

作者: 兰花仙子   发布时间: 2010-12-19

server 是http 服务器,做的和apache类似

作者: meihuaqi   发布时间: 2010-12-19

连接数在现代产品里,其实无意义。
你没看现在radware、citrix的产品,都号称无限连接数。
处理能力是多少才是重要的。
否则连接只是耗在队列里干等。

作者: 兰花仙子   发布时间: 2010-12-19



QUOTE:
server 是http 服务器,做的和apache类似
meihuaqi 发表于 2010-12-19 10:57




    你把内核参数调优一下,什么队列长度之类,应该可以加大连接数。
apache prefork能处理的并发连接本来就很有限。
event mpm的可能好一些。

作者: 兰花仙子   发布时间: 2010-12-19

连接数这个虽然不是很重要,但也是个指标,无限连接数有点夸张了,48G内存才能到24M连接

作者: meihuaqi   发布时间: 2010-12-19

扯远了,先说我这个脚本哪有问题啊,谢谢

作者: meihuaqi   发布时间: 2010-12-19

现在多连接可以使用Epoll技术.
在1G内存的机子上可以连接到10万.
我贴上一个Epoll得例子,看看先.



QUOTE:
epoll用到的所有函数都是在头文件sys/epoll.h中声明的,下面简要说明所用到的数据结构和函数:
所用到的数据结构
typedef   union   epoll_data  
{
void   *ptr;
int   fd;
__uint32_t   u32;
__uint64_t   u64;
}   epoll_data_t;

struct   epoll_event  
{
__uint32_t   events;   /*   epoll   events   */
epoll_data_t   data;   /*   user   data   variable   */
};
结构体epoll_event   被用于注册所感兴趣的事件和回传所发生待处理的事件,其中epoll_data   联合
体用来保存触发事件的某个文件描述符相关的数据,例如一个client连接到服务器,服务器通过调用
accept函数可以得到于这个client对应的socket文件描述符,可以把这文件描述符赋给epoll_data的
fd字段以便后面的读写操作在这个文件描述符上进行。epoll_event   结构体的events字段是表示感兴
趣的事件和被触发的事件可能的取值为:
epollin   :表示对应的文件描述符可以读;
epollout:表示对应的文件描述符可以写;
epollpri:表示对应的文件描述符有紧急的数据可读(我不太明白是什么意思,可能是类似client关闭   socket连接这样的事件);
epollerr:表示对应的文件描述符发生错误;
epollhup:表示对应的文件描述符被挂断;
epollet:表示对应的文件描述符有事件发生;
所用到的函数:
1、epoll_create函数
函数声明:int   epoll_create(int   size)
该函数生成一个epoll专用的文件描述符,其中的参数是指定生成描述符的最大范围(我觉得这个参数和select函数的第
一个参数应该是类似的但是该怎么设置才好,我也不太清楚)。
2、epoll_ctl函数
函数声明:int   epoll_ctl(int   epfd,   int   op,   int   fd,   struct   epoll_event   *event)
该函数用于控制某个文件描述符上的事件,可以注册事件,修改事件,删除事件。
参数:epfd:由   epoll_create   生成的epoll专用的文件描述符;
op:要进行的操作例如注册事件,可能的取值epoll_ctl_add   注册、epoll_ctl_mod   修改、epoll_ctl_del   删除
fd:关联的文件描述符;
event:指向epoll_event的指针;
如果调用成功返回0,不成功返回-1
3、epoll_wait函数
函数声明:int   epoll_wait(int   epfd,struct   epoll_event   *   events,int   maxevents,int   timeout)
该函数用于轮询i/o事件的发生;
参数:
epfd:由epoll_create   生成的epoll专用的文件描述符;
epoll_event:用于回传代处理事件的数组;
maxevents:每次能处理的事件数;
timeout:等待i/o事件发生的超时值;
返回发生事件数。
例子:
代码:
﹟include   <iostream>  
﹟include   <sys/socket.h>  
﹟include   <sys/epoll.h>  
﹟include   <netinet/in.h>  
﹟include   <arpa/inet.h>  
﹟include   <fcntl.h>  
﹟include   <unistd.h>  
﹟include   <stdio.h>  


﹟define   maxline   10  
﹟define   open_max   100  
﹟define   listenq   20  
﹟define   serv_port   5555  
﹟define   inftim   1000  

void   setnonblocking(int   sock)  
{
int   opts;  
opts=fcntl(sock,f_getfl);  
if(opts <0)  
{  
perror(″fcntl(sock,getfl)″);  
exit(1);  
}  

opts   =   opts∣o_nonblock;  

if(fcntl(sock,f_setfl,opts) <0)  
{  
perror(″fcntl(sock,setfl,opts)″);  
exit(1);  
}  
}  

int   main()  
{  
int   i,   maxi,   listenfd,   connfd,   sockfd,epfd,nfds;  
ssize_t   n;  
char   line[maxline];  
socklen_t   clilen;  
//声明epoll_event结构体的变量,ev用于注册事件,数组用于回传要处理的事件  
struct   epoll_event   ev,events[20];

//生成用于处理accept的epoll专用的文件描述符  
epfd=epoll_create(256);  
struct   sockaddr_in   clientaddr;  
struct   sockaddr_in   serveraddr;  
listenfd   =   socket(af_inet,   sock_stream,   0);  

//把socket设置为非阻塞方式  
setnonblocking(listenfd);  

//设置与要处理的事件相关的文件描述符  
ev.data.fd=listenfd;  

//设置要处理的事件类型  
ev.events=epollin∣epollet;  

//注册epoll事件  
epoll_ctl(epfd,epoll_ctl_add,listenfd,&ev);  

bzero(&serveraddr,   sizeof(serveraddr));  
serveraddr.sin_family   =   af_inet;  
char   *local_addr=″200.200.200.204″;  
inet_aton(local_addr,&(serveraddr.sin_addr));//htons(serv_port);  
serveraddr.sin_port=htons(serv_port);  
bind(listenfd,(sockaddr   *)&serveraddr,   sizeof(serveraddr));  
listen(listenfd,   listenq);  
maxi   =   0;  
for   (   ;   ;   )  
{  
//等待epoll事件的发生  
nfds=epoll_wait(epfd,events,20,500);  
//处理所发生的所有事件  
for(i=0;i <nfds;++i)  
{  
if(events.data.fd==listenfd)  
{  
connfd   =   accept(listenfd,(sockaddr   *)&clientaddr,   &clilen);  
if(connfd <0)
{  
perror(″connfd <0″);  
exit(1);  
}
}  
setnonblocking(connfd);  
char   *str   =   inet_ntoa(clientaddr.sin_addr);  
std::cout < <″connect   from   ″ <_u115   ?tr < <std::endl;  
//设置用于读操作的文件描述符  
ev.data.fd=connfd;  
//设置用于注测的读操作事件  
ev.events=epollin∣epollet;  
//注册ev  
epoll_ctl(epfd,epoll_ctl_add,connfd,&ev);  
}  
else   if(events.events&epollin)  
{
if   (   (sockfd   =   events.data.fd)   <   0)   continue;  
if   (   (n   =   read(sockfd,   line,   maxline))   <   0)  
{  
if   (errno   ==   econnreset)  
{  
close(sockfd);  
events.data.fd   =   -1;  
}  
else  
std::cout < <″readline   error″ < <std::endl;  
}
else   if   (n   ==   0)  
{  
close(sockfd);  
events.data.fd   =   -1;  
}  
//设置用于写操作的文件描述符  
ev.data.fd=sockfd;  
//设置用于注测的写操作事件  
ev.events=epollout∣epollet;  
//修改sockfd上要处理的事件为epollout  
epoll_ctl(epfd,epoll_ctl_mod,sockfd,&ev);  
}
else   if(events.events&epollout)  
{  
sockfd   =   events.data.fd;  
write(sockfd,   line,   n);  
//设置用于读操作的文件描述符  
ev.data.fd=sockfd;  
//设置用于注测的读操作事件  
ev.events=epollin∣epollet;  
//修改sockfd上要处理的事件为epolin  
epoll_ctl(epfd,epoll_ctl_mod,sockfd,&ev);  
}  
}  
}  
}

作者: 兰花仙子   发布时间: 2010-12-19

server端没有问题,我用2个客户机能上到120000W的连接,问题就是为啥一个客户机配多个ip只能有60000个连接

作者: meihuaqi   发布时间: 2010-12-19



QUOTE:
server端没有问题,我用2个客户机能上到120000W的连接,问题就是为啥一个客户机配多个ip只能有60000个连接
meihuaqi 发表于 2010-12-19 11:05




    本地端口号用尽了啦~~~

作者: 兰花仙子   发布时间: 2010-12-19

不是ip+端口确定一个连接的吗

作者: meihuaqi   发布时间: 2010-12-19

我又文盲了。。。?把那个关键点告诉我啊,一个端口只能被一个ip选择吗?

server------------------------client
ip+prot<--------tcp-------->ip+port

client端和server端只要有一个的ip或端口变了就算一个新连接吧

作者: meihuaqi   发布时间: 2010-12-19