Winsock服务器内存资源管理

转载 2015年07月08日 11:52:56
 一般来讲, 在服务器上,如果有足够的资源,Winsock server,理论上可以支持成千的并发连接。而现实是,我们没有足够的资源可供使用,分配。本文主要来讨论一下内存资源之于Winsock server开发的重要性。
一)基本概念。
-> Pages,Locked Pages.
        在现代操作系统中,内存管理会把主存(RAM)分成Pages来管理。 Paging(或者swapping)指的是主存与外存之间以Page为单位进行数据的交换。Locked Pages指的是被锁定在主存中的内存页,以保证一些内核组件,driver可以访问到它们。windows一定会保证一定数量的可交换的内存空间,防止一些非法程序锁定所有的物理内存,而致使系统崩溃。在windows NT, windows 2000上,可锁定的内存总的大小上限大概是物理内存的1/8(当然对于程序的开发人员,不应该对这个值进行任何的假设,这个值可能会随着操作系统本版的变化而变化)。在Winsock应用开发过程中,以overlapped方式读写IO操作,将会导致内存被锁定。
-> working set
        在程序开始运行,并达到其稳定的运行状态(主要指的是其对内存的使用),在这个状态下,程序使用内存的数量一般小于其需要使用内存的总量。这样一个稳定的运行状态,我们可以称为working set: 被该程序频繁访问的内存页的集合。在windows上,你可以使用SetWorkingSetSize Win32 API来增加程序使用物理内存的数量。
-> non-paged pool
       不可交换的内存。这主要指以non-paged的方式分配的内存,这些内存就像locked pages一样,是从来不会被交换出去的,用来存放一些由内核组件,driver访问的信息。 在Winsock应用开发过程中,以下的操作可能导致分配non-paged内存。
1) 调用系统一些系统的API,例如打开文件,create socket,等,都会导致从non-paged pool分配内存。
2) 一些driver可以显式地从该区域分配内存。
二) Winsock server上Locked Pages使用。
        我们提到过,任何的overlapped IO操作,都会导致锁定内存页。这些内存页一旦被locked,就不会被交换出去。我们知道,windows操作系统对最大的可锁定内存页做了一个上限,如果超出这个上限,overlapped IO调用将会导致WSAENOBUFS错误。
        考虑下面的情况,如果server在每个连接上会发出很多的overlapped receives操作,那么,随着连接数目的增多,很明显,被锁定的内存数量很有可能达到上限而导致WSAENOBUFS错误。在这种情况下,如果服务器预期会处理大数量的客户端连接,则需要服务器在每个连接上发出zero-byte buffer的overlapped接收请求(这种情况下,因为the size of buffer is zero,所以没有任何内存被锁定),一旦overlapped接收操作完成,server可以以non-blocking方式执行receive操作,以取得所有缓存在so_rcvbuf中的数据,直到返回WSAEWOULDBLOCK为止。
        另外需要注意的是,windows在page的边界上对内存进行锁定,在x86平台上,它是4kb的整数倍。所以,假如你post了一个1 KB buffer,而系统真实锁定的是4 KB 的大小,为了避免这样的浪费,尽量用4kb的整数做overlapped  IO操作。
三) Winsock server上non-paged pool使用。
        同Locked Pages限制一样,windows对non-paged pool也有一个最大的限制。并且,当你的应用出现这个问题的时候,超出它的最大限制数,情况要远比Locked Pages复杂。这种情况下,后果是不确定的,有可能你的Winsock调用返回WSAENOBUFS错误,也有可能,在系统中,一个和你的应用毫无关联的driver由于申请不到non-paged内存而致使system crash。而这样的灾难,是没法恢复的。
        考虑一个具体的例子:我们假设在windows2000上,系统有1 GB内存。这样的配置下,windows大概会预留1/4的空间用作non-paged pool(同样,对于程序的开发人员,不应该对这个值进行任何的假设),即:256MB。这样的配置下,保守估计,我们的Winsock server能够处理到大概50,000连接,或者更多。(每个accepted socket大概消耗1.5kb,每个连接上post一个overlapped操作,分配一个IRP,大概需要500 byte, 总计:(1500+500)*50,000 = 100 Mb) 。
       无论是对于Locked Pages,还是对于non-paged pool使用,一旦超出了上限,Winsock调用仅仅会返回一般的WSAENOBUFS 或者ERROR_INSUFFICIENT_RESOURCES错误。为了处理这些错误,你可以试试以下的方法:
1) 需要首先调用SetWorkingSetSize,增加应用的可支配资源数,看能否解决。
2)     确信你的应用没有做出太多的overlapped  IO操作。
3) 关闭一些连接数。
四) SOCKET的缓冲区设置问题。

         Winsock在默认的情况下,每个socket都会与一个send和receive buffer相关联。你可以通过调用setsockopt来设置buffer的大小。
        在缓冲区没有被关闭的情况下,我们看看overlapped send和revc是怎么工作的。
        当上层的应用做出了send调用,而这时如果send buffer还有剩余的空间,那么数据将会从用户提交的buffer复制到send buffer中,然后调用返回成功。否则,假如这时send buffer已满,用户提交的buffer将会被锁定,并且调用返回WSA_IO_PENDING。当send buffer的数据被下层的tcp处理完成,winsock将直接处理用户提交的buffer里的数据,而不需要再复制。
        同样,对于recv操作,如果数据已经被缓存在socket的receive buffer里,当发生recv调用的时候,数据将直接从socket的receive buffer复制到用户的buffer里,recv调用返回成功。否则,假如发生调用时receive buffer里没有数据,用户提交的buffer将会被锁定,recv调用返回WSA_IO_PENDING。当数据到达当前连接,将会被直接复制到用户提交的buffer里。
        一个应用程序通过设定send buffer为0,把缓冲区关闭,然后发出一个阻塞send()调用。在这样的情况下,系统内核会把应用程序的缓冲区锁定,直到接收方确认收到了整个缓冲区后send()调用才返回。似乎这是一种判定你的数据是否已经为对方全部收到的简洁的方法,实际上却并非如此。想想看,即使远端tcp通知数据已经收到,其实也根本不代表数据已经成功送给客户端应用程序,比如对方可能发生资源不足的情况,导致afd.sys不能把数据拷贝给应用程序。另一个更要紧的问题是,在每个线程中每次只能进行一次发送调用,效率极其低下。 
        另外,希望通过关闭Winsock缓冲区,从而避免数据复制,达到优化性能的目的,也是不可取的。从上面,我们看到:只要应用保证适量的,足够的send, recv调用,这样的复制是完全可以避免的。
        高性能的服务器应用程序可以关闭发送缓冲区,同时不会损失性能。不过,这样的应用程序必须十分小心,保证它总是发出多个重叠发送调用,而不是等待某个重叠发送结束了才发出下一个。如果应用程序是按一个发完再发下一个的顺序来操作,那浪费掉两次发送中间的空档时间,总之是要保证传输驱动程序在发送完一个缓冲区后,立刻可以转向另一个缓冲区。

        如果关闭了recv buffer,在你的应用没有保证足够的recv操作前提下,任何进来数据,必须在TCP层进行缓存,最大缓存的数量将取决于tcp windows的大小(17Kb)。而最为严重的是这些缓存是从non-paged pool分配而来。如上所述,non-paged pool是非常珍贵,稀缺的内存。所以,从这个意义上来讲,关闭了recv buffer操作是不可取的。


http://www.cppblog.com/sherrylso/archive/2008/02/03/42454.html

Windows Sockets 2.0:使用完成端口高性能,可扩展性Winsock服务程序

 Windows Sockets 2.0:使用完成端口高性能,可扩展性Winsock服务程序原作者:    APIs 完成端口( 典型的 Windows NT 缓...
  • wzsy
  • wzsy
  • 2007年05月31日 15:03
  • 1193

Winsock使用之Winsock服务器程序

创建服务器Socket(Creating a Socket for the Server) 初始化以后,SOCKET对象必须由服务器实例化 1.getaddrinfo函数用于确定sockaddr结构体...
  • zhuxipan1990
  • zhuxipan1990
  • 2016年08月02日 21:44
  • 180

Winsock服务器内存资源管理

        一般来讲, 在服务器上,如果有足够的资源,Winsock server,理论上可以支持成千的并发连接。而现实是,我们没有足够的资源可供使用,分配。本文主要来讨论一下内存资源之于Wins...
  • jaskist
  • jaskist
  • 2008年06月19日 15:37
  • 366

Winsock服务器内存资源管理(转)

一般来讲, 在服务器上,如果有足够的资源,Winsock server,理论上可以支持成千的并发连接。而现实是,我们没有足够的资源可供使用,分配。本文主要来讨论一下内存资源之于Winsock serv...
  • Jans
  • Jans
  • 2009年02月21日 02:36
  • 1239

开始Winsock编程-简单的TCP服务器端

简介     WinSock (Windows Sockets) API是微软操作系统的socket可编程库,起先是基于Berkeley sockets的.后来引入了微软自己的特点. 在这边文章中我将...
  • zhurui536
  • zhurui536
  • 2012年11月21日 16:59
  • 1224

Yarn 资源管理

环境说明:HDP2.5 + Ambari 在linux centos6上搭建的集群 一、Yarn 资源管理简述:yarn默认提供了两种调度规则,capacity scheduler和fair sche...
  • u013850277
  • u013850277
  • 2017年11月07日 21:20
  • 136

Winsock2.2 隐藏真实IP地址

【内容摘要】一、前言本文主要介绍如何在程序中实现ip地址的隐藏。其实这篇东西不算我写的。其中《ip头结构》部分我懒得打字,故复制、粘贴了孤独剑客的文章,先说声谢谢!代码部分参考了外国程序xes写的一个...
  • suwenkui
  • suwenkui
  • 2011年03月08日 14:34
  • 758

服务器的资源管理器显示进程占用内存不多,性能里内存爆满

最近公司的一个服务器非常卡顿,打开服务器的资源管理器显示进程占用不多,但性能里内存爆满,32G运行内存用了31G,资源管理器显示占用最大的 javaw.exe和数据库都是1点多G,所有的加起来应该也不...
  • u014772219
  • u014772219
  • 2017年07月26日 12:39
  • 1217

Winsock属性、方法介绍

Winsock是Mcrosoft windows提供的网络编程接口,它供了基于TCP/IP协议接口实现方法.通过网络进行的数据通信,需要用地址来表示网络中的主机.TCP/IP协议使用IP地址来作为主机...
  • wwwdbs
  • wwwdbs
  • 2008年03月20日 10:01
  • 4177

[译文] Winsock API实现了一个Tcp服务器 - for 初学者

 [译文] Winsock API实现了一个Tcp服务器 - for 初学者来源:http://www.codeproject.com/internet/winsockintro01.asp(一)介绍...
  • soldier3
  • soldier3
  • 2005年07月21日 13:13
  • 560
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Winsock服务器内存资源管理
举报原因:
原因补充:

(最多只允许输入30个字)