局域网C/S,服务器程序,主干千M,百M到桌面,为什么服务器程序只利用了5、6十M,其它网络程序如FTP什么的就上不去了??当50M以下时一点问题没有。服务器程序是对每个连接建立一个UDP SOCKET专门用于和该终端通信,也就是说开了200个左右SOCKET,带宽占用60M就不行了。通过任务管理器查看系统CPU利用20%,内存20%,用ONLINEEYE查看流量就在60M。请高手指点。问题如能解决,立即另开贴送1000分,顶也有分

解决方案 »

  1.   

    TO:Tdxdy(网事如风)
    是用了多线程,两种模型,一种是对每个终端都建立一个线程,这时带宽能够达到150M都还正常,再高就不行了。另一种是对每个终端建立一个线程,在线程中建立SOCKET,SOCKET建立好后加入链表线程就结束,另有专门线程控制链表内的所有SOCKET的通信,有收有发。我已经设置UDP SOCKET非阻塞了。这种模型就是到5、60M带宽时,其他网络程序就连不上服务器了?怀疑是资源问题,又不能确定在哪里?或者模型有问题?
      

  2.   

    100M bit换算为byte需要除以8
      

  3.   

    oyljerry(☆勇敢的心☆-Paper Reviewing) 
    我说的就是bps,单位是统一的,因此我一直莫名其妙啊
      

  4.   

    我觉得像模型的问题。
    系统CPU利用20%,内存20%。并不高啊。
    是不是由于你用专门线程控制链表内的所有SOCKET的通信,使它是轮巡、或则排队的原因?
    按道理即使这样也不该有带宽限制,纳闷中……
    难道是收、发各占一半带宽??
      

  5.   

    主要是发,占99%,收只占1%,下载服务,收几个字节的命令,发几K的数据,但每次调用发送sendto的时候,都调用一次接收recvfrom,不管有没有数据都立即返回,因为我是非阻塞的
      

  6.   

    而且,当服务器带宽在50M以内(或者SOCKET在200个以内)时,每个连接的终端的接收流量是连续稳定的,而超过这个值,从终端来看,接收流量就时断时续了,3秒100Kbps,1秒0,又3秒100Kbps
      

  7.   

    1.首先如果用户数量超过了200 建立多线程是不现实的,建议用 链表后者是数组;
    2.建议每个UDP的CLIENT 都 CONNECT(虽然不用connet()但connect()后可假定
    有一条虚拟连接);
    3.用setsockopt()设置每个socket的缓冲区大小,而且用非阻塞模型;
    4."另有专门线程控制链表内的所有SOCKET的通信" 不知道你的这句话的意思,你是开一个线程
    处理如此过的I/O?(可以考虑分64个为一组,开一个线程)你的程序问题就应该在这里要优化!
      

  8.   

    谢谢 gdy119(夜风微凉) 
           1.首先如果用户数量超过了200 建立多线程是不现实的,建议用 链表后者是数组;
    是的,因此我们放弃了方案1,而改用方案2,用链表。
          2.建议每个UDP的CLIENT 都 CONNECT(虽然不用connet()但connect()后可假定有一条虚拟连接);
    不知道有哪些优点,我们考虑试试。
          3.用setsockopt()设置每个socket的缓冲区大小,而且用非阻塞模型;
    我们是这样做的,
          4."另有专门线程控制链表内的所有SOCKET的通信" 不知道你的这句话的意思,你是开一个线程
    处理如此过的I/O?(可以考虑分64个为一组,开一个线程)你的程序问题就应该在这里要优化!
    就是说整个程序用一个专门的线程来轮循控制各个SOCKET的收发,。也考虑过50个一组,每组用一个线程,一个链表,但还是到50M,200个SOCKET就阻塞了,我也觉得应该在这里优化,但摸不着头脑啊!
      

  9.   

    3. 我说的setsocopt()不知道你是怎么用的,如果发送的数据量(一次)很小<1K,可以
    在服务器上做如下操作:
    //如果在发送数据的时,希望不经历由系统缓冲区到socket缓冲区的拷贝而影响
    //程序的性能:
    int nZero=0;
    setsockopt(socket,SOL_S0CKET,SO_SNDBUF,(char *)&nZero,sizeof(nZero));
    int nZero=0;
    setsockopt(socket,SOL_S0CKET,SO_RCVBUF,(char *)&nZero,sizeof(int));
    // 发送数据时候一般是系统缓冲区满以后才发送,现在设置为只要系统
    //缓冲区有数据就立刻发送:
    SetSockOpt(s,IPPROTO_TCP,TCP_NODELAY,(const char*)&bNodelayt,sizeof(BOOL));
    4.如果你程序代码没什么问题,那我要考虑你系统,网卡(所有硬件设备)可能是它们
    引起的瓶颈。
      

  10.   

    我分析一下你说的,50M ,200 client ,也就是每个client占用的带宽约为:256K
    你的每个client 发送的数据包有多大? UDP 每次发送数据包的最大限制为64k,按照
    这个极限考虑最少也应该有800个client 连接,所以我敢肯定,是你服务器的问题,
    也就是服务器处理数据不及时,所以你线程处理是怎么处理I/O(循环接受,肯定错误)程序的瓶颈!!
      

  11.   

    To: gdy119(夜风微凉) 
    我每次发送的数据不到1500字节,因考虑到MTU的限制,大约1400字节。对setsockopt,我是这样用的:
    int nSnd=32768;
    setsockopt(socket,SOL_S0CKET,SO_SNDBUF,(char *)&nSnd,sizeof(nSnd));
    setsockopt(socket,SOL_S0CKET,SO_RCVBUF,(char *)&nSnd,sizeof(nSnd));
    SetSockOpt(s,IPPROTO_TCP,TCP_NODELAY,(const char*)&bNodelayt,sizeof(BOOL));
    而且硬件设备肯定不是造成这种现象的原因
    经你的提醒,我现在怀疑是否是因为我的非阻塞模型用的不对。希望夜风微凉兄继续点播,谢谢!
      

  12.   

    也就是服务器处理数据不及时,所以你线程处理是怎么处理I/O(循环接受,肯定错误)程序的瓶颈!!
    ----------
    夜风微凉兄高见。我确实是循环接收的,因为我不确定终端什么时候给服务器发数据啊。流程如下:
    for(;;)
    {
       p=first;
       while(p=p->next)
       {
         p->sock.recvfrom(...);
         bool bsend=    ......//根据接收的命令数据判断是否需要发送
         if(bsend)
         {
            p->sock.sendto(...);
         }
       }
    }
      

  13.   

    我个人认为你下面要做的两件事情:
    1.
    /*int nSnd=32768;//(32K)
    setsockopt(socket,SOL_S0CKET,SO_SNDBUF,(char *)&nSnd,sizeof(nSnd));
    setsockopt(socket,SOL_S0CKET,SO_RCVBUF,(char *)&nSnd,sizeof(nSnd));
    SetSockOpt(s,IPPROTO_TCP,TCP_NODELAY,(const char*)&bNodelayt,sizeof(BOOL));*/
    改为我说的(因为你数据只有1K左右):
    int nZero=0;
    setsockopt(socket,SOL_S0CKET,SO_SNDBUF,(char *)&nZero,sizeof(nZero));
    setsockopt(socket,SOL_S0CKET,SO_RCVBUF,(char *)&nZero,sizeof(int));
    2.修改处理I/O的代码,如果你是UNIX ,LINUIX,平台,立即改为select()模型
    判断是否有数据可读;如果是WIN32 平台,改为overlapped+WSAeventselect 或者
    是IOCP(完成端口)
      

  14.   

    还是gdy119(夜风微凉) 兄牛啊。
      

  15.   

    gdy119(夜风微凉) 兄:
    对于第1点,我试过,改动没有效果;
    对于第2点,因为我要控制每个信道的传输,不能太饱,也不能太饿,而采用select()模型我不便于控制。因此没有采用select模式,还请gdy119(夜风微凉) 兄继续指教,谢谢!
      

  16.   

    你用的是非阻塞模型吗? 是建立socket的时候进行了如下设置:
    //设置非阻塞方式连接
    unsigned long ul = 1;
    ret = ioctlsocket(cClient, FIONBIO, (unsigned long*)&ul);
    if(ret==SOCKET_ERROR)return 0;
    如果是,但后面你用了:
    for(;;)
    {
       p=first;
       while(p=p->next)
       {
         p->sock.recvfrom(...);
         bool bsend=    ......//根据接收的命令数据判断是否需要发送
         if(bsend)
         {
            p->sock.sendto(...);
         }
       }
    }
    这个阻塞模式的接受数据的方式,不是自相矛盾吗?
    你要知道阻塞模式的方式,recv(),或send()不到数据的时候是要将线程挂起的,
    浪费的资源和开销是很大的!
      

  17.   

    确实如gdy119(夜风微凉)兄所言,我是通过unsigned long ul = 1;
    ret = ioctlsocket(cClient, FIONBIO, (unsigned long*)&ul);设置为非阻塞模型的,而且后面用了
    个阻塞模式的接受数据的方式。但我考虑是接收不到就直接返回,我不期望每次都收到数据,只是应付终端不定时发来的数据。我不知道“阻塞模式的方式,recv(),或send()不到数据的时候是要将线程挂起的,浪费的资源和开销是很大的!”,recv()不到数据的时候线程会挂起,能具体些吗?你认为我用什么模式来处理更好些呢?再次感谢夜风微凉兄.