为 Web页指定 DOCTYPE 会影响浏览器呈现页的方式。Internet Explorer、Mozilla Firefox 和 Opera 全都支持一种名为“DOCTYPE 切换”(也叫“DOCTYPE 嗅探”)的功能。

引入 DOCTYPE 切换的目的是使浏览器能够正确地呈现符合标准的 Web 站点以及旧式 Web 站点。大多数 Web 站点被开发为呈现 HTML 页而不是 XHTML 页。浏览器通过判断是否存在 DOCTYPE 来确定何时应该使用标准来呈现页。

Internet Explorer 6+ 支持两种呈现模式,分别叫做 Quirks 模式和 Standards 模式。当 Internet Explorer 呈现包含有效 XHTML(或 HTML 4.0)DOCTYPE 的页时,它会以 Standards 模式呈现该页;否则,它会以 Quirks模式呈现该页

Opera 浏览器 (Opera 7+) 支持与 Internet Explorer 相同的两种呈现模式:Quirks 和 Standards

Mozilla Firefox 1+ 支持三种呈现模式:Quirks 模式、Almost Standards 模式和 Standards 模式。Firefox 的 Almost Standards 模式对应于 Internet Explorer 和 Opera 的 Standards 模式。当页包含有效的 XHTML 1.0 Transitional DOCTYPE(并且该页被分配为 text/html MIME 类型)时,Firefox 会以 Almost Standards 模式呈现该页。当页包含 XHTML 1.0 Strict 或 XHTML 1.1 DOCTYPE(或者该页被分配为 XML MIME 类型)时,该页将以 Standards 模式呈现

可以通过临时向页中添加以下客户端脚本(该脚本在最新版本的 Internet Explorer、Firefox 和 Opera 中有效)确定浏览器的当前呈现模式。

alert( document.compatMode );

您需要关心浏览器的呈现模式,因为它会影响将层叠样式表应用于该页的方式。如果将现有 HTML 页转换为 XHTML 页,那么在浏览器中打开它们时,它们可能看起来非常不同。

例如,Internet Explorer 以不同方式计算页元素的大小,这取决于呈现模式(它使用不同的 CSS Box Model)。在 Quirks 模式下,元素的宽度是通过将元素的内容、内边距、边框和边距相加而计算得到的。在 Standards 模式下,元素的宽度是只考虑元素内容的宽度而计算得到的。

首席执行官【CEO】 美国人在20世纪60年代进行公司治理结构改革创新时的产物、它的出现在某种意义上代表着将原来董事会手中一些决策权过渡到经营层手中、CEO概念最早出现在一些网络企业。在那里CEO往往是自封的、也很少有人去研究这一称谓对企业到底意味着什么。但是,当“CEO”在中国叫得越来越响时候、高层人员称谓改变不是一件小事、设立CEO职位不仅仅是对时尚追赶。事实上,CEO做的事情重点在于“执行”。大多数中国公司往往CEO做的事情恰恰不是“执行”,更像是“董事长”。 首席财政官或财务总监【CFO】 现代公司中最重要、最有价值顶尖管理职位之一、掌握着企业神经系统(财务信息)和血液系统(现金资源)灵魂人物。做一名成功CFO需要具备丰富金融理论知识和实务经验。公司理财与金融市场交互、项目估价、风险管理、产品研发、战略规划、企业核心竞争力识别与建立及洞悉信息技术及电子商务对企业冲击等都是CFO职责范围内事。大型公司运作中CFO是穿插在金融市场操作和公司内部财务管理之间角色。担当CFO人才大多是拥有多年在金融市场驰骋经验的人。在美国优秀的CFO常常在华尔街做过成功基金经理人。 首席营运官【COO】 负责公司日常营运、辅助CEO工作。一般来讲COO负责公司职能管理组织体系建设、并代表CEO处理企业日常职能事务。如公司未设有总裁职务则COO还要承担整体业务管理职能、主管企业营销与综合业务拓展、负责建立公司整个销售策略与政策、组织生产经营、协助CEO制定公司业务发展计划、对公司经营绩效进行考核。也有把运营总监称呼为COO的。 首席市场官【CMO】 指市场总监 首席技术官【CTO】 技术总监 销售总监【CSO】 渠道销售总监 公关总监【CPO】 政府事务、媒体、重要公司与人物公共关系,主要是搞定人。 首席信息官【CIO】 大多数公司把这个职位变成了盯人盯票,有点象明朝时候的“东厂”,所以说中国是个很神奇的国家。 开发总监【CDO】 人事总监 【CHO】 首席品牌官【CBO】 首席文化官【CCO】 首席知识官【CKO】 首席谈判官【CNO】 质量总监【CQO】 评估总监【CVO】 首席发言人【CAO】 专门负责解答媒体、债权人和用户等有关问题询问。 首席商业计划官【CBO】 首席财务官助理之一、专门针对不同投资人制订相应BP。 首席成本控制官【CCO】 凡超过XXXX元以上支出必须由CC0批准。 首席域名官【CDO】 负责公司域名注册、网站清盘时域名拍卖、域名法律纠纷等相关问题。 首席交换官【CEO】 一般由国际CEO自由联盟随时更换、常设短期职能岗位、类似足球教练。 首席方针制订官【CGO】 规划公司宏伟蓝图、一般是5年以后目标。 首席协调官【CHO】 调解投资者和经营者之间的冲突、确保公司内部矛盾不要泄露。 首席检查官【CIO】 检查公司内部工作状况、监督员工工作态度。 首席执法官【CJO】 解决内部劳资纠纷、包括员工对降薪、辞退补偿等所引起问题。 网络连接专员【CKO】 最繁忙的岗位之一、当中国电信网络连接中断时及时向员工通报。 首席律师【CLO】 负责公司被控侵权时应诉以及各种合同文本审核。主要是灭人的打手。 首席媒体官【CMO】 保持和媒体之间友好关系为公司随时发布新闻做准备,类似首席代表。 首席新闻官【CNO】 向媒体披露公司被黑、裁员、被收购等重大新闻。一般由公司市场总监担任,类似政府部门新闻发言人,主要由司长级部门领导担任,公司声音的统一出口。 首席隐私官【CPO】 负责公司内部员工Email、ICQ、OICQ等通信内容监控。 数量指标编造专家【CQO】 负责注册用户数量、页面浏览、营业收入等指标编造。 首席裁员官【CRO】 负责与裁员有关事务、直接向股东大会负责、包括董事长在内都不得干预工作。 首席战略官【CSO】 由已经退位公司主要创建人担任,在政府机关一般称为调研员或顾问。 首席联盟官【CUO】 以战略联盟名义专门寻找有收购自己意向的公司。 投资者关系【CVO】 首席财务官另一重要助理。 首席网络写手【CWO】 负责将小事扩大化、通过炒作达到扩大公司名度目的,御用文人,比如给陈天桥,史玉柱编故事,造神。 形象代言人【CXO】 (中国特有)一般由学历不高且没有什么网络知识的年轻人担任。 公司元老【CYO】 荣誉称号授予在公司工作满X年员工(通常空缺)。

**1.closesocket(一般不会立即关闭而经历TIME_WAIT的过程)后想继续重用该socket: BOOL bReuseaddr=TRUE; setsockopt(s,SOL_SOCKET ,SO_REUSEADDR,(const char)&bReuseaddr,sizeof(BOOL)); 2. 如果要已经处于连接状态的soket在调用closesocket后强制关闭,不经历 TIME_WAIT的过程: BOOL bDontLinger = FALSE; setsockopt(s,SOL_SOCKET,SO_DONTLINGER,(const char)&bDontLinger,sizeof(BOOL)); **3.**在send(),recv()过程中有时由于网络状况等原因,发收不能预期进行,而设置收发时限: int nNetTimeout=1000;//1秒 //发送时限 setsockopt(socket,SOL_S0CKET,SO_SNDTIMEO,(char )&nNetTimeout,sizeof(int)); //接收时限 setsockopt(socket,SOL_S0CKET,SO_RCVTIMEO,(char )&nNetTimeout,sizeof(int)); **4.**在send()的时候,返回的是实际发送出去的字节(同步)或发送到socket缓冲区的字节 (异步);系统默认的状态发送和接收一次为8688字节(约为8.5K);在实际的过程中发送数据 和接收数据量比较大,可以设置socket缓冲区,而避免了send(),recv()不断的循环收发: //接收缓冲区 int nRecvBuf=321024;//设置为32K setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char)&nRecvBuf,sizeof(int)); //发送缓冲区 int nSendBuf=321024;//设置为32K setsockopt(s,SOL_SOCKET,SO_SNDBUF,(const char)&nSendBuf,sizeof(int)); 5. 如果在发送数据的时,希望不经历由系统缓冲区到socket缓冲区的拷贝而影响 程序的性能: int nZero=0; setsockopt(socket,SOL_S0CKET,SO_SNDBUF,(char *)&nZero,sizeof(nZero)); **6.**同上在recv()完成上述功能(默认情况是将socket缓冲区的内容拷贝到系统缓冲区): int nZero=0; setsockopt(socket,SOL_S0CKET,SO_RCVBUF,(char *)&nZero,sizeof(int)); **7.*一般在发送UDP数据报的时候,希望该socket发送的数据具有广播特性: BOOL bBroadcast=TRUE; setsockopt(s,SOL_SOCKET,SO_BROADCAST,(const char)&bBroadcast,sizeof(BOOL)); **8.在client连接服务器过程中,如果处于非阻塞模式下的socket在connect()的过程中可 以设置connect()延时,直到accpet()被呼叫(本函数设置只有在非阻塞的过程中有显著的 作用,在阻塞的函数调用中作用不大) BOOL bConditionalAccept=TRUE; setsockopt(s,SOL_SOCKET,SO_CONDITIONAL_ACCEPT,(const char)&bConditionalAccept,sizeof(BOOL)); 9.如果在发送数据的过程中(send()没有完成,还有数据没发送)而调用了closesocket(),以前我们 一般采取的措施是"从容关闭"shutdown(s,SD_BOTH),但是数据是肯定丢失了,如何设置让程序满足具体 应用的要求(即让没发完的数据发送出去后在关闭socket)? struct linger { u_short l_onoff; u_short l_linger; }; linger m_sLinger; m_sLinger.l_onoff=1;//(在closesocket()调用,但是还有数据没发送完毕的时候容许逗留) // 如果m_sLinger.l_onoff=0;则功能和2.)作用相同; m_sLinger.l_linger=5;//(容许逗留的时间为5秒) setsockopt(s,SOL_SOCKET,SO_LINGER,(const char)&m_sLinger,sizeof(linger));

linux 套接字选项定义(二)

设置套接口的选项。 #include <winsock.h> int PASCAL FAR setsockopt( SOCKET s, int level, int optname, const char FAR* optval, int optlen); s:标识一个套接口的描述字。 level:选项定义的层次;目前仅支持SOL_SOCKET和IPPROTO_TCP层次。 optname:需设置的选项。 optval:指针,指向存放选项值的缓冲区。 optlen:optval缓冲区的长度。 注释: setsockopt()函数用于任意类型、任意状态套接口的设置选项值。尽管在不同协议层上存在选项,但本函数仅定义了最高的“套接口”层次上的选项。选项影响套接口的操作,诸如加急数据是否在普通数据流中接收,广播数据是否可以从套接口发送等等。 有两种套接口的选项:一种是布尔型选项,允许或禁止一种特性;另一种是整形或结构选项。允许一个布尔型选项,则将optval指向非零整形数;禁止一个选项optval指向一个等于零的整形数。对于布尔型选项,optlen应等于sizeof(int);对其他选项,optval指向包含所需选项的整形数或结构,而optlen则为整形数或结构的长度。SO_LINGER选项用于控制下述情况的行动:套接口上有排队的待发送数据,且closesocket()调用已执行。参见closesocket()函数中关于SO_LINGER选项对closesocket()语义的影响。应用程序通过创建一个linger结构来设置相应的操作特性: struct linger { int l_onoff; int l_linger; }; 为了允许SO_LINGER,应用程序应将l_onoff设为非零,将l_linger设为零或需要的超时值(以秒为单位),然后调用setsockopt()。为了允许SO_DONTLINGER(亦即禁止SO_LINGER),l_onoff应设为零,然后调用setsockopt()。 缺省条件下,一个套接口不能与一个已在使用中的本地地址捆绑(参见bind())。但有时会需要“重用”地址。因为每一个连接都由本地地址和远端地址的组合唯一确定,所以只要远端地址不同,两个套接口与一个地址捆绑并无大碍。为了通知WINDOWS套接口实现不要因为一个地址已被一个套接口使用就不让它与另一个套接口捆绑,应用程序可在bind()调用前先设置SO_REUSEADDR选项。请注意仅在bind()调用时该选项才被解释;故此无需(但也无害)将一个不会共用地址的套接口设置该选项,或者在bind()对这个或其他套接口无影响情况下设置或清除这一选项。 一个应用程序可以通过打开SO_KEEPALIVE选项,使得WINDOWS套接口实现在TCP连接情况下允许使用“保持活动”包。一个WINDOWS套接口实现并不是必需支持“保持活动”,但是如果支持的话,具体的语义将与实现有关,应遵守RFC1122“Internet主机要求-通讯层”中第4.2.3.6节的规范。如果有关连接由于“保持活动”而失效,则进行中的任何对该套接口的调用都将以WSAENETRESET错误返回,后续的任何调用将以WSAENOTCONN错误返回。 TCP_NODELAY选项禁止Nagle算法。Nagle算法通过将未确认的数据存入缓冲区直到蓄足一个包一起发送的方法,来减少主机发送的零碎小数据包的数目。但对于某些应用来说,这种算法将降低系统性能。所以TCP_NODELAY可用来将此算法关闭。应用程序编写者只有在确切了解它的效果并确实需要的情况下,才设置TCP_NODELAY选项,因为设置后对网络性能有明显的负面影响。TCP_NODELAY是唯一使用IPPROTO_TCP层的选项,其他所有选项都使用SOL_SOCKET层。 如果设置了SO_DEBUG选项,WINDOWS套接口供应商被鼓励(但不是必需)提供输出相应的调试信息。但产生调试信息的机制以及调试信息的形式已超出本规范的讨论范围。 setsockopt()支持下列选项。其中“类型”表明optval所指数据的类型。 选项        类型   意义 SO_BROADCAST BOOL允许套接口传送广播信息。 SO_DEBUG BOOL记录调试信息。 SO_DONTLINER BOOL不要因为数据未发送就阻塞关闭操作。设置本选项相当于将SO_LINGER的l_onoff元素置为零。 SO_DONTROUTE BOOL禁止选径;直接传送。 SO_KEEPALIVE BOOL发送“保持活动”包。 SO_LINGER struct linger FAR*  如关闭时有未发送数据,则逗留。 SO_OOBINLINE BOOL在常规数据流中接收带外数据。 SO_RCVBUF int为接收确定缓冲区大小。 SO_REUSEADDR BOOL允许套接口和一个已在使用中的地址捆绑(参见bind())。 SO_SNDBUF int指定发送缓冲区大小。 TCP_NODELAY BOOL禁止发送合并的Nagle算法。 setsockopt()不支持的BSD选项有: 选项名    类型 意义 SO_ACCEPTCONN BOOL套接口在监听。 SO_ERROR int获取错误状态并清除。 SO_RCVLOWAT int接收低级水印。 SO_RCVTIMEO int接收超时。 SO_SNDLOWAT int发送低级水印。 SO_SNDTIMEO int发送超时。 SO_TYPE     int套接口类型。 IP_OPTIONS   在IP头中设置选项。 返回值: 若无错误发生,setsockopt()返回。否则的话,返回SOCKET_ERROR错误,应用程序可通过WSAGetLastError()获取相应错误代码。 错误代码: WSANOTINITIALISED:在使用此API之前应首先成功地调用WSAStartup()。 WSAENETDOWN:WINDOWS套接口实现检测到网络子系统失效。 WSAEFAULT:optval不是进程地址空间中的一个有效部分。 WSAEINPROGRESS:一个阻塞的WINDOWS套接口调用正在运行中。 WSAEINVAL:level值非法,或optval中的信息非法。 WSAENETRESET:当SO_KEEPALIVE设置后连接超时。 WSAENOPROTOOPT:未知或不支持选项。其中,SOCK_STREAM类型的套接口不支持SO_BROADCAST选项,SOCK_DGRAM类型的套接口不支持SO_DONTLINGER 、SO_KEEPALIVE、SO_LINGER和SO_OOBINLINE选项。 WSAENOTCONN:当设置SO_KEEPALIVE后连接被复位。 WSAENOTSOCK:描述字不是一个套接口。 参见: bind(), getsockopt(), ioctlsocket(), socket(), WSAAsyncSelect().

原文地址    http://www.ibm.com/developerworks/cn/linux/l-hisock.html 在开发 socket 应用程序时,首要任务通常是确保可靠性并满足一些特定的需求。利用本文中给出的 4 个提示,您就可以从头开始为实现最佳性能来设计并开发 socket 程序。本文内容包括对于 Sockets API 的使用、两个可以提高性能的 socket 选项以及 GNU/Linux 优化。 为了能够开发性能卓越的应用程序,请遵循以下技巧:

  • 最小化报文传输的延时。
  • 最小化系统调用的负载。
  • 为 Bandwidth Delay Product 调节 TCP 窗口。
  • 动态优化 GNU/Linux TCP/IP 栈。

技巧 1. 最小化报文传输的延时 在通过 TCP socket 进行通信时,数据都拆分成了数据块,这样它们就可以封装到给定连接的 TCP payload(指 TCP 数据包中的有效负荷)中了。TCP payload 的大小取决于几个因素(例如最大报文长度和路径),但是这些因素在连接发起时都是已知的。为了达到最好的性能,我们的目标是使用尽可能多的可用数据来填充 每个报文。当没有足够的数据来填充 payload 时(也称为_最大报文段长度(maximum segment size)_ 或 MSS),TCP 就会采用 Nagle 算法自动将一些小的缓冲区连接到一个报文段中。这样可以通过最小化所发送的报文的数量来提高应用程序的效率,并减轻整体的网络拥塞问题。 尽管 John Nagle 的算法可以通过将这些数据连接成更大的报文来最小化所发送的报文的数量,但是有时您可能希望只发送一些较小的报文。一个简单的例子是 telnet 程序,它让用户可以与远程系统进行交互,这通常都是通过一个 shell 来进行的。如果用户被要求用发送报文之前输入的字符来填充某个报文段,那么这种方法就绝对不能满足我们的需要。 另外一个例子是 HTTP 协议。通常,客户机浏览器会产生一个小请求(一条 HTTP 请求消息),然后 Web 服务器就会返回一个更大的响应(Web 页面)。 解决方案 您应该考虑的第一件事情是 Nagle 算法满足一种需求。由于这种算法对数据进行合并,试图构成一个完整的 TCP 报文段,因此它会引入一些延时。但是这种算法可以最小化在线路上发送的报文的数量,因此可以最小化网络拥塞的问题。 但是在需要最小化传输延时的情况中,Sockets API 可以提供一种解决方案。要禁用 Nagle 算法,您可以设置 TCP_NODELAY socket 选项,如清单 1 所示。

int sock, flag, ret; /* Create new stream socket */ sock = socket( AF_INET, SOCK_STREAM, 0 ); /* Disable the Nagle (TCP No Delay) algorithm */ flag = 1; ret = setsockopt( sock, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag) ); if (ret == -1) { printf(“Couldn’t setsockopt(TCP_NODELAY)\n”); exit(-1); }

技巧 2. 最小化系统调用的负载 任何时候通过一个 socket 来读写数据时,您都是在使用一个_系统调用(system call)。这个调用(例如 readwrite)跨越了用户空间应用程序与内核的边界。另外,在进入内核之前,您的调用会通过 C 库来进入内核中的一个通用函数(system_call())。从 system_call() 中,这个调用会进入文件系统层,内核会在这儿确定正在处理的是哪种类型的设备。最后,调用会进入 socket 层,数据就是在这里进行读取或进行排队从而通过 socket 进行传输的(这涉及数据的副本)。 这个过程说明系统调用不仅仅是在应用程序和内核中进行操作的,而且还要经过应用程序和内核中的很多层次。这个过程耗费的资源很高,因此调用次数越多,通过这个调用链进行的工作所需要的时间就越长,应用程序的性能也就越低。 由于我们无法避免这些系统调用,因此惟一的选择是最小化使用这些调用的次数。幸运的是,我们可以对这个过程进行控制。 解决方案 在将数据写入一个 socket 时,尽量一次写入所有的数据,而不是执行多次写数据的操作。对于读操作来说,最好传入可以支持的最大缓冲区,因为如果没有足够多的数据,内核也会试图填充 整个缓冲区(另外还需要保持 TCP 的通告窗口为打开状态)。这样,您就可以最小化调用的次数,并可以实现更好的整体性能。 技巧 3. 为 Bandwidth Delay Product 调节 TCP 窗口 TCP 的性能取决于几个方面的因素。两个最重要的因素是_链接带宽(link bandwidth)(报文在网络上传输的速率)和 往返时间(round-trip time) 或 RTT(发送报文与接收到另一端的响应之间的延时)。这两个值确定了称为 Bandwidth Delay Product(BDP)的内容。 给定链接带宽和 RTT 之后,您就可以计算出 BDP 的值了,不过这代表什么意义呢?BDP 给出了一种简单的方法来计算理论上最优的 TCP socket 缓冲区大小(其中保存了排队等待传输和等待应用程序接收的数据)。如果缓冲区太小,那么 TCP 窗口就不能完全打开,这会对性能造成限制。如果缓冲区太大,那么宝贵的内存资源就会造成浪费。如果您设置的缓冲区大小正好合适,那么就可以完全利用可用的 带宽。下面我们来看一个例子: BDP = link_bandwidth * RTT 如果应用程序是通过一个 100Mbps 的局域网进行通信,其 RRT 为 50 ms,那么 BDP 就是: 100MBps * 0.050 sec / 8 = 0.625MB = 625KB **注意:**此处除以 8 是将位转换成通信使用的字节。 因此,我们可以将 TCP 窗口设置为 BDP 或 1.25MB。但是在 Linux 2.6 上默认的 TCP 窗口大小是 110KB,这会将连接的带宽限制为 2.2MBps,计算方法如下: throughput = window_size / RTT 110KB / 0.050 = 2.2MBps 如果使用上面计算的窗口大小,我们得到的带宽就是 12.5MBps,计算方法如下: 625KB / 0.050 = 12.5MBps 差别的确很大,并且可以为 socket 提供更大的吞吐量。因此现在您就知道如何为您的 socket 计算最优的缓冲区大小了。但是又该如何来改变呢? 解决方案 Sockets API 提供了几个 socket 选项,其中两个可以用于修改 socket 的发送和接收缓冲区的大小。清单 2 展示了如何使用 SO_SNDBUFSO_RCVBUF 选项来调整发送和接收缓冲区的大小。 **注意:**尽管 socket 缓冲区的大小确定了通告 TCP 窗口的大小,但是 TCP 还在通告窗口内维护了一个拥塞窗口。因此,由于这个拥塞窗口的存在,给定的 socket 可能永远都不会利用最大的通告窗口。

int ret, sock, sock_buf_size; sock = socket( AF_INET, SOCK_STREAM, 0 ); sock_buf_size = BDP; ret = setsockopt( sock, SOL_SOCKET, SO_SNDBUF, (char *)&sock_buf_size, sizeof(sock_buf_size) ); ret = setsockopt( sock, SOL_SOCKET, SO_RCVBUF, (char *)&sock_buf_size, sizeof(sock_buf_size) );

在 Linux 2.6 内核中,发送缓冲区的大小是由调用用户来定义的,但是接收缓冲区会自动加倍。您可以进行 getsockopt 调用来验证每个缓冲区的大小。

巨帧(jumbo frame)

我们还可以考虑将包的大小从 1,500 字节修改为 9,000 字节(称为巨帧)。在本地网络中可以通过设置最大传输单元(Maximum Transmit Unit,MTU)来设置巨帧,这可以极大地提高性能。

就 window scaling 来说,TCP 最初可以支持最大为 64KB 的窗口(使用 16 位的值来定义窗口的大小)。采用 window scaling(RFC 1323)扩展之后,您就可以使用 32 位的值来表示窗口的大小了。GNU/Linux 中提供的 TCP/IP 栈可以支持这个选项(以及其他一些选项)。 **提示:**Linux 内核还包括了自动对这些 socket 缓冲区进行优化的能力(请参阅下面 表 1 中的 tcp_rmemtcp_wmem),不过这些选项会对整个栈造成影响。如果您只需要为一个连接或一类连接调节窗口的大小,那么这种机制也许不能满足您的需要了。   技巧 4. 动态优化 GNU/Linux TCP/IP 栈 标准的 GNU/Linux 发行版试图对各种部署情况都进行优化。这意味着标准的发行版可能并没有对您的环境进行特殊的优化。 解决方案 GNU/Linux 提供了很多可调节的内核参数,您可以使用这些参数为您自己的用途对操作系统进行动态配置。下面我们来了解一下影响 socket 性能的一些更重要的选项。 在 /proc 虚拟文件系统中存在一些可调节的内核参数。这个文件系统中的每个文件都表示一个或多个参数,它们可以通过 cat 工具进行读取,或使用 echo 命令进行修改。清单 3 展示了如何查询或启用一个可调节的参数(在这种情况中,可以在 TCP/IP 栈中启用 IP 转发)。

[root@camus]# cat /proc/sys/net/ipv4/ip_forward 0 [root@camus]# echo “1” > /poc/sys/net/ipv4/ip_forward [root@camus]# cat /proc/sys/net/ipv4/ip_forward 1 [root@camus]#

TCP/IP 栈性能使用的可调节内核参数

可调节的参数

默认值

选项说明

/proc/sys/net/core/rmem_default

“110592”

定义默认的接收窗口大小;对于更大的 BDP 来说,这个大小也应该更大。

/proc/sys/net/core/rmem_max

“110592”

定义接收窗口的最大大小;对于更大的 BDP 来说,这个大小也应该更大。

/proc/sys/net/core/wmem_default

“110592”

定义默认的发送窗口大小;对于更大的 BDP 来说,这个大小也应该更大。

/proc/sys/net/core/wmem_max

“110592”

定义发送窗口的最大大小;对于更大的 BDP 来说,这个大小也应该更大。

/proc/sys/net/ipv4/tcp_window_scaling

“1”

启用 RFC 1323 定义的 window scaling;要支持超过 64KB 的窗口,必须启用该值。

/proc/sys/net/ipv4/tcp_sack

“1”

启用有选择的应答(Selective Acknowledgment),这可以通过有选择地应答乱序接收到的报文来提高性能(这样可以让发送者只发送丢失的报文段);(对于广域网通信来说)这个选项应该启用,但是这会增加对 CPU 的占用。

/proc/sys/net/ipv4/tcp_fack

“1”

启用转发应答(Forward Acknowledgment),这可以进行有选择应答(SACK)从而减少拥塞情况的发生;这个选项也应该启用。

/proc/sys/net/ipv4/tcp_timestamps

“1”

以一种比重发超时更精确的方法(请参阅 RFC 1323)来启用对 RTT 的计算;为了实现更好的性能应该启用这个选项。

/proc/sys/net/ipv4/tcp_mem

“24576 32768 49152”

确 定 TCP 栈应该如何反映内存使用;每个值的单位都是内存页(通常是 4KB)。第一个值是内存使用的下限。第二个值是内存压力模式开始对缓冲区使用应用压力的上限。第三个值是内存上限。在这个层次上可以将报文丢弃,从而减 少对内存的使用。对于较大的 BDP 可以增大这些值(但是要记住,其单位是内存页,而不是字节)。

/proc/sys/net/ipv4/tcp_wmem

“4096 16384 131072”

为自动调优定义每个 socket 使用的内存。第一个值是为 socket 的发送缓冲区分配的最少字节数。第二个值是默认值(该值会被 wmem_default 覆盖),缓冲区在系统负载不重的情况下可以增长到这个值。第三个值是发送缓冲区空间的最大字节数(该值会被 wmem_max 覆盖)。

/proc/sys/net/ipv4/tcp_rmem

“4096 87380 174760”

tcp_wmem 类似,不过它表示的是为自动调优所使用的接收缓冲区的值。

/proc/sys/net/ipv4/tcp_low_latency

“0”

允许 TCP/IP 栈适应在高吞吐量情况下低延时的情况;这个选项应该禁用。

/proc/sys/net/ipv4/tcp_westwood

“0”

启用发送者端的拥塞控制算法,它可以维护对吞吐量的评估,并试图对带宽的整体利用情况进行优化;对于 WAN 通信来说应该启用这个选项。

/proc/sys/net/ipv4/tcp_bic

“1”

为快速长距离网络启用 Binary Increase Congestion;这样可以更好地利用以 GB 速度进行操作的链接;对于 WAN 通信应该启用这个选项。

与任何调优努力一样,最好的方法实际上就是不断进行实验。您的应用程序的行为、处理器的速度以及可用内存的多少都会影响到这些参数影响性能的方式。 在某些情况中,您认为有益的操作可能恰恰是有害的(反之亦然)。因此,我们需要逐一试验各个选项,然后检查每个选项的结果。换而言之,我们需要相信自己的 经验,但是对每次修改都要进行验证。 **提示:**下面介绍一个有关永久性配置的问题。注意,如果您重新启动了 GNU/Linux 系统,那么您所需要的任何可调节的内核参数都会恢复成默认值。为了将您所设置的值作为这些参数的默认值,可以使用 /etc/sysctl.conf 在系统启动时将这些参数配置成您所设置的值。 GNU/Linux 工具 GNU/Linux 对我非常有吸引力,这是因为其中有很多工具可以使用。尽管其中大部分都是命令行工具,但是它们都非常有用,而且非常直观。GNU/Linux 提供了几个工具 —— 有些是 GNU/Linux 自己提供的,有些是开放源码软件 —— 用于调试网络应用程序,测量带宽/吞吐量,以及检查链接的使用情况。 表 2 列出最有用的几个 GNU/Linux 工具,以及它们的用途。表 3 列出了 GNU/Linux 发行版没有提供的几个有用工具。有关表 3 中工具的更多信息请参阅

任何 GNU/Linux 发行版中都可以找到的工具

GNU/Linux 工具

用途

ping

这是用于检查主机的可用性的最常用的工具,但是也可以用于识别带宽延时产品计算的 RTT。

traceroute

打印某个连接到网络主机所经过的包括一系列路由器和网关的路径(路由),从而确定每个 hop 之间的延时。

netstat

确定有关网络子系统、协议和连接的各种统计信息。

tcpdump

显示一个或多个连接的协议级的报文跟踪信息;其中还包括时间信息,您可以使用这些信息来研究不同协议服务的报文时间。

表 3. GNU/Linux 发行版中没有提供的有用性能工具

GNU/Linux 工具

用途

netlog

为应用程序提供一些有关网络性能方面的信息。

nettimer

为瓶颈链接带宽生成一个度量标准;可以用于协议的自动优化。

Ethereal

以一个易于使用的图形化界面提供了 tcpump(报文跟踪)的特性。

iperf

测量 TCP 和 UDP 的网络性能;测量最大带宽,并汇报延时和数据报的丢失情况。

作者:Sean Baron 你本来可能只是打算坐下来玩几分钟游戏;而过了好几个小时后,你才后知后觉地意识到自己正在扮演一个柔术演员的角色,并一直努力地在游戏中获取更高分数。此时的你可能会问自己:时间怎么过得这么快?我是在什么时候沉浸到游戏中? 也许你并未真正沉浸于游戏中,但是如果你认为自己是一名游戏玩家,你便可能已经遇到过类似的情况。而当你面对任何游戏都无法自拔之时,你便深陷这种情形中了。 特别是当你在玩一款优秀的游戏时更能够深刻体会到这种感受。如果游戏开发者能够塑造并添加具有强大用户粘性的设计要素,他们便可能创造出有趣,且畅销的好游戏。 幸运的是,一些心理学家已经察觉并研究了这种能够提高用户粘性的内容;他们甚至为其命名为:认知流。我将在以下内容中详细介绍这种“流”及其四大特征。我将从心理角度阐述每一个特征,并提供给游戏开发者一些重要的建议。 介绍 在20世纪70年代,心理学家Mihaly Csikszentmihalyi通过实验发现了“流”的存在。他发现人们的技能以及他们所面对的任务难度将导致不同的认知和情感状态的产生。如果人们的技能太低但却面对过于复杂的任务,他们便会感到焦虑。相反地,如果是技能高超之人面对过于简单的任务,他也会对此感到厌烦。而当人们的技能和任务难度成正比时,他们便会进入“流”状态。 在这种状态下,人们便会体验到: 1.极度专注于任务。 2.具有主动控制感。 3.整合行动和意识。 4.失去自我意识。 5.忘却了时间的流逝。 6.感受到完成任务是继续前进的唯一方法。 Csikszentmihalyi同样也提到了任务中能够推动技能和任务难度平衡的四大特征(能够提到流状态的概率)。这些特征分别是: 1.拥有明确的目标和管理规则。 2.以个人能力为基准完成目标。 3.明确且即时地反馈执行力和目标完成状况。 4.减少外部干扰,便于集中注意力。 如果游戏开发者希望玩家能够在游戏中产生“流”状态,他们就需要好好研究这四大任务特征。以下我将更加详细地分析这四大特征。   特征1:游戏应该拥有明确的目标和管理规则。 “我完全被搞糊涂了。一个非玩家角色(NPC)告诉我我应该做什么,但是我却因为房间中央的战利品而分神了,并且这时候我还发现了来自四面八方的Giant Spiders。此时我不但不能再访问NPC,我还注意到这个地牢中的所有房间都拥有相同的形状以及相同的颜色,我对此更加迷糊了!我不知道该去哪里也不知道如何才能到达目的地。过了15分钟后我才找到我需要面对的谜题,但是现在我却不知道该使用库存中20个任务道具中的哪一个去揭开谜题。过了一会后,我最终放弃了任务。” 如果玩家不知道目标是什么,不知道自己该如何完成目标或者使用何种技能去解决谜题,他们的“流”状态便会瓦解。并且他们将最终停止游戏。   **为何明确的目标和管理规则对于人们来说如此重要?**因为我们的信息处理和关注能力都非常局限;我们不可能完全消化所有来自屏幕上或者说话人口中的信息。尽管我们能够同时处理许多基于图像或声音的信息,但是这种处理能力也是非常局限。   特别是当我们的注意力出现分散时,这种处理局限便会更加明显。除此之外,如果任务相关信息过快呈现于人们眼前或者同时展开了多条信息,人们也会明显感受到信息处理的局限性。不管是何种情况,人们都会终止任务的执行。因为此时的人们会充满各种交流,觉得自己不可能完成任务,而因此抑制了内心“流”的发展。 关于信息处理的另外一大重要元素便是确保指示与任务的一致性。如果你能够确保任务和信息/指示保持一致,人们便能够更加容易理解并使用这些信息。 信息处理和注意力问题将直接影响我们解决问题与做决定的能力。如果你的信息处理出了问题,那么人们对于任务目标和规则的理解也会受到牵连。也就是如果人们不能理解问题的本质,他们便会感到焦虑而不愿意去尝试着解决问题。最终,这种挫败感将导致“流”状态的下降并因此影响人们解决问题的能力。 如果面对过多的打击,人们可能会后退求助于他们早前所使用的解决问题方法。但是开发者却不一定能够考虑到这种逆转。 明确目标和管理规则是一种切实可行的方法。获取目标是一种有报答的行为,从而因此能够推动个体继续努力完成目标。不论完成目标能够让你的角色获得升级还是争取更多分数,你都会因此而更加坚定达到目标的最终信念。目标——成就——奖励,如此循环不仅能够让玩家对游戏更加着迷,而且能够推动他们“流”状态的发展。 **游戏设计师该如何解决目标和规则问题?**如果设计师们能够考虑上述所提到的心理元素,他们便能够轻松地解决这些规则和目标问题。 * 不论是用户界面还是游戏屏幕上的任何内容都应该明确地向玩家指示他们的任务。情境线索,HUD信息以及NPC等也都应该确保目标的浅显易懂。 * 因为注意力的分散会影响理解力,所以设计师应该避免在玩家面对高度刺激感时刻(游戏邦注:如玩家在《光晕2》中面对Flood的肆虐或者在《天际》中需要避开成群的Draugr时)提供目标和指示内容。 * 在提供重要信息时更需要小心谨慎,以此确保信息和任务/目标保持一致。《死亡空间》中的指示线索便是一个典型的例子。开发者通过在玩家所处环境周围覆盖关于下个目标的相关提示,从而让玩家能够清楚地知道自己该如何前进。 * 而关于规则,玩家则希望能够在游戏过程中尝试更多不同的游戏技巧。 但是,在关卡或游戏中间段引入新的机制则会抑制“流”状态的发展。不过有时候这么做却是必要的,并且能够提高游戏的乐趣以及游戏玩法的多元化(例如,在《半条命》中主人公Gordon Freeman第一次获得Zero-point能量场操纵器时)。 但是当你提供新技能给玩家时,你还需要谨慎地面对如何培养他们使用新技能的问题(例如,当Gordon使用Zero-point能量场操纵器去追赶Dog时)的。 * 将小目标(如清除一地的野猪)与更大的目标(如获得足量的XP进行升级)并且与更大的目标(如进入特定关卡的齿轮)相互联系起来。这种联系将创造一系列的奖励体验,从而因此吸引更多玩家玩游戏并构建起“目标——成就——奖励”循环。 如果玩家能够较容易完成目标,他们便更乐意继续游戏。不过就像之前所说的,我们必须平衡玩家技能与任务难度之间的比例。 特征2:游戏只能要求玩家执行自己能力范围内的行动。 “我知道我应该朝着Fiend攻击的相反方向发动进攻,这么做才能够避开他的攻击,并朝着我的相反方向打击他。但是事实上我却做不到这一点。不知道是因为我不够放松还是这是我初次游戏,我的行动都非常笨拙。对此我感到非常沮丧。” 理解玩家的能力局限并培养他们的技能非常重要。如果玩家没有能力完成目标,那么即使你的目标和规则再明确,他们也不会感受到游戏体验的乐趣。 为什么游戏只能要求玩家执行自己能力范围内的行动? 因为如果不这么做,“玩家便会停止游戏!”还有许多心理元素拥有值得借鉴之处: 压力和执行力影响着“流”。如果玩家的能力不足以帮助他们完成游戏目标,他们便会倍感压力从而使得自己的执行力大大下降。最终瓦解了他们的“流”状态并破坏了游戏体验的乐趣。 目标难度和玩家的毅力。随着目标难度的提升(与玩家技能紧密相关),玩家关于完成这些目标的耐性也会被慢慢磨平,从而最终不愿意继续游戏。   游戏设计师该如何处理涉及玩家技能与任务难度的问题? 每个玩家都拥有自己的执行力-压力曲线(见图2)。这就意味着一名压力值为+7(随机值)的玩家可能拥有非常高的执行力,而另外一名同时拥有+7压力值的玩家就可能就执行力欠佳。 这同样也意味着游戏难度的层次(如简单,中等,困难)设置不合理也会导致糟糕的游戏体验。 游戏开发者应该在游戏中设置能够调整不同游戏情况以适应不同难度的AI,从而对玩家的执行力产生积极的影响(例如《求生之路》系列游戏中的AI Director)。 对于这种AI,你应该着重考虑执行力和乐趣之间的关系。有些玩家在面对越来越困难的任务时执行力也会慢慢提高,但是在这种复杂的挑战下他们却不一定能够感受到游戏的乐趣。在这种情况下,他们反倒会充满焦虑感(如图1所示)。游戏开发者便是从那些拥有较高执行力同时也属于较高流失率玩家中意识到这一点(如,即使玩家因为任务难度的改变而离开游戏,但是他们的执行力却仍保持稳定)。 另外一个需要考虑的元素便是,这些AI该如何针对不同多人玩家团队(如《求生之路2》战役中的4名玩家)设置难度。如此看来,开发者必须深刻意识到任务难度的变化将从不同方面影响着不同能力的玩家。因此,开发者首先需要考虑如何在不破坏游戏的前提下平衡同一个团队中最优秀玩家或最糟糕玩家,从而做出最合理的难度改变。 逐步向玩家传输游戏中的特殊技能。如果你的游戏中没有那些玩家熟知的技能(游戏邦注:如典型的FPS控制或瞄准技能),你就需要逐步地教授玩家你的游戏中的新技能。鉴于之前提到的信息处理局限,你应该让玩家能够在一种相对缓和的环境下学习这种技能。 特征3:游戏应该明确且即时地反馈玩家的执行力 “我这样做对吧?我刚刚创造的斧头是否放置到我的库存中了?这一行动是否能够提高我的魔法能力?” 无论这种反馈信息是基于虚拟高尔夫俱乐部所发出的声音,还是RPG游戏中经典的经验指示栏,或者是FPS游戏中模拟血的红色指示图标,你都需要让玩家清楚自己在游戏中的发展。 为何玩家需要获得即时的反馈? 这源自人类与生俱来的学习和调节机制。如果在完成行动后(200至400分毫秒内)或期间给予玩家相关反馈,便能够帮助他们更好地处理行动与结果之间的关系。 但是有趣的是,在行动开始的同时给予反馈信息却不见得有多大成效。(见图3)。 再次回到目标上,如果游戏能够在玩家的游戏进程中提供中期和长期目标(完成一个关卡或完成游戏)反馈,便能够进一步提高游戏的用户粘性并推动玩家最终完成游戏。 这也就意味着接收到反馈信息的玩家更愿意长时间玩游戏。   游戏设计师应该如何处理反馈问题? 如果玩家发现行动和结果之间出现了矛盾,他们便很难理解自己的行动对于执行力的影响。 所以开发者应该建立相关机制并尽早呈现给玩家长期和短期目标,随后在整个游戏过程中始终围绕着这些目标而发展。 特征4:游戏应该排除任何会破坏注意力的外部信息。 “这些穿梭于屏幕上方和下方的咒语和图标看起来真有趣!你看我的Ice Storm咒语的粒子影响!等等!谁袭击了我?” 如果面对的是越来越多噪杂的内容,玩家关于察觉并评估重要刺激物的能力便会大大减弱。这就意味着设计师应该确保那些穿梭于游戏中(不论是UI还是HUD)的额外内容足够简单。 为何需要排除任何会破坏玩家注意力的外部信息? 我们不得不再次提到人类对于信息处理的局限:就像我们在第一个特征中所提到的“流”状态,人类对于信息的处理具有一定的局限。而杂乱的视野将会打乱玩家的信息处理过程;并因此影响玩家对于目标和规则的理解,从而最终影响他们的“流”状态。 游戏设计师应该如何处理外部信息问题?HUD和游戏内部的菜单设置便是最简单的方法(游戏邦注:如《死亡空间》或《辐射》中那样)。 如果你的游戏中牵扯到游戏技能或选择,或者说这是开发者为了突破艺术或技术界限所强调的内容,你就必须将其涵括到游戏中去。 结论 能够创造出“流”状态的任务将拥有明确的目标和管理规则;基于玩家的能力调整目标;提供清晰且即时的执行力反馈;并且擅于排除任何外部信息。如果游戏开发者在设计过程中能够考虑这些特征,他们定能够创造出具有较高用户粘性(且高销量)的游戏。 我针对于每个特征所列举出的设计要素只是一种例子;或者说只是基于心理元素的基本原理。你应该根据你所创造的游戏类型——不论简单还是复杂,采用不同方法去应对这些特征和问题——就像每种特征中还存在许多推动着“流”状态发展的心理要素。 同时值得注意的是,大多数优秀的游戏设计师和游戏公司都已经明确(或含蓄)认可了这些“流”特征的重要性。 最后我想说的是,我所提供的这些内容只是引导开发者和设计师思考如何提高游戏的用户粘性;而真正的实践完全取决于那些参与游戏创造的人。

一月 Jan. January 二月 Feb. February 三月 Mar. March 四月 Apr. April 五月 May. May 六月 June. June 七月 July. July 八月 Aug. Aguest 九月 Sept. September 十月 Oct. October 十一月 Nov. November 十二月 Dec. December

0%