??xml version="1.0" encoding="utf-8" standalone="yes"?>香蕉aa三级久久毛片,久久久国产亚洲精品,www.久久99http://www.shnenglu.com/zliner/category/1641.html技术学?/description>zh-cnMon, 19 May 2008 17:50:43 GMTMon, 19 May 2008 17:50:43 GMT60用例分析基础http://www.shnenglu.com/zliner/archive/2006/06/01/8038.html依旧的博?/dc:creator>依旧的博?/author>Thu, 01 Jun 2006 09:18:00 GMThttp://www.shnenglu.com/zliner/archive/2006/06/01/8038.htmlhttp://www.shnenglu.com/zliner/comments/8038.htmlhttp://www.shnenglu.com/zliner/archive/2006/06/01/8038.html#Feedback0http://www.shnenglu.com/zliner/comments/commentRss/8038.htmlhttp://www.shnenglu.com/zliner/services/trackbacks/8038.html1. 一个用例可以有多个参与者,q且可以同时有多个参与者?br />用例和参与者的兌可以是双向的Q参与者和用例都可以发起通信?br />
2. 用例之间的基本关pLQ泛化,包含和扩展?br />用例A到B的泛化关p表CA和B是具体与抽象的关pR?br />用例A到B的包含关p表CA使用?jin)B提供的功能?br />用例A到B的扩展关p表CA向B(ti)提供的可用的功能?br />但从A到B的包含关pd从B到A的扩展关pL不同的:(x)
A包含B说明B是从A中分解出来的公共行ؓ(f)QB自n是独立的Q但对于A来说是不可缺的一部分?br />B扩展A说明B是从A中分解出来的变(sh)行ؓ(f)Q必L定扩展点Q也是在基本用例中执行变(sh)行ؓ(f)的具体条件。B仅仅是A的补充,而不是不可缺的部分QB自n也不是独立的。A可以单独执行Q表C通常的情况,在特定的情况下,用B来补充它?br />抽象用例不能被实例化Q不能被实际执行Q它的作用在于更好地l织用例关系?br />



参考书Q?br />《UML用户指南?Grady BoochQJames RumbaughQIvar Jacobson?늻忠等?机械工业出版C?br />《统一软g开发过E?Ivar JacobsonQGrady BoochQJames Rumbaugh?周伯生等?机械工业出版C?br />



]]>
MFC的五U基本机?/title><link>http://www.shnenglu.com/zliner/archive/2006/05/15/7218.html</link><dc:creator>依旧的博?/dc:creator><author>依旧的博?/author><pubDate>Mon, 15 May 2006 11:33:00 GMT</pubDate><guid>http://www.shnenglu.com/zliner/archive/2006/05/15/7218.html</guid><wfw:comment>http://www.shnenglu.com/zliner/comments/7218.html</wfw:comment><comments>http://www.shnenglu.com/zliner/archive/2006/05/15/7218.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/zliner/comments/commentRss/7218.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zliner/services/trackbacks/7218.html</trackback:ping><description><![CDATA[<p>我们知道MFC的作用在于封装Windows的编E接口,q提供应用程序框架的开发模式。ؓ(f)?jin)完成从前者到后者的q渡QMFC实现?jin)几U基本机Ӟ它们是消息映,命o(h)传递,q行时类信息(RTCI)Q动态创建和序列化?br><br>消息映射和命令传递是对SDKE序交互机制的封装。序列化是应用程序需要的一U基本特性,x(chng)数据保存到磁盘和从磁盘打开数据。通过RTCI和动态创建,可以把Y件的对象数据保存到磁盘,反过来从q些数据识别和恢复对象,从而实现对象的序列化。基于数据库的序列化机制和这U方式不同,应用E序和数据库之间有一个约定,以什么样的格式保存(sh)么样的数据,再以同样的方式打开Qƈ且如何重建对象数据也定下来了(jin)Q在打开数据Ӟ应用E序不需要有适应性,不需要识别数据类型,也不需要根据在q行期才定的类型名U创建其对象?/p> <p>动态创建就是创建某U类型的对象Q具体类型在q行时确定,~译时可能不知道。比如运行时用户输入一个类型名Uͼ如果该类型是E序cd体系中的一员,则程序中能够创cd的对象。下面的代码是用MFC动态创建机制的一个简化的例子Q?/p> <p>CRuntimeClass* g_pFirstClass;<br>void func()<br>{<br>     char szClassName[64];<br>     CRuntimeClass* pClass;<br>     CObject* pObject;<br>     <br>     cout << "enter a class name...  ";<br>     cin >> szClassName;<br>     <br>     for (pClass = g_pFirstClass; pClass != NULL; pClass = pClass->m_pNextClass)<br>     {<br>          if (strcmp(szClassName, pClass->m_lpszClassName) == 0)<br>              pObject = pClass->CreateObject();<br>     }<br>}</p> <p>实现动态创建的思\是把动态的cd名称与程序类型体pM的每一个进行比较,与某个类型吻合时让该cd创徏自n的对象。这P支持动态创建的cd中的每一个类都要额外实现一些功能,卛_别一个名U是否与自n相符Q以?qing)创w的对象?/p> <p>判别一个名U是否与自n相符Q这是运行时c识别的内容Q所以MFC动态创建是在RTCI基础上实现的?/p> <p>RTCI是一个对象能够判定自己是否属于某U类型,该类型的名称在运行时定Q编译时可能不知道。从下面的例子很Ҏ(gu)理解RTCIQ?/p> <p>void Func()<br>{<br>     char szClassName[64];<br>     CDocument* pDoc = new CDocument;<br>     <br>     cout << "enter a class name...  ";<br>     cin >> szClassName;<br>     <br>     cout << pDoc->IsKindOf(szClassName); //是返?Q否q回0<br>}</p> <p>有一炚w要说明的是,因ؓ(f)CDocumentz于CObjectQ所以IsKindOf对于CObject也要q回1。因为我们是从动态创建出发的Q所以如果是q样可能?x)有一点背d街但是RTCI明显和动态创建有密切联系QRTCI也可能有单独的h(hun)|所以先把RTCI实现h?/p> <p>实现RTCI的思\是让每一个类记录自n的类型信息,q提供IsKindOf(char*)函数q行所l类型与自ncd的比较,而且q要能访问基cȝcd信息Q进行比较,一直到根类。所以记录的cd信息要按l承关系qv来,每个cȝIsKindOf()q要调用基类的IsKindOf()。MFC把要记录的类型信息抽取到一个CRuntimeClassl构体中Q每个类中加入一个CRuntimeClass成员卛_?/p> <p>现在回到动态创建,在RTCI建立的数据结构基上将可实现它。动态创Z不同于IsKindOf()的角度用这一数据l构Q它要遍历所有类型的CRuntimeClass。那么仅仅有l承关系的类的CRuntimeClass相连q(sh)够,要把所有类的CRuntimeClassq成一个链表。其实动态创建ƈ不关?j)类间的l承关系Q它q等看待每个cR现在以CRuntimeClass为结Ҏ(gu)成一个纵横两个方向的链表QIsKindOf()和动态创建分别用它不同的侧面?/p> <p>序列化的概念是在文g中存储对象信息,q能Ҏ(gu)它恢复对象。对于文档视囄构的软gQ用户需要保存所~辑的文档和打开已编辑的文档Q这正是序列化的应用Q所以序列化是非帔R要的一U特性。在序列化恢复对象时Q就可以用到动态创建?/p> <p>使用MFC序列化的例子如下Q?/p> <p>void CMyDocument::Serialize(CArichive &ar)<br>{<br>    if (ar.IsStoring())<br>    {<br>        ar << m_pMyClass; //CMyClass m_pMyClass;<br>    }<br>    else<br>    {<br>        ar >> m_pMyClass;<br>    }<br>}</p> <p>一个支持序列化的类提供Serialize(CArchive &)函数Q重?lt;<?gt;>操作。注意两者是不同的,在上例中QCMyDocumentcȝ信息q不被序列化Q而CMyClasscȝ信息被序列化。实际上一个序列化cȝ<<?gt;>操作Q其不涉?qing)类信息的部分是调用Serialize()完成的,它必d时实现这两者?/p> <p>按照MFC的要求,需要在支持序列化的cd义中使用DECLARE_SERIAL宏,在类实现中用IMPLEMENT_SERIAL宏。我们看一下这两个宏实C(jin)什么,</p> <p>#define DECLARE_SERIAL(class_name) \<br> _DECLARE_DYNCREATE(class_name) \<br> AFX_API friend CArchive& AFXAPI operator>>(CArchive& ar, class_name* &pOb);</p> <p>#define IMPLEMENT_SERIAL(class_name, base_class_name, wSchema) \<br> CObject* PASCAL class_name::CreateObject() \<br>  { return new class_name; } \<br> _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, \<br>  class_name::CreateObject) \<br> AFX_CLASSINIT _init_##class_name(RUNTIME_CLASS(class_name)); \<br> CArchive& AFXAPI operator>>(CArchive& ar, class_name* &pOb) \<br>  { pOb = (class_name*) ar.ReadObject(RUNTIME_CLASS(class_name)); \<br>   return ar; } \</p> <p>主要是加入了(jin)?gt;>的重载,但是没有重蝲<<QMFC仅提供了(jin)CObject?lt;<的重载,如下Q?/p> <p>_AFX_INLINE CArchive& AFXAPI operator<<(CArchive& ar, const CObject* pOb)<br> { ar.WriteObject(pOb); return ar; }</p> <p>q是因ؓ(f)在序列化d写的时候,都需要具体类的CRuntimeClass信息。相应的GetRuntimeClass()是一个虚函数QCObject重蝲<<Q在写类信息时调用到该函敎ͼ׃虚函数机Ӟ写入的是具体cȝ信息。但是这里隐含着一个条Ӟ是调用<<和GetRuntimeClass()Ӟ具体cd象已l存在了(jin)Q而调?gt;>和读入类信息Ӟ该类对象q未被创建,所以无法利用这U机Ӟ只能在每个具体类中都重蝲一?gt;>。我觉得《深入解析MFC》对q个问题的解释不正确?/p> <p>q里有一个问题需要明一下,序列化ؓ(f)什么要写入cM息?一是它应该保存完整的能够独立恢复对象的信息Q二是在E序d对象Ӟ要把它的cM息和E序中期望的(所能处理的)cM息相比较Q进行检验?/p> <p>看IMPLEMENT_SERIAL宏对重蝲>>的实玎ͼ是提供一个期望的CRuntimeClassl构(用于(g)?Q委托CArchiveq行对象d。因对象旉先要跟文件打交道Q所以交lC(j)Archive处理Q随后把d的数据写入对象时QCArchive再调用具体类的Serialize()Q如此合作是十分恰当的。在q里QCArchiveq负责了(jin)d和检验类信息Q然后创建对象的q程。因Z斚w具体cd象还?sh)存在,另一斚wq些操作Ҏ(gu)有具体类都没有分别,应该提出来,在类U别实现或者让合作者实现。实际上QMFC先把q个q程交给C(j)Archive::ReadClass()Q后者又调用CRuntimeClass::Load()?nbsp;</p> <p>对于序列化来_(d)搞清它的概念以后Q就是实现Serialzie()Q重?lt;<?gt;>。对<<?gt;>的重载涉?qing)很多工作,MFC已经帮我们实C(jin)Q我们也看见?jin)大概的设计Q主要是与CArchive分工合作Q其ơ是CRuntimeClass?/p> <p>现在看到CRuntimeClassl构体在MFC对RTCIQ动态创建和序列化的实现中都L(fng)重要的作用,重新认识一下这个数据结构很有必要?/p> <p>CRuntimeClass包含?jin)关于类的各U信息和有关操作。把cd(qing)其基cȝCRuntimeClassq成一个链表,可以很方便地实现RTCI的IsKindOf()Q把所有类的CRuntimeClassq成一个链表,再加上一个简单的CreateObject函数Q就可以对以Lcdq行动态创建的企图做出反应QCRuntimeClassq实C(jin)向文件读写类信息的Load()QStore()Q配合序列化的实现?/p> <p>在分析消息映和命o(h)传递机制之前,需要对<a title=WindowsE序模型 href="http://www.shnenglu.com/zliner/archive/2007/04/15/21942.html">WindowsE序模型</a>有很好的理解?/p> <p>未完待箋(hu)...<br><br><br>参考:(x)<br><br>《深入解析MFC?中国?sh)力出版C?br>《深入浅出MFC?华中U大出版C?br>《WindowsE序设计?北大出版C?/p> <img src ="http://www.shnenglu.com/zliner/aggbug/7218.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zliner/" target="_blank">依旧的博?/a> 2006-05-15 19:33 <a href="http://www.shnenglu.com/zliner/archive/2006/05/15/7218.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>思\ƣ赏http://www.shnenglu.com/zliner/archive/2006/05/12/7045.html依旧的博?/dc:creator>依旧的博?/author>Fri, 12 May 2006 15:14:00 GMThttp://www.shnenglu.com/zliner/archive/2006/05/12/7045.htmlhttp://www.shnenglu.com/zliner/comments/7045.htmlhttp://www.shnenglu.com/zliner/archive/2006/05/12/7045.html#Feedback2http://www.shnenglu.com/zliner/comments/commentRss/7045.htmlhttp://www.shnenglu.com/zliner/services/trackbacks/7045.html
1. 问题Q对32位的二进制整敎ͼ不用循环Q求出其?的个数?br />
#define (tng)POW(c) (tng)(1<<(c))
#define (tng)MASK(c) (tng)(((unsigned (tng)long)-1) (tng)/ (tng)(POW(POW(c)) (tng)+ (tng)1))
#define (tng)ROUND(n, (tng)c) (tng)(((n) (tng)& (tng)MASK(c)) (tng)+ (tng)((n) (tng)>> (tng)POW(c) (tng)& (tng)MASK(c)))

int (tng)bit_count(unsigned (tng)int (tng)n)
{
 (tng) (tng) (tng) (tng)n (tng)
= (tng)ROUND(n, (tng)0);
 (tng) (tng) (tng) (tng)n (tng)
= (tng)ROUND(n, (tng)1);
 (tng) (tng) (tng) (tng)n (tng)
= (tng)ROUND(n, (tng)2);
 (tng) (tng) (tng) (tng)n (tng)
= (tng)ROUND(n, (tng)3);
 (tng) (tng) (tng) (tng)n (tng)
= (tng)ROUND(n, (tng)4);
 (tng) (tng) (tng) (tng)
return (tng)n;
}

基本的想法是把所有的1加v来,得到的就?的个数。我们需要把q些1分离出来Q每?都是q等的,与其位置无关。难题在于不能一个一个去取,那就用到?jin)@环,当然递归也是不允许的。需要有一U统一的办法,可是很难惌具体该怎样。我们逐步地做qg事,假设?6位和?6位分别求得了(jin)1的个敎ͼ那么加v来就行了(jin)?6位二q制中的1仍然是未知的Q随机出现的Q问题的性质没有变,但我们可以(h)l分解,q种逐步的做法不一定就意味着递归。每?6位分解ؓ(f)两个8位,...,每个2位分解ؓ(f)两个1位,把两?位上的数相加是q两位上1的个数。现在需要取出每一位上的数吗?如果惛_?jin)这个问题,q最l的思\不远?jin)。现?2位已l分成了(jin)16个两位,很容易将其看作两?6位,一个是所有奇CQ一个是所有偶C。我们不难把q两?6位分开Q然后移位相加,求Z(jin)每两位中1的个数。到?jin)这一步,以后的思\很自然?jin)?br />

参考:(x)

《计二q制?1'的个数》来自?a >http://kaikai.cnblogs.com

]]>
几种排序Ҏ(gu)的实?/title><link>http://www.shnenglu.com/zliner/archive/2006/05/09/6825.html</link><dc:creator>依旧的博?/dc:creator><author>依旧的博?/author><pubDate>Tue, 09 May 2006 08:37:00 GMT</pubDate><guid>http://www.shnenglu.com/zliner/archive/2006/05/09/6825.html</guid><wfw:comment>http://www.shnenglu.com/zliner/comments/6825.html</wfw:comment><comments>http://www.shnenglu.com/zliner/archive/2006/05/09/6825.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/zliner/comments/commentRss/6825.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zliner/services/trackbacks/6825.html</trackback:ping><description><![CDATA[ <div>1. 冒(chng)排序<br /><br /> (tng)思想Q?br /><br /></div> <ol> <li>从现有元素中取出最大的元素Q移到相应的位置Q直到所有元素都׃? </li> <li>通过比较和交换逐步调整现有序列Q最l找出最大元素ƈ使其׃?</li> </ol> <p> (tng)设计Q?br /><br /></p> <p> (tng) 输入是待排数l及(qing)光度,输出排序后的数组?br /> (tng) (tng)在冒泡过E中Ҏ(gu)l的有序情况q行(g)查,在数l已l有序时便结束算法?br /><br />代码Q?br /><br />void BubbleSort(int nArray[], int nLength)<br />{<br /> (tng) (tng) (tng) (tng) bool bSorted = false;<br /> (tng) (tng) (tng) <br /> (tng) (tng) (tng) (tng) if (nArray == NULL)<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) throw -1;<br /> (tng) (tng) (tng) <br /> (tng) (tng) (tng) (tng) if (nLength < 2)<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng)  (tng)return;<br /> (tng) (tng) (tng) <br /> (tng) (tng) (tng) for (int i = nLength; !bSorted && i > 1; i--)<br /> (tng) (tng) (tng) {<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng)  (tng)bSorted = true;<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) <br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) for (int j = 1; j < i; j++)<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) {<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) if (nArray[j] < nArray[j-1])<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) {<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) int n;<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) n = nArray[j];<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) nArray[j] = nArray[j-1];<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) nArray[j-1] = n;<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) <br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) bSorted = false;<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }//if<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }<br /> (tng) (tng) (tng) (tng) (tng)}<br /><br />}<br /><br />2. 双向冒(chng)排序<br /><br />void BiBubbleSort(int nArray[], int nLength)<br />{<br /> (tng) (tng) (tng) (tng)int (tng) low, high;<br /> (tng)<br /> (tng) (tng) (tng) (tng)if (nArray == NULL)<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng)throw -1;</p> <p> (tng) (tng) (tng) (tng)if (nLength < 2)<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng)returnt;</p> <p> (tng) (tng) (tng) low = 0;<br /> (tng) (tng) (tng) (tng)high = nLength - 1;<br /> (tng) (tng) (tng) while (low < high)<br /> (tng) (tng) {<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng)int t;</p> <p> (tng) (tng) (tng) (tng) (tng) (tng) (tng)t = low;<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng)for (int i = low; i < high; i++)<br /> (tng) (tng) (tng) (tng) (tng) (tng) {<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) if (nArray[i] > nArray[i+1])<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) {<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) int n;<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) n = nArray[i];<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) nArray[i] = nArray[i+1];<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) nArray[i+1] = n;<br /><br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) t = i + 1;<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }<br /> (tng) (tng) (tng) (tng) (tng) (tng) }<br /> (tng) (tng) (tng) (tng) (tng) (tng) high = t - 1;</p> <p> (tng) (tng) (tng) (tng) (tng) t = high;<br /> (tng) (tng) (tng) (tng)  (tng)for (int j = high; j > low; j--)<br /> (tng) (tng) (tng) (tng) (tng) {<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) if (nArray[j] < nArray[j-1])<br /> (tng) (tng) (tng) (tng) (tng) (tng)  (tng) (tng) {<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) int n;<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) n = nArray[j];<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) nArray[j] = nArray[j-1];<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) nArray[j-1] = n;<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) t = j - 1;<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }<br /> (tng) (tng) (tng) (tng) (tng) }</p> <p> (tng) (tng) (tng) (tng) low = t + 1;</p> <p> (tng) }//while<br /><br />}<br /><br />3. 快速排?br /><br /> (tng)思想Q?br /><br /> (tng)选一个枢轴元素,把待排序列划分成两段Q前一D不大于枢uQ?tng)后一D不于枢u。如果这两段分别有序Q原序列也随之有序。通过划分Q一个段的排序可以{化ؓ(f)两个子段的排序,卛_h质但较?yu)规模的问题。当D늚长度?Ӟ本n是有序的Q{化可以终止?br /><br />设计Q?br /><br />用一个递归函数来实现快速排序算法,递归l止条g是段的长度小于等??br />一ơ划分过E设计如下:(x)取段的第一个元素ؓ(f)枢uQ从最后一个元素向前与枢u比较Q发现小于枢轴的元素Ӟ与枢轴交换位|,从第二个元素向后与枢轴比较,q样两端是已完成划分的部分,中间是待划分的部分,枢u始终处于中间部分的一端,比较从另一端向该端q行Q发现分cM同的元素同枢u交换。随着比较和交换的q行Q中间部分不断收~?每次长度~短1)Q当收羃到长度ؓ(f)1Ӟ划分l止?br /><br />实现要点Q?br /><br />递归函数的参数是待排序列?qing)前后边界?br />划分q程需要用两个变量记录中间部分的边界?br /><br />代码Q?br /><br />void QuickSort(int nArray[], int low, int high)<br />{<br /> (tng) (tng) (tng) (tng) int pivot = nArray[low];<br /> (tng) (tng) (tng) (tng) int (tng)i = lowQj = high;<br /> (tng) (tng) (tng) <br /> (tng) (tng) (tng) (tng) if (high < low)<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)return; (tng) (tng) (tng)<br /> (tng) (tng) (tng) (tng)<br /> (tng) (tng) (tng) (tng) while (i < j)<br /> (tng) (tng) (tng) (tng) {<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) while (i < (tng)j && nArray[j] >= pivot) j--;<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) if (i < j) (tng)<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) nArray[i++] = nArray[j];<br /> (tng)<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) while (i < (tng)j && nArray[i] <= pivot) i++;<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) if (i < j) (tng)<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) nArray[j--] = nArray[i];<br /> (tng) (tng) (tng) (tng) }<br /> (tng) (tng) (tng) (tng)<br /> (tng) (tng) (tng) (tng) nArray[i] = pivot;<br /> (tng) (tng) (tng) <br /> (tng) (tng) (tng) (tng) QuickSort(nArray, low, (tng)i - 1);<br /> (tng) (tng) (tng) (tng) QuickSort(nArray, (tng)i + 1, high);<br />}<br /><br />试要点Q?</p> <ol> <li>递归l止条g。必Lhigh < lowQ而不能是 high (tng)== low。递归的终止是很重要的边界情况Q在实现之前有一个概念上的终止条Ӟ但在实现时处理必d。终止条件和递推方式有关Q需要结合实际的递推方式来确定? </li> <li>递归的递推方式? </li> <li>分划的终止条件。分划过E在i == j时终止,虽然在比较的q程中可能进行交换,但是每次未分划部分的长度?Q用该长度控制分划的l止? </li> <li>分划q程中改变方向时的交接?</li> </ol> <p>法分析Q?br /><br />假设原序列有2<sup>n</sup>个元素,每次分划把一个段{分成两D,则经qnU递归法l止Q每一U递归的比较L为n, 所以QuickSort()的时间ؓ(f)O(nlog(n))Q这是^均情c(din)当原序列本w有序时QQuickSort()出现最坏情况,旉为O(n<sup>2</sup>)?/p> <img src ="http://www.shnenglu.com/zliner/aggbug/6825.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zliner/" target="_blank">依旧的博?/a> 2006-05-09 16:37 <a href="http://www.shnenglu.com/zliner/archive/2006/05/09/6825.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>多线E通信的机?/title><link>http://www.shnenglu.com/zliner/archive/2006/05/05/6630.html</link><dc:creator>依旧的博?/dc:creator><author>依旧的博?/author><pubDate>Thu, 04 May 2006 16:15:00 GMT</pubDate><guid>http://www.shnenglu.com/zliner/archive/2006/05/05/6630.html</guid><wfw:comment>http://www.shnenglu.com/zliner/comments/6630.html</wfw:comment><comments>http://www.shnenglu.com/zliner/archive/2006/05/05/6630.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/zliner/comments/commentRss/6630.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zliner/services/trackbacks/6630.html</trackback:ping><description><![CDATA[最原始的多U程通信机制是全局变量Q但是两个线E对同一变量的ƈ发操作可能是冲突的,所谓冲H是指一Uƈ发调度不{h(hun)于Q何串行调度。可以通过特定的系l调用保证线E对全局变量的操作具有原子性。这时全局变量成ؓ(f)一U可用的通信机制Q根据通信的需要设计通信的协议,两个U程分别执行Q就可以完成合作。比如辅U程重复某个q程直到ȝE通知它终止,可以U定全局变量为特定值时辅线E终止,让辅U程在@环中(g)全局变量Q主U程讄全局变量通知辅线E终止。这U机制的~点是接攉知的一方必M断检全局变量Q事件机制由此进行了(jin)改进。接收方可以在事件上dQ等待特定的通知Q等待的旉可以讑֮Q如果设?Q则事g退化ؓ(f)全局变量。事件只有两U状态,有信h无信Pq相对全局变量是一个限制。事件实C(jin)单向的消息,q是最基本的机制。在实际通信zd中还有许多同步问题,每一方不但根据特定的消息采取相应的动作,q在收到消息后发出反馈消息。通信是一个交互和持箋(hu)的过E。(f)界段机制是为此而提供的。(f)界段的局限是只有两种状态:(x)锁定和解锁,在很多的通信中,需要进一步量化的状态,q就产生?jin)信号量机制?img src ="http://www.shnenglu.com/zliner/aggbug/6630.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zliner/" target="_blank">依旧的博?/a> 2006-05-05 00:15 <a href="http://www.shnenglu.com/zliner/archive/2006/05/05/6630.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>COM基本概念和COM模型http://www.shnenglu.com/zliner/archive/2006/05/03/6601.html依旧的博?/dc:creator>依旧的博?/author>Wed, 03 May 2006 13:54:00 GMThttp://www.shnenglu.com/zliner/archive/2006/05/03/6601.htmlhttp://www.shnenglu.com/zliner/comments/6601.htmlhttp://www.shnenglu.com/zliner/archive/2006/05/03/6601.html#Feedback0http://www.shnenglu.com/zliner/comments/commentRss/6601.htmlhttp://www.shnenglu.com/zliner/services/trackbacks/6601.html1. 接口

接口是一l函数的集合(更一般情况下Q是一l函数和变量的集?Q对象和客户(E序的两个不同部?可通过它进行通信。接口有特定的内存结构,一个接口指针指向一个虚?vtbl)指针Q虚表是一个函数指针的数组Q每Ҏ(gu)向一个接口函数?br />
接口是概忉|的E序元素Q它hl承和多态性。(h)承性是指子接口l承?jin)基接口的所有函敎ͼ子接口可以{型ؓ(f)基接口。在实现上,子接口的虚表包括?jin)基接口的虚表,子接口的虚表指针可以转型为基接口的虚表指针。多态性是指一个基接口的不同子接口可以有不同的行ؓ(f)?br />
2. COM接口(lg模型Ҏ(gu)口的要求)

COM作ؓ(f)一U二q制lg模型Q要求对象和客户可能分,它们的一切联p都通过接口q行。一个对象可以有多个接口Q那么,客户在获得第一个接口指针后Q应当可以从一个接口指针查询下一个接口指针,以保持对象的使用。客户应当可以通过接口理对象的生命期Q以l束对象的用。作ZU设计,COM规定从对象的一个接口可以查询它的所有接口,对象生命期管理的责Q分散到每个接?只要客户为每个接口进行生命期理Q就可以实现对象的生命期理)。在实现上,COM接口查询和生命期管理的责Q集中C个IUnknown接口Q所有接口都从IUnknownz。COM接口是从IUnknownz的接口?/p>

2. COM的面向对象特?/p>COM在二q制上提供了(jin)一UY件结构模型,q且带有面向对象的特征?br />

  1. COM对象是有状态的Q数据和操作装在一赗COM接口和普通API函数的不同,在于COM对象是有状态的。比如一个宇宙飞船对?实现IMotion接口QIMotion包含void Fly(double dTime)和double GetPosition()函数)Q让它飞行一D|?通过IMotion接口调用Fly()函数)以后它的位置改变(sh)(jin)(在飞行前后调用GetPosition()得到不同l果)?/p>

  2. 多?

    同样的接口可以由不同的COM对象实现Q客L(fng)序用l一的方法进行处理,却可以得C同的l果。接口也可以zQ不同的子接口对基接口的函数有不同的实现?/p>

    在这里解释一下MFC实现COM对象的机制。一个COM对象可以实现多个接口Q而这些接口都是IUnknown的子接口Q它们对QueryInterface(), (tng) AddRef(), (tng) Release()各有一份实C码,而在同一对象内,q三个函数的内容完全相同Q因此可以抽出来Q委z该对象。又׃对Q何COM对象QAddRef()和Release()的实现本质上也相同,因此可以q一步,抽取q两个函数及(qing)其操作的数据(m_Ref)Q放到CCmdTarget中去。QueryInterface()的情冉|所不同Q它操作的数据是依赖于具体COM对象的接口映表Q可以在把函数放qCCmdTarget的同Ӟ实现一个返回接口映表的虚函数QQueryInterface()调用此函数获得具体的接口映射表?/p>

  3. 重用

    COM对象可以用包容和聚合两种方式重用已有的COM对象?/p>

    聚合方式实现重用比较复杂?br />
    在实现对象聚合时Q要解决的一个主要问题是在接口查询上对用户保持透明。客户从暴露出来的内部对象接口进行查询,应当查到的是外部对象的接口。那么收到查询时Q内部对象的IUnknown应当d托外部对象的IUnknown。但是内部对象也可能不被用于聚合Q应该有一个正常的IUnknown。这样可以考虑把内部对象最初收到查询的IUnknown设成一个代理,它根据聚合与否把查询h转交l外部对象IUnknown或内部对象的正常IUnknownQ即内部对象实现两个IUnknownQ作Z理的委托I(y)Unknown和正常的非委托I(y)Unknown。内部对象还要知道外部对象IUnknownQƈ且能判别自n是否被聚合。可以在创徏内部对象时把外部对象IUnknown指针传给它,不是聚合时传递一个空指针Q这样内部对象就得到?jin)够信息?/p>

    引用计数的管理也是一P内部对象的委托I(y)Unknown区别被聚合与否,调用外部对象IUnknown或自w的非委托I(y)Unknown?/p>

    当然Q从外部对象接口要能查到内部对象接口。外部对象需要知道内部对象的IUnknownQ以查询所要暴露给客户E序的接口。这个IUnknown应当是内部对象的非委托I(y)Unknown?/p>



]]>
排序的方?/title><link>http://www.shnenglu.com/zliner/archive/2006/05/03/6595.html</link><dc:creator>依旧的博?/dc:creator><author>依旧的博?/author><pubDate>Wed, 03 May 2006 09:40:00 GMT</pubDate><guid>http://www.shnenglu.com/zliner/archive/2006/05/03/6595.html</guid><wfw:comment>http://www.shnenglu.com/zliner/comments/6595.html</wfw:comment><comments>http://www.shnenglu.com/zliner/archive/2006/05/03/6595.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/zliner/comments/commentRss/6595.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zliner/services/trackbacks/6595.html</trackback:ping><description><![CDATA[如果有一个随机排列的整数表,怎样它排序呢?q是生活中也l常到的问题。比如给一l牌排序Q我们通常?x)怎样做呢Q?br /><br />不断从原序列中取出元素来排成一个新序列Q在新序列Ş成的时候保证它有序Q这是插入排序的办法。插入排序需要有I间存放和操作新序列Q这可以在原序列的空间中满。插入排序需要大量的比较和移动,量是O(n*n)。我们也可以每次从现有元素中取出最元素,q样新序列排下来自然是有序的Q这是选择排序的办法。选择排序需要O(n*n)的比较,最坏最好情况下都一栗这是一个缺点,和与之对U的插入排序比较Q选择排序对原序列的情늼乏适应性,冒(chng)排序是对此的改进。冒泡排序也基本使用原序列的I间Q每ơ在现有元素中进行比较以L最元素,q过交换逐步把它Ud相应位置。冒泡排序在原序列的基础上逐步调整得到新序列,它可以更加适应原序列的情况Q在最好情况下旉为O(n)。这三种排序是最基本的,其它Ҏ(gu)都是从各U角度对它们q行改进?br /><br />三种基本排序都着g从原序列形成新序列的q程。这是最基本的,但还可以把整个过E用分治或渐q的思想来处理。具体的改进Ҏ(gu)有多U,希尔排序Q快速排序,归ƈ排序{等Q我们现在可以欣赏它们的思想Q但是当初每U方法的发现都是重要的成果,需要对排序问题有扎实的认识Q也需要创造的灉|?br /><br />希尔排序把原序列分组Q每一l进行插入排序,从较?yu)的分组开始逐渐扩大Q直到整个序列作Zl。分l元素是间隔选取的,较小的分l排序完成后Q整个序列就在一个较大的度上有序了(jin)Q随着分组的扩大,序列在越来越的度上有序,直到完全有序。希?dng)排序利用插入排序对乐观情况的适应性,自顶向下渐进处理Q避免了(jin)直接在小度上进行处理的盲目性?br /><br />归ƈ排序反映ZU自底向上的分治思想Q其旉为O(n*log(n))?br /><br />快速排序采用了(jin)自顶向下的分L想Q其做法和归q排序有某种对称性?br /><br />基数排序也是自顶向下的分L想Q它从关键字本n衡量问题的解决程度?br /><br /><br /><img src ="http://www.shnenglu.com/zliner/aggbug/6595.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zliner/" target="_blank">依旧的博?/a> 2006-05-03 17:40 <a href="http://www.shnenglu.com/zliner/archive/2006/05/03/6595.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>数据库范式及(qing)其涵?/title><link>http://www.shnenglu.com/zliner/archive/2006/05/02/6562.html</link><dc:creator>依旧的博?/dc:creator><author>依旧的博?/author><pubDate>Tue, 02 May 2006 09:15:00 GMT</pubDate><guid>http://www.shnenglu.com/zliner/archive/2006/05/02/6562.html</guid><wfw:comment>http://www.shnenglu.com/zliner/comments/6562.html</wfw:comment><comments>http://www.shnenglu.com/zliner/archive/2006/05/02/6562.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/zliner/comments/commentRss/6562.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zliner/services/trackbacks/6562.html</trackback:ping><description><![CDATA[ <p dir="ltr" style="MARGIN-RIGHT: 0px">2NF以上的范式都是对关系上的依赖q行限制Q其中最重要的是3NF和BCNF?/p> <ul> <li> (tng)BCNFQ所有非q_依赖都以键为决定子。一个属性集只有包含?jin)整个的键,才能军_集外的属性? </li> <li>3NFQ其非^凡依赖X->A必须满QX是超键,或者A是主属性?NF比BCNF有所放松Q允许含键不完全的属性集军_集外的属性,但必Ld性? </li> <li>不符?NF的情冉|两种: <ol><li>键的真子集决定非d性,即非d性对键的部分依赖Q? </li><li>既非键也非键的真子集决定非d性,由此可证明Q存在非d性对键的传递依赖?/li></ol>如果一个关pM满2但满?Q称此关pȝ?NF?</li> </ul> <p>2NF?NF的涵义是Q键是关pȝ标识信息Q非d性是附属信息。如果附属信息对标识信息的依赖不够紧密,关系的语义单U性就差,从而容易出现各U更新异常?</p> <p>如果q反2NFQ既存在非主属性对键的部分依赖Q会(x)有什么问题?例如关系模式SCGT(S#,C#,G,TN)QS#是学生号QC#是课E号QG是成l,TN是Q课教师姓名,假设每门译֏有一个教师?S#,C#)是键QC#->TN是非d性对键的部分依赖Q因为它的存在会(x)产生三种更新异常Q?). 不开评教师姓名无法插入Q?). 一门课的所有学生都退选,则Q课教师姓名无法保留;3). 一门课更换教师Ӟ必须寚w该评所有学生进行修攏V非d性对键的部分依赖反映?jin)附属信息和标识信息的缺乏整体一致性,所以会(x)产生以上问题?/p> <p>如果W合2NFQ但q反3NFQ即存在非主属性对键的传递依赖,?x)有什么问题?例如关系模式SDL(S#,DEPT,LOC)QS#是学生号QDEPT是所在系QLOC是系的办公地Q这里S#是键QS#->DEPTQDEPT-/>S#QDEPT->LOCQLOC传递依赖于S#Q因为它的存在会(x)产生三种更新异常Q?). 如果一个系新成立尚未招生,则无法插入;2). 如果一个系不再招生Q但仍ؓ(f)其他pd课,则现有学生毕业后Q系的信息无法保留;3). 一个系更换办公地时Q必d该系的所有学生进行修攏V非d性对键的传递依赖反映了(jin)附属信息和标识信息缺乏直接一致性,所以会(x)产生以上问题。缺乏直接一致不如缺乏整体一致那样严重,所以到?NF才排除?/p> <p>那么BCNF的涵义在哪里呢?<br /><br />2NF?NF对一个关pL式中的非d性加以限Ӟ而忽略键之间的关pR如果一个主属性依赖含键不完全的属性组意味着什么呢Q可以证明,该依赖涉?qing)不止一个键Q其军_子有两种情况Q一U是部分键,一U是含部分键和键外的属性。第一U情况下存在一个键之外的属性对该键的部分依赖;W二U情况下Q取一个不含前qC属性的键,易知存在该属性对该键的传递依赖,即一个键外的属性对该键的传递依赖,排除q两U情况就得到BCNF。ؓ(f)什么要q样做呢Q因为有多个键的情况下,必须照顾每一个键Q如果键之外的属性和该键不能保持整体和直接的一_(d)也可能生更新异常。例如SCZ(S,C,Z)QSQCQZ分别表示街道Q城?jng),邮编Q关pL式上的依赖集为{SC->Z,Z->C}QSC和SZ都是键。如果插入一个城?jng)的总邮~,必须借助一个街道,删除q个街道Q城?jng)的总邮~也被删除,出现q种情况是因为C与SZ键缺乏整体一致性?br /><br /><br />参考:(x)</p> <p>王能斌《数据库pȝ教程??sh)子工业出版C?/p> <img src ="http://www.shnenglu.com/zliner/aggbug/6562.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zliner/" target="_blank">依旧的博?/a> 2006-05-02 17:15 <a href="http://www.shnenglu.com/zliner/archive/2006/05/02/6562.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C/S通信和W(xu)insock~程http://www.shnenglu.com/zliner/archive/2006/05/02/6553.html依旧的博?/dc:creator>依旧的博?/author>Tue, 02 May 2006 04:46:00 GMThttp://www.shnenglu.com/zliner/archive/2006/05/02/6553.htmlhttp://www.shnenglu.com/zliner/comments/6553.htmlhttp://www.shnenglu.com/zliner/archive/2006/05/02/6553.html#Feedback0http://www.shnenglu.com/zliner/comments/commentRss/6553.htmlhttp://www.shnenglu.com/zliner/services/trackbacks/6553.html

1. 客户-服务器通信中的基本问题

客户和服务器通信是ؓ(f)?jin)用服务,为此在传输机制的基础上设计协议,通过寚w信行ؓ(f)的规范,实现通信的目的,q解决传输中的问题?/p>

传输机制通常׃层协议提供,Ҏ(gu)不同的通信需要选择不同的下层协议,q是一个基本的问题。对应用协议来说Q可用的传输机制有可靠连接的字节类型和不可靠无q接的数据报cd?/p>

服务器处理大量客L(fng)hQ从而ƈ发是服务器的一个基本问题,如何处理q个问题?sh)取决于通信需要。处理方式上Q服务器可以是@环的或ƈ发的Qƈ发服务器有多U实现方?异步I/OQ多U程和多q程)?/p>

一件事情能无重复地q箋(hu)q行Q通常?x)获得更好的效率Q这要求M始终知道当前的状态。一ơ通信q程的连l性取决于通信双方Q它们都要知道通信q行的状态。这对客户一般不成问题,但服务器要和大量客户通信Q不一定能为每个客L(fng)每次通信保存状态。如果服务器是有状态的Q那么就更快地计响应,减少通信的数据量。但是传输和客户的故障有状态服务器面(f)很大问题Q当传输不可?报文重复Q丢失,乱序)Ӟ服务器维护的状态会(x)和客户失M_(d)一个不断崩溃重启的客户?x)造成状态信息不能发挥作用,而维护开销却极大增加?/p>

q就提出?jin)客?服务器通信中的三个基本问题Q它们的解决Ҏ(gu)都取决于实际需要,客户-服务器通信中有哪些情况的需要呢Q?/p>

  • 是否要求可靠传输Q?
  • 是否需要服务器q行大量处理。对循环服务器进行分析可以知道,需要大量处理的通信用@环方案可能会(x)丢失hQ用q发Ҏ(gu)q可以提高服务器资源利用率,改善性能Q只要少量处理的通信则无法忍受开销大的解决Ҏ(gu)?
  • 在局域网q是互联|环境下Q局域网中传输很出错,互联|环境则不然Q?


通常Ҏ(gu)前两个基本问题把服务器实现分为四U类型,它们的适用范围如下Q?/p>

  • 循环无连接服务器Q少量处理的通信Ӟq且在局域网中或不要求可靠传输。这U做法主要是Z(jin)避免开销?
  • 循环q接服务器,较少用,主要是@环的方式不够高效Q因接有一定开销Q响应时间可能不低。在量处理q要求可靠性的情况下用?
  • q发无连接服务器Q很用Q因l每个请求开U程Q开销太大。在不要求可靠性的情况下,如果U程开销q小于计响应开销Q或者ƈ发可以让各请求的I/Oq行Q或者@环方案会(x)丢失h时可以考虑?
  • q发q接服务器,常用?


2. winsock基本函数的?/p>

winsock的基本函数有WSAStartup()QW(xu)SACleanup()Qsocket()Qclosesocket()Qbind()Qlisten()Qaccept()Q?connect()Qsend()和recv()?/p>

使用q些函数Q客L(fng)的大概算法是Q?/p>

  1.  调用WSAStartup()初始化winsock库?
  2.  调用socket()创徏套接字,q回套接字描q符s?
  3.  指定q程套接字地址saQ对s调用connect()Q向sa标识的服务进E请求连接?
  4.  q接成功后,对s调用send()发送请求,调用recv()接收响应Q如此反复直到完成Q务?
  5.  对s调用closesocket()关闭q接?
  6.  不再发vq接处理新的dӞ调用WSACleanup()释放winsock库?

服务器端的大概算法是Q?/p>

  1. 调用WSAStartup()初始化winsock库?
  2. 调用socket()创徏套接字,q回套接字描q符s?
  3. 对s调用bind()Q将其绑定到本地的套接字sa?
  4. 调用listen()Q将s|ؓ(f)被动模式。此时开始侦听客L(fng)的连接请求,其攑օ一个队列?
  5. 对s调用accept()Q即从请求队列中取出一,接受该连接后q回一个新的套接字描述Ws'Q以?qing)对应客L(fng)的套接字地址sa'?
  6. 对s'调用recv()接收hQ调用send()发送响应,如此反复直到完成d?
  7. 对s'调用closesocket()关闭该连接?
  8. 重复5?的过E?
  9. ?退出后Q调用WSACleanup()释放winsock库?

有以下几炚w要进一步说明,

1). 客户端调用connect()和服务器端调用accept()成功后将在客戯E和服务器进E之间徏立一个TCPq接。连接两端的每个套接字描q符都包含一个本地端点地址和一个远E端点地址。所以在使用q接套接字发送数据时不用指示目的地址?/p>

2). 多宿M机的IP地址选择问题。从上面的算法容易提?gu)L(fng)问题Qؓ(f)什么客L(fng)在用套接字时不l定端点地址Q通常的主机只有一个IPQ但是多宿主L有多个IP地址Q在q种情况下,客户端ؓ(f)套接字指定的IP可能与实际发送时l过的IP不符Q所以允许客L(fng)不指定套接字地址Q而由TCP/IP软g在实际发送时指定IPQ同旉择一个未用过的端口号Q这正是在connect()调用中完成的。那么服务器端就不存在同L(fng)情况吗?不是Q在它调用bind()时指定一个套接字地址Q其端口部分采用应用协议的熟知端口,而IP地址部分有着同样的问题。ؓ(f)此定义了(jin)一个代表统配地址的常量INADDR_ANYQ用它指CIP地址部分。实际用的IP仍然是由TCP/IP软g分配?/p>

3). TCPZ个连接的发送端和接收端各维护一个缓冲区。当发送端~冲区满的时候,send()调用?x)阻塞,在接收端~冲Zؓ(f)I的时候,recv()调用?x)阻塞。ؓ(f)什么要在通信q程和TCPq接之间l护一个间接层呢?可能是ؓ(f)?jin)在一端有多个q程要用信道的情况下,在多个进E之间进行信道分配的协调。比如在发送端Q信道传输数据时send()调用可以l箋(hu)执行Q多个进E的send()调用同缓冲区打交道,彼此影响不大Q因写缓冲区速度很快Q而信道同~冲区打交道Q这时可以对各进E的发送数据进行协调,实现公^的信道分配。另外,在TCP中有滑动H口概念Q是用于量控制的,前述~冲区和滑动H口有什么关p?我现在不太清楚?/p>

4). 套接字的关闭问题。在客户机和服务器通过TCPq接完成数据交换后,有一个安全关闭的问题。一斚wQ服务器不能关闭q接Q因为客h可能q有hQ另一斚wQ客h虽然知道何时不再hQ但是它不知道服务器的响应何时发送完Q因为有些应用协议的响应数据量不定。ؓ(f)此采用部分关闭的办法Q虽然连接是双向的,但是允许在一个方向上关闭它,当客L(fng)不再hӞ可以部分关闭q接Q服务器收C个信P如果响应发送完?jin),服务器就可以关闭q接Q此时连接被完全关闭

3. 套接字接口中的端点地址

端点地址用来表示通信的进E,是传输层协议?qing)其套接字接口中的重要概c(din)不同的协议族可以用不同方式表示端点地址Q一个协议族q可以有多个地址族,每个地址族的地址格式不同。TCP/IP只有一个地址族,它的端点地址包括一?2位IP地址和一?6位端口号。在协议族和地址族的基础上,套接字接口用更ؓ(f)具体的结构来表示端点地址?/p>

套接字是一U适用于多个协议族的接口,q允怸个协议族使用多个地址族。TCP/IP协议族及(qing)其唯一地址族的标识分别是PF_INET和AF_INET。由于套接字接口的通用性,它提供一个通用的地址l构Q其格式?地址族,该族中的套接字地址)。套接字作ؓ(f)一个接口标准,可以有不同实玎ͼ以下我们只讨论windows套接字?/p>

如下定义的sockaddr实现?jin)前q通用地址l构Q?/p>

// winsock2.h

struct sockaddr {
        u_short sa_family;              /* address family */
        char    sa_data[14];            /* up to 14 bytes of direct address */
};

sockaddr的通用性是相对的,某些地址族不适合q个l构?/p>

管sockaddr适合于TCP/IP协议族,但是winsockq定义了(jin)TCP/IP专用的地址格式Q?/p>

// winsock2.h

struct sockaddr_in {
        short   sin_family;
        u_short sin_port;
        struct  in_addr sin_addr;
        char    sin_zero[8];
};

sin_family域取值恒为AF_INET。其中的in_addrl构表示IP地址Q定义如下,

//winsock2.h

struct in_addr {
        union {
                struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
                struct { u_short s_w1,s_w2; } S_un_w;
                u_long S_addr;
        } S_un;
#define s_addr  S_un.S_addr
                                /* can be used for most TCP & IP code */
#define s_host  S_un.S_un_b.s_b2
                                /* host on imp */
#define s_net   S_un.S_un_b.s_b1
                                /* network */
#define s_imp   S_un.S_un_w.s_w2
                                /* imp */
#define s_impno S_un.S_un_b.s_b4
                                /* imp # */
#define s_lh    S_un.S_un_b.s_b3
                                /* logical host */
};

Z(jin)保证软g的可UL性与可维护性,讉KTCP/IP的代码不应用sockaddr。只使用TCP/IP的应用程序可以只使用sockaddr_inQ而永q不用sockaddr?/p>

4. winsockE序实例

《vc6技术内q》的例程ex34a包括一个web服务器和三个客户Q服务器用winsock实现Q一个客L(fng)winsockQ另两个用wininet。我们以winsock实现的服务器和客户ؓ(f)例?/p>

CBlockingSocket对各接口函数q行装Q它们的调用可以统一报错。把错误(g)查和函数调用一起封装可以避免每ơ调用这些函数时都检错。ؓ(f)l一报错Q采用了(jin)异常机制Q在(g)出错误后抛出异常Q然后统一q行异常处理。异常机制我们可以把错误检查和错误处理分开Q检查必L分散的,但是处理可以适当集中Q代码化?/p>

CHttpBlockingSocketҎ(gu)接收http报文的特点对CBlockingSocketq行?jin)扩展。成员函数ReadHttpHeaderLine()可以从TCPq接中按行接收字W?它引入了(jin)一个缓冲区Q缓冲区中收到的字符构成一行后再输出。该~冲区的长度需要能够容Ux(chng)一行字W,溢出时报错。接收输?gu)的缓冲区也可能长度不Iq时接收的数据不一行,在调用ReadHttpHeaderLine()时要注意q一?QReadHttpResponse()用于接收首部行之后所有的响应Q当调用者提供的~冲Zx(chng)?x)报错。缓冲区不的情况都是在CBlockingSocket::Receive()函数中检到的,该函数调用以上层ơ中的代码按照正常情늼写?/p>

CSockAddr是一个与sockaddr_in同样用途的c,但是用法更方ѝwinsock函数使用的端点地址l构是sockaddrQsockaddr_in本n用来代替它,所以CSockAddr需要能够替代sockaddr。sockaddr可能用在传值或传址参数中,CSockAddr必须在逻辑上和存储上都和sockaddr有等h,q实现有兛_制类型{换。CSockAddrq实C(jin)和sockaddr, sockaddr_in互相转换的成员函敎ͼ因ؓ(f)一U结构很隑֜所有情况下都好用,新结构也需要和旧结构保持兼宏V?br>

 

本例中采用服务器关闭套接字的办法Q因为每ơ连接只处理一个请求?br>
参考:(x)

《用TCP/IPq行|际互联W三?windows套接字版)?清华出版C?/p>

《vc6技术内q?5th ed?希望?sh)子出版C?/p>

]]>
论面向对?/title><link>http://www.shnenglu.com/zliner/archive/2006/05/02/6552.html</link><dc:creator>依旧的博?/dc:creator><author>依旧的博?/author><pubDate>Tue, 02 May 2006 04:44:00 GMT</pubDate><guid>http://www.shnenglu.com/zliner/archive/2006/05/02/6552.html</guid><wfw:comment>http://www.shnenglu.com/zliner/comments/6552.html</wfw:comment><comments>http://www.shnenglu.com/zliner/archive/2006/05/02/6552.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/zliner/comments/commentRss/6552.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zliner/services/trackbacks/6552.html</trackback:ping><description><![CDATA[<p>软g中的对象同领域中的概忉|着密切的关pR?/p> <p>我们知道概念是h们在某个领域中实늻验的ȝQƈ可能发展为理论。概忉|以客观事物ؓ(f)基础Q但不是对客观事物的L反映。它来自于实践,所以包含主体因素,q是很重要的。实跉|概念的根本来源,理论上的需要对概念形成也有一些作用?/p> <p>软g中用的对象cM于领域中使用的概c(din)《UML与模式应用》中_(d)面向对象是按照概念而不是功能进行分解。ؓ(f)什么Y件要使用概念性元素呢Q因Zh的认识是概念性的Q而Y件由人来使用Qh来开发。ؓ(f)?jin)提供有良好概念性的用户接口QY件本w适宜采用概念性元素。由人来开发的软g则更需要采用概忉|元素,软g本n和领域实践都有巨大的复杂性,Z是按照功能性元素来思考的Q面向对象可以让开发h员用概念性元素思考,从而增加对复杂性的适应和控制能力?/p> <p>领域概念是对象的重要来源Q但是对象也形成于Y件开发的q程。一斚wQY件的使用没有改变领域实践的本质,臛_没有完全改变Q而概念反映了(jin)领域中已l成熟的认识Q所以是非常重要的指导和参考。另一斚wQ领域实는软gq行和由行确实非怸同,要求q行新的认识QY件本w的需要也?x)?jing)响到对象的Ş成?/p> <p>面向对象的基本特征反映着概念的基本特征?/p> <ol> <li>装Q概念不是静(rn)态的Q它的属性和操作不可分? <li>通信Q概念不是孤立的Q概늚属性可以其他概忉|成,也可以在属性中引用其他概念Q概늚操作q程中会(x)用到其它的概c(din)? <li>抽象Q从具体概念可以q一步生抽象概c(din)? <li>多态:(x)抽象概念有着多样的具体表现?/li> </ol> <p>Stroustrup的《C++E序设计语言》中_(d)(x)</p> <p>“cd该用于模拟程序员的和应用的世界里的那些概c(din)?..一个概念不?x)孤立地存在Q它M一些相关的概念共存Qƈ在与相关概念的相互关pM表现出它的大部分力量?..因ؓ(f)我们要用c表C概念,问题变成了(jin)如何去表C概念之间的关系。然而,我们无法在程序语a里表qCQ意的关系。即使能q样做,我们也未必想d它。我们的cd该定义得比日常概忉|H一些——而且也更_?#8221;</p> <p>我们可以体会(x)q段话的深刻性?/p> <ol> <li>cȝ来定义概c(din)首先,概念不是?rn)态的Q它的属性和操作不可分,装是面向对象的W一个特征。然后,概念不是孤立的,一个概忉|L与相x(chng)念共存,最基本的关pL两对Q封装和通信Q抽象和多态。前者反映了(jin)分工与合作关p,后者反映了(jin)抽象与具体关pR类是面向对象的核心(j)Q从探讨cȝ作用出发Q就引出?jin)面向对象的四个基本特征? <li>cL定义的概念不但来自应用领域,也来自程序员引入的东ѝ? <li>“我们无法在程序语a里表qCQ意的关系。即使能q样做,我们也未必想d它?#8221; </li> </ol> <img src ="http://www.shnenglu.com/zliner/aggbug/6552.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zliner/" target="_blank">依旧的博?/a> 2006-05-02 12:44 <a href="http://www.shnenglu.com/zliner/archive/2006/05/02/6552.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <p>лǵվܻԴȤ</p> <a href="http://www.shnenglu.com/" title="精品视频久久久久">精品视频久久久久</a> <div class="friend-links"> </div> </div> </footer> <a href="http://www.jn879.cn" target="_blank">ȾþùŷһƷ</a>| <a href="http://www.okboom.cn" target="_blank">þþƷҹҹŷ </a>| <a href="http://www.ghoststory.cn" target="_blank">ھƷþþþþòӰԺ</a>| <a href="http://www.hunxueer.cn" target="_blank">޾Ʒþǧն</a>| <a href="http://www.dgyjte580.cn" target="_blank">þɫۺһ</a>| <a href="http://www.nsimple.cn" target="_blank">þþƷ99þ˿</a>| <a href="http://www.rojie.cn" target="_blank">Ʒ˾þþþþþ</a>| <a href="http://www.areall.cn" target="_blank">aëƬ÷˾þ</a>| <a href="http://www.z8990.cn" target="_blank">ƷþþþӰӲ</a>| <a href="http://www.jihejingjia.cn" target="_blank">97þóƷɰ</a>| <a href="http://www.pluv.cn" target="_blank">þۺ</a>| <a href="http://www.tzcn86.cn" target="_blank">þþƷŷ</a>| <a href="http://www.ksxhsd.cn" target="_blank">ھƷþþþþþþõӰ</a>| <a href="http://www.jire1z.cn" target="_blank">鶹ŷۺϾþ</a>| <a href="http://www.huangjisoo.cn" target="_blank">޾Ʒþ</a>| <a href="http://www.duopudz.cn" target="_blank">ŷaƬѿþ</a>| <a href="http://www.omrk.cn" target="_blank">޾Ʒþò</a>| <a href="http://www.zhaozhounews.cn" target="_blank">һþaþþƷvrۺ</a>| <a href="http://www.mdz8.cn" target="_blank">þۺϺݺۺϾþ</a>| <a href="http://www.yueyuju.cn" target="_blank">2020¾þþӾƷ</a>| <a href="http://www.hkzkzs.com.cn" target="_blank">Ʒþþþþù</a>| <a href="http://www.eca2000.cn" target="_blank">þþƷަvDz </a>| <a href="http://www.dangqie.cn" target="_blank">ɫݺݾþAVۺ</a>| <a href="http://www.changde8.cn" target="_blank">þۺϸþúݺ97ɫ</a>| <a href="http://www.zyxslswx.cn" target="_blank">þþƷƵ</a>| <a href="http://www.ldzv.cn" target="_blank">ԾþþӰԺ</a>| <a href="http://www.3495.com.cn" target="_blank">þþƷAVȫ</a>| <a href="http://www.jhyjpj.cn" target="_blank">ƷŮٸaѾþ</a>| <a href="http://www.ersunle.cn" target="_blank">þù׽</a>| <a href="http://www.asyb.com.cn" target="_blank">þۺ88</a>| <a href="http://www.qdog.com.cn" target="_blank">þҹɫƷwww</a>| <a href="http://www.ftfygs.cn" target="_blank">þˬˬˬ˾þþ</a>| <a href="http://www.k443.cn" target="_blank">þþþӰԺŮ</a>| <a href="http://www.sme88.cn" target="_blank">Ʒþ¶</a>| <a href="http://www.8910wan.cn" target="_blank">Ʒʾþþþ999Ұ</a>| <a href="http://www.mhlz4f.cn" target="_blank">ھƷŷþþƷ</a>| <a href="http://www.zwdl.com.cn" target="_blank">þþþŷղAV </a>| <a href="http://www.uqknet.cn" target="_blank">þþƷ޾Ʒ2020 </a>| <a href="http://www.zhidaow.com.cn" target="_blank">ƷŷƬþùŷ</a>| <a href="http://www.ajchugui.cn" target="_blank">2019þþø456</a>| <a href="http://www.yiyaosheji.cn" target="_blank">þþƷѹۿ</a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>