这几天在做IIS 6上Web Service (WSE 2.0)的性能测试。在这个过程中陆续发现和解决了一些问题。
其中有一个问题比较有意思。我和项目组的同事发现,不论我们用C#写的模拟客户端用多少并发量来连接Web Service,服务器端监测到的并发连接数(性能记数器中的Web Service\Current Connections)总是每客户端最高2个。这使得我们无法查看服务器在大并发量下的真切反应。
那么为什么服务器会对每客户端做出最高2个并发量的限制呢?
通过查找资料,我找到了问题的根源。原来,在HTTP 1.1 Spec中针对Persistent Connections提出了这样的Practical considerations:
Clients that use persistent connections SHOULD limit the number of simultaneous connections that they maintain to a given server. A single-user client SHOULD NOT maintain more than 2 connections with any server or proxy. A proxy SHOULD use up to 2*N connections to another server or proxy, where N is the number of simultaneously active users. These guidelines are intended to improve HTTP response times and avoid congestion.
以上内容表明,为了提高HTTP响应时间以及避免产生网络堵塞,HTTP连接中的客户端不应该与服务器端建立超过2个的HTTP连接。如果有更多的请求需要,那么这些请求将被pipeline到这两个HTTP连接之中,并以异步的方式传送给服务器端。举个例子:有上百辆汽车(requests)想从天津开往北京,但是天津与北京之间最多只允许修建两条公路(HTTP connection),因此这些汽车要想从天津驶往北京的话,就只能走这两条公路。
但是,有时的确需要突破这样的限制。比如我一开始提到的性能测试,我需要用尽可能少的客户端程序来模拟尽可能多的用户访问,而不能为了模拟1000个并发量同时使用500台机器来测。那么应该怎样通过一个测试应用程序来产生指定的并发数量呢?
不难看出,为了提高单一测试应用程序所产生的并发量,就应该增加两个指标:网络客户端数量和单一客户端的HTTP连接数量。就我所知,可以通过以下两种方法来分别提高这两个指标。
方法一:使用AppDomain
在. NET中,一个AppDomain就被视为网络连接中的一个客户端,因此如果希望用一个测试应用程序模拟多个客户端,那么只须创建多个AppDomain 即可。需要注意的是,对于每一个AppDomain,最高2个的连接限额仍然存在,不同之处只是我们可以使用一个测试应用程序发送超过2个的并发请求了(现在为了模拟1000个并发量就不需要找500台测试机器了)。请看下面的代码:
AppDomain appDomain = AppDomain.CreateDomain("");
appDomain.ExecuteAssembly(@"TestClient.exe");
AppDomain.Unload(appDomain);
在这里,我通过调用AppDomain的静态方法CreateDomain创建了一个新的应用程序域,并要求该应用程序域执行一个应用程序 TestClient.exe。该应用程序将负责向服务器发送请求(最多只能建立两个连接)。你可以通过多线程的方式来驱动上述代码,使得大量应用程序域在近乎相同的时间里被创建,从而就可以模拟指定数量的客户端,并产生所希望的并发访问量。
方法二:使用配置文件
除了增加客户端数量以外,我们还可以增加单一客户端所能建立的HTTP连接数量。在.NET中实现这一目标非常容易,只需要在客户端(没错,是客户端!)的配置文件中增加以下几行即可:
<system.net>
<connectionManagement>
<add address="*" maxconnection="100"/>
</connectionManagement>
</system.net>
其中,connectionManagement节点负责指定客户端与某一网络主机之间所能建立的最高连接数量。它在Machine.config文件中的默认取值就是2。我们完全可以在应用程序级的配置文件中对这一限额做出更改。address属性表明该连接限额针对的是哪一个网络地址,*表明所有的网络主机;如果写成address="www.google.com"就表明后面的maxconnection只适用于对google的访问。
好了,现在就可以根据自己的需要来更改配置了。如果你把maxconnection的取值改成了1000,那么你的测试应用程序与服务器之间所能建立的最高连接数量就是测试用应用程序域的数量 * 1000,测吧!
最近,我所在的团队利用业余时间在帮北邮举办的“北京邮电大学微软移动开发大赛”做技术支持。和同学们做了几次交流之后,我们发现大多数同学还对Windows Mobile开发了解甚少,他们非常希望能找到一条方便、可行的入门途径。因此我昨晚写了一篇介绍如何搭建Windows Mobile开发环境的文章,主要目的是帮助北邮参加移动开发大赛的同学们(以及所有想了解Windows Mobile开发的朋友们)熟悉和建立Windows Mobile开发环境。文章在这里。
在平时用电脑的过程中,我喜欢隔段时间就把鼠标左右调换一下,一来是想让自己一侧的肩、手臂、手腕能得到休息,尽量避免因长期固定姿势使用鼠标而带来的身体不适,另一方面也因为我本来就是个左撇子,喜欢尝试给两只手均等的做事机会。
当然,自从我给电脑同时接上左右两只鼠标以后,来回调换鼠标是避免了(据我所知,有在电脑上接三四只鼠标的,真是厉害!),但系统对于鼠标左右键的安排却不听我的调换,还要费力地去控制面板中设置一番,非常麻烦。因此我想,何不写几行代码,让鼠标左右键能在最短的时间内左右切换呢?这主意不错!OK,马上到MSDN里查找一番,十几分钟写出了下面这个小程序。
文章请见这里。
在用.NET CF开发Smartphone/Pocket PC应用时,我们经常需要给应用程序增加提醒功能,比如在下午两点时提醒用户去开会,或者在手持设备和PC通过ActiveSync连接时提醒用户同步某项重要数据。目前,实现提醒功能主要有以下几种方式:
-
Windows CE .NET提供了CeSetUserNotification(在CE 2.11版本及以后又增加了CeSetUserNotificationEx)这一API,可用于创建或修改提醒。该方法适用于Smartphone和Pocket PC。
-
Windows CE .NET还提供了另外一条API,SHNotificationAdd,也可以完成提醒的工作。该提醒是以Pocket PC中的气泡方式显示的,在Smartphone上不予处理。
-
Windows CE .NET中内置了Pocket Outlook,并提供了POOM (Pocket Outlook Object Model)以便二次开发。该方法适用于Smartphone和Pocket PC。
全文请见这里: http://blog.joycode.com/musicland/articles/34511.aspx
最近写了一个Smartphone 2003应用程序安装工具,可以在很大程度上简化Smartphone 2003应用程序的打包和安装。它的原理非常简单,就是调用CabWizSP.exe生成CAB包(需要手动写inf文件),然后调用一个第三方的ezsetup.exe工具来生成安装文件,在建立与Smartphone(真机or模拟器)连接之后执行自动安装。
以下是这款工具的部分运行界面及描述:

程序主界面。大多数情况下,用户只需选取一个安装信息文件(.inf)再点击”Generate”就可以了。

安装文件生成成功的提示。

应用程序配置界面。如果需要进一步的配置(比如配置Prexml/PostXml/Platform等),用户可以在主界面点击”Options…”进入这里。
因为这工具主要是在目前所在的项目组里用,所以我在保证所需功能完整的前提下,尽可能地做了简化。本想再写一个inf文件的可视化开发界面,但在用的过程中发现inf配置虽然相对复杂,但大部分内容都可以基于现有配置文件做少量更改实现,所以也就放弃了进一步开发的想法。
大家如果对Smartphone部署感兴趣,可以参考下面这篇文章:
Smartphone 2003 Application Deployment Demystified
今天在做一个VSTO (Visual Studio Tools for Office)的示例时遇到了点儿麻烦,一开始百思不得其解,后来找到问题的根源之后发现蛮有意思的,写出来和大家分享一下。

昨天把收到的Longhorn (build: 4074)装在自己的开发机器上,算是迟迟地体会了一把Longhorn的威力。
因为还没有下载完SDK,所以我的体会仅限于Longhorn所提供给最终用户(以及管理人员)的一些新特性,其中比较让我感兴趣的就是IE中的新增功能——Download Manager。
其实类似的工具早已经在其它的游览器中提供了,也有一些第三方的很棒的工具,比如Flashget等。我个人感觉,IE所提供的Download Manager最主要的目标不是提供一套完整的下载以及下载过程/文件管理工具,而是直接针对IE本身进行一种Add-on嵌入,帮助用户对下载过程和下载文件进行简单的管理,比如设定和修改下载优先级(High/Background/Suspended),提供安全警告,显示下载进度,断点续传等等。同时,Download Manager让用户可以很方便地定位已经下载的文件,而此前经常会发生用户下载完以后却找不到文件的情形。另外,在下载提示对话框中就已经显示了即将要下载的文件的大小,而在原来,只有真正去下载该文件才能看到文件大小的提示。
从整体上来看,Download Manager对用户的下载过程起到了很有必要的帮助。虽然我们很可能还要寻找一些专业下载工具的支援,但至少在系统自身里已经提供了这样的辅助功能。我想这样的进步本身就已经让人感到由衷的高兴了,呵呵。
BTW:用过微软的File Transfer Manager (通常在MSDN/MCT下载站点中提供)的人能一眼就看出,Download Manager与前者如出一辙,可能它们走的是同一条技术路线吧。
下载提示对话框,可以显示要下载的文件的大小

Download管理界面

Download Manager的设置选项,这里和File Transfer Manager几乎一模一样

前天,我开发机器上的POP3/SMTP服务出了问题,一时无法解决,于是就在MSN Messenger上找严诺(Nuo Yan)求助。因为问题涉及的面比较广,文字沟通很难说清楚,所以我邀请他进行了一次远程协助(Remote Assistance)。
首先是发现MSN Messenger中的远程协助功能失效,软件提示要安装最新版本的Windows Messenger。于是下载安装Windows Messenger 5.0,重新登陆,终于进入了远程协助的界面。
我请严诺直接控制我的本机(他在汕头,我在北京),他用最快的速度排除了我DNS设置中的一个问题(该问题来自于我的Server 2003一开始设置为动态获取IP和DNS地址,该机器同时是Domain Controller和DNS Server),然后检查POP3/SMTP中的设置。在这个过程中遇到了一串怪问题,最后SMTP的management console竟然在Inetmgr里失踪了,以致最后的时间几乎完全花在寻找SMTP management console上。
整个过程大概持续了一个半小时,SMTP management console还是找不见,不过随后当我按http://support.microsoft.com/default.aspx?scid=kb;en-us;323350这篇文章中给出的方法对本机POP3/SMTP服务进行测试的时候,竟然发现邮件已经收发自如了,这更让我觉得奇怪,难道SMTP management console的失踪是个bug?还是我的操作有误?
不过,我真的要在这儿再次感谢严诺的无私帮助,特别是后来他对我问题的解答更让我受益:
musicland: 你说我有没有必要找时间学一学Windows Server 2003方面的知识呢?
Nuo Yan: 非常有必要,对系统的了解会有助于开发的。马骐老师就是两方面都很精通。
(因为Windows Messenger中没有聊天记录存储功能,所以以上对话内容是我凭印象记忆的
MyMSDNTVLibrary是我以前写的一个小型WinForms项目,当时的想法是为初学者们演示如何创建一个简单但却完整的小项目。今天我又把这个小项目翻出来,通过应用Factory Method模式,使该项目可以支持多种不同的数据源(Access/ SQL Server ...)。大家如果感兴趣可以看我写的这篇文章。
目前我增加了对Access和SQL Server的支持,对其它数据源的支持也可以很容易增加。
BTW:不知大家对MCT领域是否关注,我昨天看到这里正在进行“2004年微软金牌认证讲师”评选。在其中列出的MCT名单中就有我们博客堂的马骐,一位有着四年授课经验的资深MCT(同时也是我的好老师、引路人);此外还有我们博客堂长期以来的好朋友李争(上次聚会时站在我旁边的那个高个子:)。如果大家也和我同样欣赏和佩服这二位MCT的话,那么请支持他们!
前段日子读代码时发现了一个不曾用过的命名空间——System.IO.IsolatedStorage,通过该命名空间下面的一些类(如IsolatedStorage、IsolatedStorageFile、IsolatedStorageFileStream等)可以把应用程序中一些敏感的信息保存在文件系统之外,这让我感到很兴奋。
举个简单的例子,下面这行代码可以在IsolatedStorage(MSDN中译为“独立存储区”)寻找是否有一个名为PersonalFeedList.xml的文件:
if (IsolatedStorageFile.GetUserStoreForDomain().GetFileNames("PersonalFeedList.xml").Length!=0)
{
IsolatedStorageFileStream listLoader=new IsolatedStorageFileStream("PersonalFeedList.xml",
FileMode.Open, IsolatedStorageFile.GetUserStoreForDomain());
// TODO: process the FileStream here
}
关于IsolatedStorage命名空间的具体应用大家如有兴趣可以查阅MSDN,我个人认为IsolatedStorage非常适合存储那些应用程序运行过程中产生的临时文件,比如下载到本机需要进一步处理的xml文件。这些文件不便于呈现给最终用户,有些还不能让用户看到(比如一些临时性的密码存储)。由于IsolatedStorage独立于用户的文件系统,因此这种存储方式在某种程度上保证了数据的保密性。
不过此项应用也有诸多不足,最主要的一点是:你不应该用它来存储永久性文件,因为用户可以使用.NET SDK中的storeadm.exe工具删除独立存储区的所有数据,方法是:
storeadm /remove
在我的.NET开发过程中,一些来自GNU的非常优秀的自由软件(如Emacs、grep等)自始至终起着至关重要的作用。离开这些工具,我的开发过程将变得异常低效和单调。今天我就为大家介绍一下grep这款强大的搜索工具。请别把它和Google混在一起,grep将把你的文档搜索操作变得快速而高效。
Let's go!
前面我写出一篇Simple & Funny——My MSDN TV Library后,很多初学.NET的朋友都表示出了浓厚的兴趣,纷纷下载源代码进行学习。我这才意识到,其实走在前面的人应该更多地拿出些时间来为后来者们做点什么。我们每个人在学习的初期都遇到过非常多的困难,当我们把这些困难度过之后,其实还有更多的人在同样地面临着它们,他们是多么渴望能分享一些经验,少走一些弯路呀。
出于这一点考虑,我想在近期为初学.NET的朋友们写一系列入门文章。每篇文章都很浅显,针对某一个技术细节展开。文章所采用的实例都是我在实战中遇到的,因此里面所含的讲解也都会是我在实战中反复考虑并总结下来的。希望对大家,特别是.NET初学者们带来帮助!
今天这一篇是我上星期在开发时遇到的一个问题——应用正则表达式来处理html文档。
这几天手头没什么项目,难得轻闲,正好自己机器上下载的MSDN TV视频差不多满600m该刻盘了(硬盘太小),于是就花了一个晚上写了个管理这些文件的可爱的WinForms程序——My MSDN TV Library,用上它以后原本杂乱无章的一堆.wmv文件还真变得井井有条了

简介请看这里。
从高中开始算到今日,我弹吉他已经有八年了。这期间经历的乐队,参加的演出,写的歌曲,真的都已经记不清楚。我只知道当自己选择了软件开发之后,花在弹吉他上的时间越来越少,几年时间内一直在吃过去的老底,再也没认真、正式地练过琴,甚至有段时间都想把这种爱好放弃了。我想自己可能遇到一个瓶颈了吧。
前天晚上我在MSN上和开心聊天时说,自己感到不知该做点什么了,技术上不知该如何突破,找不到下一个应该学习的方向,甚至找不到开发的热情。我想自己可能遇到一个瓶颈了吧。
记得去年在CSDN上看到一篇题为《程序员成长最危险的时刻》的帖子,里面有一段给我留下的印象特别深,我把它引用在下面:
其实程序员成长最危险的时刻不是在你什么都不懂的时候,而是在你懂了一些的时候。开始的时候,你觉得什么都不懂,于是你天天看书,通宵编程。后来你懂了c了,算法数据结构操作系统在学校也学了,用VC 写程序时你边看MSDN边用MFC,觉得感觉还不错;你用Delphi甚至做了一个个像模像样数据库的项目了。至于COM,你懂了一点点,说起来头头是到,虽然没用过。标准C++嘛,你在大学学过基本的C++,工作时用VC,什么继承,虚函数,const,引用,模板你也都用过了。你也听说过设计模式,用过最简单的单件模式什么的,虽然还有很多你不懂的。有的时候你觉得操作系统很有意思,你还写过些多线程的控制系统的东西。可是现在你反倒觉得你什么都不会了,看这别人用VC 写的大系统,你觉得很写的很好,可是你不知道怎样达到那样的水平。你觉得你有很多的东西都不懂,可是你不知道怎么学得更好,有的时候你对编程序都快没激情了,于是你也跟我一样到了程序员成长最危险的时刻。有些朋友觉得已经可以混到饭吃了,就不再努力,这样就危险了!
在CSDN论坛的汪洋大海中,这是一篇再普通不过的帖子了,然而却是这篇普通的帖子给了我最大的冲击,里面的每句话都仿佛在描述一个过去的我。比如说弹吉他,我曾在大学里以两年的时间和无数次翘课为代价苦练了小林克己的那套教材,在演出时能轻松弹一些诸如Hotel California的曲子,然而后来我却没有继续练下去,多年来站在原来的水平无法前进,甚至技艺渐趋倒退;至于软件开发的情形也大体相似。当我对.NET一无所知的时候拼命地看书写代码,到CSDN上去问问题找答案,后来考下了MCAD/MCSD.NET,又做了几个或大或小的项目,自己感觉对.NET (特别是ASP.NET/XML/C#)掌握得已经很不错了,于是就开始松懈起来,开始止步不前。到了后来,我甚至不愿去CSDN问问题,有了疑问后便去查MS KB,查不到就去Google,再找不到就捡一个自己会的解决方案代替了。如此一来,技术长进也就真的遥不可及了。
OK,从现在开始以这篇文章为警示,放弃一切负担,重拾热情,像初学者一样认认真真地去学。如果您在自己的身上也发现了同样的问题,那么就让我们共勉吧。:)
由于不久前才装上了宽带,因此最近才有机会接触.NET Framework v1.2(这儿的好多朋友早已经用起来了),对里面的MSBuild工具产生了浓厚的兴趣。此前我是用NAnt管理生成过程的,用起来一直感觉不错,所以这次用上MSBuild之后还一时有点不适应,特别是两者在语法风格上的差异让我在一段时间内颇感不适。不过现在好多了
为了让自己别忘得太快,同时也想让更多还没接触MSBuild的朋友能了解这款不错的Build工具,我最近陆续写了点东西放在下面,大家有兴趣可以一看,我还会陆续把我所知道的有关MSBuild的一些应用写出来的。
MSBuild入门(一)(http://blog.joycode.com/musicland/posts/11833.aspx)
MSBuild入门(二)(http://blog.joycode.com/musicland/posts/12161.aspx)