﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-云的天空</title><link>http://www.cppblog.com/yunboy4/</link><description>C++</description><language>zh-cn</language><lastBuildDate>Thu, 16 Apr 2026 09:24:54 GMT</lastBuildDate><pubDate>Thu, 16 Apr 2026 09:24:54 GMT</pubDate><ttl>60</ttl><item><title>CString详细讲解(转载)</title><link>http://www.cppblog.com/yunboy4/archive/2009/07/31/91800.html</link><dc:creator>yunboy</dc:creator><author>yunboy</author><pubDate>Fri, 31 Jul 2009 05:46:00 GMT</pubDate><guid>http://www.cppblog.com/yunboy4/archive/2009/07/31/91800.html</guid><wfw:comment>http://www.cppblog.com/yunboy4/comments/91800.html</wfw:comment><comments>http://www.cppblog.com/yunboy4/archive/2009/07/31/91800.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yunboy4/comments/commentRss/91800.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yunboy4/services/trackbacks/91800.html</trackback:ping><description><![CDATA[<p>CString详细讲解<br>&nbsp;前言：串操作是编程中最常用也最基本的操作之一。 做为VC程序员，无论是菜鸟或高手都曾用过Cstring。而且好像实际编程中很难离得开它（虽然它不是标准Ｃ++中的库）。因为MFC中提供的这个类对我们操作字串实在太方便了，CString不仅提供各种丰富的操作函数、操作符重载，使我们使用起串起来更象basic中那样直观；而且它还提供了动态内存分配，使我们减少了多少字符串数组越界的隐患。但是，我们在使用过程中也体会到CString简直太容易出错了，而且有的不可捉摸。所以有许多高人站过来，建议抛弃它。 </p>
<p>在此，我个人认为：CString封装得确实很完美，它有许多优点，如&#8220;容易使用 ，功能强，动态分配内存，大量进行拷贝时它很能节省内存资源并且执行效率高，与标准Ｃ完全兼容，同时支持多字节与宽字节，由于有异常机制所以使用它安全方便&#8221; 其实，使用过程中之所以容易出错，那是因为我们对它了解得还不够，特别是它的实现机制。因为我们中的大多数人，在工作中并不那么爱深入地去看关于它的文档，何况它还是英文的。 </p>
<p>由于前几天我在工作中遇到了一个本不是问题但却特别棘手、特别难解决而且莫名惊诧的问题。好来最后发现是由于CString引发的。所以没办法，我把整个CString的实现全部看了一遍，才慌然大悟，并彻底弄清了问题的原因(这个问题，我已在csdn上开贴)。在此，我想把我的一些关于CString的知识总结一番，以供他（她）人借鉴，也许其中有我理解上的错误，望发现者能通知我，不胜感谢。</p>
<p><br>1． CString实现的机制.</p>
<p>CString是通过&#8220;引用&#8221;来管理串的，&#8220;引用&#8221;这个词我相信大家并不陌生，象Window内核对象、COM对象等都是通过引用来实现的。而CString也是通过这样的机制来管理分配的内存块。实际上CString对象只有一个指针成员变量,所以任何CString实例的长度只有4字节.</p>
<p>即: int len = sizeof(CString);//len等于4</p>
<p>这个指针指向一个相关的引用内存块，如图: CString str("abcd");</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><br>&#8216;A&#8217;</p>
<p>&#8216;B&#8217;</p>
<p>&#8216;C&#8217;</p>
<p>&#8216;D&#8217;</p>
<p>0</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>0x04040404 head部，为引用内存块相关信息</p>
<p><br>str 0x40404040</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><br>正因为如此，一个这样的内存块可被多个CString所引用，例如下列代码：</p>
<p>CString str("abcd");</p>
<p>CString a = str;</p>
<p>CString b(str);</p>
<p>CString c;</p>
<p>c = b;</p>
<p>上面代码的结果是：上面四个对象(str,a,b,c)中的成员变量指针有相同的值，都为0x40404040.而这块内存块怎么知道有多少个CString引用它呢？同样，它也会记录一些信息。如被引用数，串长度，分配内存长度。</p>
<p>这块引用内存块的结构定义如下：</p>
<p>struct CStringData</p>
<p>{</p>
<p>long nRefs; //表示有多少个CString 引用它. 4</p>
<p>int nDataLength; //串实际长度. 4</p>
<p>int nAllocLength; //总共分配的内存长度（不计这头部的12字节）. 4</p>
<p>};</p>
<p>由于有了这些信息，CString就能正确地分配、管理、释放引用内存块。</p>
<p>如果你想在调试程序的时候获得这些信息。可以在Watch窗口键入下列表达式：</p>
<p>(CStringData*)((CStringData*)(this-&gt;m_pchData)-1)或</p>
<p>(CStringData*)((CStringData*)(str.m_pchData)-1)//str为指CString实例</p>
<p><br>正因为采用了这样的好机制，使得CString在大量拷贝时，不仅效率高，而且分配内存少。</p>
<p>&nbsp;</p>
<p>2．LPCTSTR 与 GetBuffer(int nMinBufLength) </p>
<p>这两个函数提供了与标准C的兼容转换。在实际中使用频率很高，但却是最容易出错的地方。这两个函数实际上返回的都是指针，但它们有何区别呢？以及调用它们后，幕后是做了怎样的处理过程呢？</p>
<p>(1) LPCTSTR 它的执行过程其实很简单，只是返回引用内存块的串地址。 它是作为操作符重载提供的，所以在代码中有时可以隐式转换，而有时却需强制转制。如：</p>
<p>CString str;</p>
<p>const char* p = (LPCTSTR)str;</p>
<p>//假设有这样的一个函数，Test(const char* p)； 你就可以这样调用</p>
<p>Test(str);//这里会隐式转换为LPCTSTR</p>
<p>(2) GetBuffer(int nMinBufLength) 它类似，也会返回一个指针，不过它有点差别,返回的是LPTSTR</p>
<p>(3) 这两者到底有何不同呢？我想告诉大家，其本质上完全不一样，一般说LPCTSTR转换后只应该当常量使用，或者做函数的入参；而GetBuffer(...)取出指针后，可以通过这个指针来修改里面的内容，或者做函数的出参。为什么呢？也许经常有这样的代码：</p>
<p>CString str("abcd");</p>
<p>char* p = (char*)(const char*)str;</p>
<p>p[2] = 'z'; </p>
<p>其实，也许有这样的代码后，你的程序并没有错，而且程序也运行得挺好。但它却是非常危险的。再看</p>
<p>CString str("abcd");</p>
<p>CString test = str;</p>
<p>....</p>
<p>char* p = (char*)(const char*)str;</p>
<p>p[2] = 'z'; </p>
<p>strcpy(p, "akfjaksjfakfakfakj");//这下完蛋了 </p>
<p>你知道此时，test中的值是多少吗？答案是"abzd"。它也跟着改变了，这不是你所期望发生的。但为什么会这样呢？你稍微想想就会明白，前面说过，因为CString是指向引用块的，str与test指向同一块地方,当你p[2]='z'后，当然test也会随着改变。所以用它做LPCTSTR做转换后，你只能去读这块数据，千万别去改变它的内容。</p>
<p><br>假如我想直接通过指针去修改数据的话，那怎样办呢？就是用GetBuffer(...).看下述代码：</p>
<p>CString str("abcd");</p>
<p>CString test = str;</p>
<p>....</p>
<p>char* p = str.GetBuffer(20);</p>
<p>p[2] = 'z'; // 执行到此，现在test中值却仍是"abcd"</p>
<p>strcpy(p, "akfjaksjfakfakfakj"); // 执行到此，现在test中值还是"abcd"</p>
<p>为什么会这样？其实GetBuffer(20)调用时，它实际上另外建立了一块新内块存，并分配20字节长度的buffer，而原来的内存块引用计数也相应减1. 所以执行代码后str与test是指向了两块不同的地方，所以相安无事。</p>
<p>(4) 不过这里还有一点注意事项：就是str.GetBuffer(20)后，str的分配长度为20，即指针p它所指向的buffer只有20字节长，给它赋值时，切不可超过，否则灾难离你不远了；如果指定长度小于原来串长度，如GetBuffer(1),实际上它会分配4个字节长度（即原来串长度）；另外，当调用GetBuffer(...)后并改变其内容，一定要记得调用ReleaseBuffer(),这个函数会根据串内容来更新引用内存块的头部信息。</p>
<p>(5) 最后还有一注意事项，看下述代码：</p>
<p>char* p = NULL;</p>
<p>const char* q = NULL;</p>
<p>{</p>
<p>CString str = "abcd";</p>
<p>q = (LPCTSTR)str;</p>
<p>p = str.GetBuffer(20);</p>
<p>AfxMessageBox(q);// 合法的</p>
<p>strcpy(p, "this is test");//合法的，</p>
<p>}</p>
<p>AfxMessageBox(q);// 非法的，可能完蛋</p>
<p>strcpy(p, "this is test");//非法的，可能完蛋</p>
<p>这里要说的就是，当返回这些指针后， 如果CString对象生命结束，这些指针也相应无效。</p>
<p><br>3．拷贝 &amp; 赋值 &amp; "引用内存块" 什么时候释放？</p>
<p><br>下面演示一段代码执行过程</p>
<p>void Test()</p>
<p>{</p>
<p>CString str("abcd");</p>
<p>//str指向一引用内存块（引用内存块的引用计数为1,长度为4,分配长度为4）</p>
<p>CString a;</p>
<p>//a指向一初始数据状态，</p>
<p>a = str;</p>
<p>//a与str指向同一引用内存块（引用内存块的引用计数为2,长度为4,分配长度为4）</p>
<p>CString b(a);</p>
<p>//a、b与str指向同一引用内存块（引用内存块的引用计数为3,长度为4,分配长度为4）</p>
<p>{</p>
<p>LPCTSTR temp = (LPCTSTR)a;</p>
<p>//temp指向引用内存块的串首地址。（引用内存块的引用计数为3,长度为4,分配长度为4）</p>
<p>CString d = a;</p>
<p>//a、b、d与str指向同一引用内存块（引用内存块的引用计数为4, 长度为4,分配长度为4）</p>
<p>b = "testa";</p>
<p>//这条语句实际是调用CString::operator=(CString&amp;)函数。 b指向一新分配的引用内存块。（新分配的引用内存块的 引用计数为1, 长度为5, 分配长度为5）</p>
<p>//同时原引用内存块引用计数减1. a、d与str仍指向原 引用内存块（引用内存块的引用计数为3,长度为4,分配长度为4） </p>
<p>}</p>
<p>//由于d生命结束，调用析构函数，导至引用计数减1（引用内存块的引用计数为2,长度为4,分配长度为4）</p>
<p>LPTSTR temp = a.GetBuffer(10);</p>
<p>//此语句也会导致重新分配新内存块。temp指向新分配引用内存块的串首地址（新 分配的引用内存块的引用计数为1,长度为0,分配长度为10）</p>
<p>//同时原引用内存块引用计数减1. 只有str仍 指向原引用内存块 （引用内存块的引用计数为1, 长度为4, 分配长度为4） </p>
<p>strcpy(temp, "temp"); </p>
<p>//a指向的引用内存块的引用计数为1,长度为0,分配长度为10 a.ReleaseBuffer();//注意:a指向的引用内存块的引用计数为1,长度为4,分配长度为10</p>
<p>}</p>
<p>//执行到此，所有的局部变量生命周期都已结束。对象str a b 各自调用自己的析构构</p>
<p>//函数，所指向的引用内存块也相应减1</p>
<p>//注意，str a b 所分别指向的引用内存块的计数均为0,这导致所分配的内存块释放</p>
<p><br>通过观察上面执行过程，我们会发现CString虽然可以多个对象指向同一引用内块存，但是它们在进行各种拷贝、赋值及改变串内容时，它的处理是很智能并且非常安全的，完全做到了互不干涉、互不影响。当然必须要求你的代码使用正确恰当，特别是实际使用中会有更复杂的情况，如做函数参数、引用、及有时需保存到CStringList当中，如果哪怕有一小块地方使用不当，其结果也会导致发生不可预知的错误</p>
<p><br>5 FreeExtra()的作用</p>
<p>看这段代码</p>
<p>(1) CString str("test");</p>
<p>(2) LPTSTR temp = str.GetBuffer(50);</p>
<p>(3) strcpy(temp, "there are 22 character");</p>
<p>(4) str.ReleaseBuffer();</p>
<p>(5) str.FreeExtra();</p>
<p>上面代码执行到第(4)行时，大家都知道str指向的引用内存块计数为1,长度为22,分配长度为50. 那么执行str.FreeExtra()时，它会释放所分配的多余的内存。(引用内存块计数为1,长度为22,分配长度为22)</p>
<p><br>6 Format(...) 与 FormatV(...)</p>
<p>这条语句在使用中是最容易出错的。因为它最富有技巧性，也相当灵活。在这里，我没打算对它细细分析，实际上sprintf(...)怎么用，它就怎么用。我只提醒使用时需注意一点：就是它的参数的特殊性，由于编译器在编译时并不能去校验格式串参数与对应的变元的类型及长度。所以你必须要注意，两者一定要对应上，</p>
<p>否则就会出错。如：</p>
<p>CString str;</p>
<p>int a = 12;</p>
<p>str.Format("first:%l, second: %s", a, "error");//result?试试</p>
<p><br>7 LockBuffer() 与 UnlockBuffer()</p>
<p>顾名思议，这两个函数的作用就是对引用内存块进行加锁及解锁。但使用它有什么作用及执行过它后对CString串有什么实质上的影响。其实挺简单，看下面代码:</p>
<p>(1) CString str("test");</p>
<p>(2) str.LockBuffer();</p>
<p>(3) CString temp = str;</p>
<p>(4) str.UnlockBuffer();</p>
<p>(5) str.LockBuffer();</p>
<p>(6) str = "error";</p>
<p>(7) str.ReleaseBuffer();</p>
<p>执行完(3)后，与通常情况下不同，temp与str并不指向同一引用内存块。你可以在watch窗口用这个表达式(CStringData*)((CStringData*)(str.m_pchData)-1)看看。</p>
<p>其实在msdn中有说明：</p>
<p>While in a locked state, the string is protected in two ways: </p>
<p><br>No other string can get a reference to the data in the locked string, even if that string is assigned to the locked string.</p>
<p>The locked string will never reference another string, even if that other string is copied to the locked string. </p>
<p><br>8 CString 只是处理串吗？</p>
<p>不对，CString不只是能操作串，而且还能处理内存块数据。功能完善吧！看这段代码</p>
<p>char p[20];</p>
<p>for(int loop=0; loop&lt;sizeof(p); loop++)</p>
<p>{</p>
<p>p[loop] = 10-loop;</p>
<p>}</p>
<p>CString str((LPCTSTR)p, 20);</p>
<p>char temp[20];</p>
<p>memcpy(temp, str, str.GetLength());</p>
<p>str完全能够转载内存块p到内存块temp中。所以能用CString来处理二进制数据</p>
<p><br>8 AllocSysString()与SetSysString(BSTR*) </p>
<p>这两个函数提供了串与BSTR的转换。使用时须注意一点：当调用AllocSysString()后，须调用它SysFreeString(...) </p>
<p><br>9 参数的安全检验</p>
<p>在MFC中提供了多个宏来进行参数的安全检查，如：ASSERT. 其中在CString中也不例外，有许多这样的参数检验，其实这也说明了代码的安全性高，可有时我们会发现这很烦，也导致Debug与Release版本不一样，如有时程序Debug通正常，而Release则程序崩溃；而有时恰相反，Debug不行，Release行。其实我个人认为，我们对CString的使用过程中，应力求代码质量高，不能在Debug版本中出现任何断言框，哪怕release运行似乎看起来一切正常。但很不安全。如下代码：</p>
<p>(1) CString str("test");</p>
<p>(2) str.LockBuffer();</p>
<p>(3) LPTSTR temp = str.GetBuffer(10);</p>
<p>(4) strcpy(temp, "error");</p>
<p>(5) str.ReleaseBuffer();</p>
<p>(6) str.ReleaseBuffer();//执行到此时，Debug版本会弹出错框</p>
<p><br>10 CString的异常处理</p>
<p>我只想强调一点：只有分配内存时，才有可能导致抛出CMemoryException.</p>
<p>同样，在msdn中的函数声明中，注有throw( CMemoryException)的函数都有重新分配或调整内存的可能。</p>
<p><br>11 跨模块时的Cstring。即一个DLL的接口函数中的参数为CString&amp;时，它会发生怎样的现象。解答我遇到的问题。我的问题原来已经发贴，地址为：</p>
<p><a href="http://www.csdn.net/expert/topic/741/741921.xml?temp=.2283136"><u><font color=#0000ff>http://www.csdn.net/expert/topic/741/741921.xml?temp=.2283136</font></u></a></p>
<p><br>构造一个这样CString对象时，如CString str，你可知道此时的str所指向的引用内存块吗？也许你会认为它指向NULL。其实不对，如果这样的话，CString所采用的引用机制管理内存块就会有麻烦了，所以CString在构造一个空串的对象时，它会指向一个固定的初始化地址，这块数据的声明如下：</p>
<p>AFX_STATIC_DATA int _afxInitData[] = {-1,0,0,0};</p>
<p>简要描述概括一下：当某个CString对象串置空的话，如Empty(),CString a等，它的成员变量m_pchData就会指向_afxInitData这个变量的地址。当这个CString对象生命周期结束时，正常情况下它会去对所指向的引用内存块计数减1，如果引用计数为0(即没有任何CString引用它时)，则释放这块引用内存。而现在的情况是如果CString所指向的引用内存块是初始化内存块时，则不会释放任何内存。</p>
<p><br>说了这么多，这与我遇到的问题有什么关系呢？其实关系大着呢？其真正原因就是如果exe模块与dll模块有一个是static编译连接的话。那么这个CString初始化数据在exe模块与dll模块中有不同的地址，因为static连接则会在本模块中有一份源代码的拷贝。另外一种情况，如果两个模块都是share连接的，CString的实现代码则在另一个单独的dll中实现，而AFX_STATIC_DATA指定变量只装一次，所以两个模块中_afxInitData有相同的地址。</p>
<p>现在问题完全明白了吧！你可以自己去演示一下。</p>
<p>__declspec (dllexport) void test(CString&amp; str)</p>
<p>{</p>
<p>str = "abdefakdfj";//如果是static连接，并且传入的str为空串的话，这里出错。</p>
<p>}</p>
<p><br>最后一点想法：写得这里，其实CString中还有许多技巧性的好东东，我并没去解释。如很多重载的操作符、查找等。我认为还是详细看看msdn，这样也许会比我讲的好多了。我只侧重那些可能会出错的情况。当然，如我上面叙述中有错误，敬请高手指点，不胜感谢！</p>
<p><br>msdn：<a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vcmfc98/html/_mfc_cstring_class_members.asp"><u><font color=#0000ff>http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vcmfc98/html/_mfc_cstring_class_members.asp</font></u></a><br></p>
<div id=div_digg></div>
<img src ="http://www.cppblog.com/yunboy4/aggbug/91800.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yunboy4/" target="_blank">yunboy</a> 2009-07-31 13:46 <a href="http://www.cppblog.com/yunboy4/archive/2009/07/31/91800.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>setsockopt参数详细说明(转载)</title><link>http://www.cppblog.com/yunboy4/archive/2009/07/29/91551.html</link><dc:creator>yunboy</dc:creator><author>yunboy</author><pubDate>Wed, 29 Jul 2009 00:33:00 GMT</pubDate><guid>http://www.cppblog.com/yunboy4/archive/2009/07/29/91551.html</guid><wfw:comment>http://www.cppblog.com/yunboy4/comments/91551.html</wfw:comment><comments>http://www.cppblog.com/yunboy4/archive/2009/07/29/91551.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yunboy4/comments/commentRss/91551.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yunboy4/services/trackbacks/91551.html</trackback:ping><description><![CDATA[
<p><span  style="font-weight: bold;"><p><strong>int</strong> <strong><font style="BACKGROUND-COLOR: #316ac5" color="#ffffff">setsockopt</font>(</strong><br>&#160; <strong>SOCKET</strong> <em><a class="synParam" onclick="showTip(this)" href="http://writeblog.csdn.net/fckeditor/editor/">s</a></em><strong>,<br></strong>&#160; 
<strong>int</strong> <em><a class="synParam" onclick="showTip(this)" href="http://writeblog.csdn.net/fckeditor/editor/">level</a></em><strong></strong><strong>,<br></strong>&#160; 
<strong>int</strong> <em><a class="synParam" onclick="showTip(this)" href="http://writeblog.csdn.net/fckeditor/editor/">optname</a></em><strong></strong><strong>,<br></strong>&#160; 
<strong>const char*</strong> <em><a class="synParam" onclick="showTip(this)" href="http://writeblog.csdn.net/fckeditor/editor/">optval</a></em><strong></strong><strong>,<br></strong>&#160; 
<strong>int</strong> <em><a class="synParam" onclick="showTip(this)" href="http://writeblog.csdn.net/fckeditor/editor/">optlen</a></em><strong></strong><strong><br></strong><strong>);</strong><br></p>
<p>s(套接字):&#160;指向一个打开的套接口描述字 <br>&#160;level:(级别)：&#160;指定选项代码的类型。 <br>SOL_SOCKET:&#160;基本套接口&#160; 
<br>IPPROTO_IP:&#160;IPv4套接口&#160; <br>IPPROTO_IPV6:&#160;IPv6套接口&#160; <br>IPPROTO_TCP:&#160;TCP套接口&#160; 
<br>optname(选项名)：&#160;选项名称&#160; 
<br>optval(选项值):&#160;是一个指向变量的指针&#160;类型：整形，套接口结构，&#160;其他结构类型:linger{},&#160;timeval{&#160;}&#160; 
<br>optlen(选项长度)&#160;：optval&#160;的大小&#160; <br><br>返回值：标志打开或关闭某个特征的二进制选项 
<br>[/code:1:59df4ce128] </p>
<p>
</p><p>&#160;</p><table style="BORDER-COLLAPSE: collapse; WORD-BREAK: break-all" border="0" cellspacing="0" cellpadding="0" width="90%" align="center">
<tbody>
<tr>
<td>========================================================================&#160; 
<br>SOL_SOCKET&#160; 
<br>------------------------------------------------------------------------&#160; 
<br>SO_BROADCAST&#160;允许发送广播数据&#160;int&#160; 
<br>适用於&#160;UDP&#160;socket。其意义是允许&#160;UDP&#160;socket&#160;「广播」（broadcast）讯息到网路上。 
<br><br>SO_DEBUG&#160;允许调试&#160;int&#160; <br><br>SO_DONTROUTE&#160;不查找路由&#160;int&#160; 
<br><br>SO_ERROR&#160;获得套接字错误&#160;int&#160; <br><br>SO_KEEPALIVE&#160;保持连接&#160;int&#160; 
<br>检测对方主机是否崩溃，避免（服务器）永远阻塞于TCP连接的输入。&#160;设置该选项后，如果2小时内在此套接口的任一方向都没有数据交换，TCP就自动给对方&#160;发一个保持存活探测分节(keepalive&#160;probe)。这是一个对方必须响应的TCP分节.它会导致以下三种情况：&#160;对方接收一切正常：以期望的ACK响应。2小时后，TCP将发出另一个探测分节。&#160;对方已崩溃且已重新启动：以RST响应。套接口的待处理错误被置为ECONNRESET，套接&#160;口本身则被关闭。&#160;对方无任何响应：源自berkeley的TCP发送另外8个探测分节，相隔75秒一个，试图得到&#160;一个响应。在发出第一个探测分节11分钟15秒后若仍无响应就放弃。套接口的待处理错&#160;误被置为ETIMEOUT，套接口本身则被关闭。如ICMP错误是&#8220;host&#160;unreachable(主机不&#160;可达)&#8221;，说明对方主机并没有崩溃，但是不可达，这种情况下待处理错误被置为&#160;EHOSTUNREACH。&#160; 
<br><br><br><br>SO_DONTLINGER&#160;若为真，则SO_LINGER选项被禁止。 
<br>SO_LINGER&#160;延迟关闭连接&#160;struct&#160;linger&#160; <br>上面这两个选项影响close行为 <br>选项&#160;间隔&#160;关闭方式&#160;等待关闭与否 
<br>SO_DONTLINGER&#160;不关心&#160;优雅&#160;否 <br>SO_LINGER&#160;零&#160;强制&#160;否 <br>SO_LINGER&#160;非零&#160;优雅&#160;是 
<br>若设置了SO_LINGER（亦即linger结构中的l_onoff域设为非零，参见2.4，4.1.7和4.1.21各节），并设置了零超时间隔，则closesocket()不被阻塞立即执行，不论是否有排队数据未发送或未被确认。这种关闭方式称为&#8220;强制&#8221;或&#8220;失效&#8221;关闭，因为套接口的虚电路立即被复位，且丢失了未发送的数据。在远端的recv()调用将以WSAECONNRESET出错。 
<br>若设置了SO_LINGER并确定了非零的超时间隔，则closesocket()调用阻塞进程，直到所剩数据发送完毕或超时。这种关闭称为&#8220;优雅的&#8221;关闭。请注意如果套接口置为非阻塞且SO_LINGER设为非零超时，则closesocket()调用将以WSAEWOULDBLOCK错误返回。 
<br>若在一个流类套接口上设置了SO_DONTLINGER（也就是说将linger结构的l_onoff域设为零；参见2.4，4.1.7，4.1.21节），则closesocket()调用立即返回。但是，如果可能，排队的数据将在套接口关闭前发送。请注意，在这种情况下WINDOWS套接口实现将在一段不确定的时间内保留套接口以及其他资源，这对于想用所以套接口的应用程序来说有一定影响。 
<br><br><br><br>SO_OOBINLINE&#160;带外数据放入正常数据流,在普通数据流中接收带外数据&#160;int&#160; 
<br><br>SO_RCVBUF&#160;接收缓冲区大小&#160;int&#160; <br>设置接收缓冲区的保留大小 
<br>与&#160;SO_MAX_MSG_SIZE&#160;或TCP滑动窗口无关，如果一般发送的包很大很频繁，那么使用这个选项 
<br><br>SO_SNDBUF&#160;发送缓冲区大小&#160;int&#160; <br>设置发送缓冲区的保留大小 
<br>与&#160;SO_MAX_MSG_SIZE&#160;或TCP滑动窗口无关，如果一般发送的包很大很频繁，那么使用这个选项 
<br>每个套接口都有一个发送缓冲区和一个接收缓冲区。&#160;接收缓冲区被TCP和UDP用来将接收到的数据一直保存到由应用进程来读。&#160;TCP：TCP通告另一端的窗口大小。&#160;TCP套接口接收缓冲区不可能溢出，因为对方不允许发出超过所通告窗口大小的数据。&#160;这就是TCP的流量控制，如果对方无视窗口大小而发出了超过宙口大小的数据，则接&#160;收方TCP将丢弃它。&#160;UDP：当接收到的数据报装不进套接口接收缓冲区时，此数据报就被丢弃。UDP是没有&#160;流量控制的；快的发送者可以很容易地就淹没慢的接收者，导致接收方的UDP丢弃数据报。 
<br><br><br><br>SO_RCVLOWAT&#160;接收缓冲区下限&#160;int&#160; <br>SO_SNDLOWAT&#160;发送缓冲区下限&#160;int&#160; 
<br>每个套接口都有一个接收低潮限度和一个发送低潮限度。它们是函数selectt使用的，&#160;接收低潮限度是让select返回&#8220;可读&#8221;而在套接口接收缓冲区中必须有的数据总量。&#160;——对于一个TCP或UDP套接口，此值缺省为1。发送低潮限度是让select返回&#8220;可写&#8221;&#160;而在套接口发送缓冲区中必须有的可用空间。对于TCP套接口，此值常缺省为2048。&#160;对于UDP使用低潮限度，&#160;由于其发送缓冲区中可用空间的字节数是从不变化的，只要&#160;UDP套接口发送缓冲区大小大于套接口的低潮限度，这样的UDP套接口就总是可写的。&#160;UDP没有发送缓冲区，只有发送缓冲区的大小。 
<br><br>SO_RCVTIMEO&#160;接收超时&#160;struct&#160;timeval&#160; <br>SO_SNDTIMEO&#160;发送超时&#160;struct&#160;timeval&#160; 
<br>SO_REUSERADDR&#160;允许重用本地地址和端口&#160;int&#160; <br>充许绑定已被使用的地址（或端口号），可以参考bind的man 
<br><br>SO_EXCLUSIVEADDRUSE <br>独占模式使用端口,就是不充许和其它程序使用SO_REUSEADDR共享的使用某一端口。 
<br>在确定多重绑定使用谁的时候，根据一条原则是谁的指定最明确则将包递交给谁，而且没有权限之分，也就是说低级权限的用户是可以重绑定在高级权限如服务启动的端口上的,这是非常重大的一个安全隐患, 
<br>如果不想让自己程序被监听，那么使用这个选项 <br><br>SO_TYPE&#160;获得套接字类型&#160;int&#160; 
<br>SO_BSDCOMPAT&#160;与BSD系统兼容&#160;int&#160; 
<br><br><br><br><br><br><br><br><br><br><br><br>==========================================================================&#160; 
<br>IPPROTO_IP&#160; 
<br>--------------------------------------------------------------------------&#160; 
<br>IP_HDRINCL&#160;在数据包中包含IP首部&#160;int&#160; <br>&#160;&#160;&#160;这个选项常用于黑客技术中，隐藏自己的IP地址 
<br><br>IP_OPTINOS&#160;IP首部选项&#160;int&#160; <br>IP_TOS&#160;服务类型&#160; <br>IP_TTL&#160;生存时间&#160;int&#160; 
<br><br>以下IPV4选项用于组播 <br>IPv4&#160;选项&#160;数据类型&#160;描&#160;述 
<br>　　IP_ADD_MEMBERSHIP&#160;struct&#160;ip_mreq&#160;加入到组播组中 
<br>　　IP_ROP_MEMBERSHIP&#160;struct&#160;ip_mreq&#160;从组播组中退出 
<br>　　IP_MULTICAST_IF&#160;struct&#160;ip_mreq&#160;指定提交组播报文的接口 
<br>　　IP_MULTICAST_TTL&#160;u_char&#160;指定提交组播报文的TTL 
<br>　　IP_MULTICAST_LOOP&#160;u_char&#160;使组播报文环路有效或无效 <br>在头文件中定义了ip_mreq结构： 
<br>[code:1:63724de67f] <br>struct&#160;ip_mreq&#160;{ 
<br>struct&#160;in_addr&#160;imr_multiaddr;&#160;/*&#160;IP&#160;multicast&#160;address&#160;of&#160;group&#160;*/ 
<br>struct&#160;in_addr&#160;imr_interface;&#160;/*&#160;local&#160;IP&#160;address&#160;of&#160;interface&#160;*/ <br>}; 
<br>[/code:1:63724de67f] 
<br>若进程要加入到一个组播组中，用soket的setsockopt()函数发送该选项。该选项类型是ip_mreq结构，它的第一个字段imr_multiaddr指定了组播组的地址，第二个字段imr_interface指定了接口的IPv4地址。 
<br>　　IP_DROP_MEMBERSHIP <br>　　该选项用来从某个组播组中退出。数据结构ip_mreq的使用方法与上面相同。 
<br>　　IP_MULTICAST_IF <br>　　该选项可以修改网络接口，在结构ip_mreq中定义新的接口。 
<br>　　IP_MULTICAST_TTL <br>　　设置组播报文的数据包的TTL（生存时间）。默认值是1，表示数据包只能在本地的子网中传送。 
<br>　　IP_MULTICAST_LOOP 
<br>　　组播组中的成员自己也会收到它向本组发送的报文。这个选项用于选择是否激活这种状态。<br><br></td></tr>
<tr>
<td>
<hr>
<small><font size="2">&#160;</font><a href="http://www.chinaunix.net/forum/profile.php?mode=viewprofile&amp;u=29829" target="_blank"><font size="2">无双</font></a><font size="2"> 回复于：2003-05-08 
21:21:52</font></small></td></tr>
<tr>
<td><br>IPPRO_TCP&#160; 
<br>--------------------------------------------------------------------------&#160; 
<br>TCP_MAXSEG&#160;TCP最大数据段的大小&#160;int&#160; 
<br>获取或设置TCP连接的最大分节大小(MSS)。返回值是我们的TCP发送给另一端的最大&#160;数据量，它常常就是由另一端用SYN分节通告的MSS，除非我们的TCP选择使用一个比&#160;对方通告的MSS小些的值。如果此值在套接口连接之前取得，则返回值为未从另&#183;—端&#160;收到Mss选项的情况下所用的缺省值。小于此返回值的信可能真正用在连接上，因为譬&#160;如说使用时间戳选项的话，它在每个分节上占用12字节的TCP选项容量。我们的TcP将&#160;发送的每个分节的最大数据量也可在连接存活期内改变，但前提是TCP要支持路径MTU&#160;发现功能。如果到对方的路径改变了，此值可上下调整。 
<br>TCP_NODELAY&#160;不使用Nagle算法&#160;int&#160; 
<br><br>指定TCP开始发送保持存活探测分节前以秒为单位的连接空闲时间。缺省值至少必须为7200秒，即2小时。此选项仅在SO_KEPALIVEE套接口选项打开时才有效。 
<br><br>TCP_NODELAY&#160;和&#160;TCP_CORK， 
<br>这两个选项都对网络连接的行为具有重要的作用。许多UNIX系统都实现了TCP_NODELAY选项，但是，TCP_CORK则是Linux系统所独有的而且相对较新；它首先在内核版本2.4上得以实现。此外，其他UNIX系统版本也有功能类似的选项，值得注意的是，在某种由BSD派生的系统上的TCP_NOPUSH选项其实就是TCP_CORK的一部分具体实现。 
<br>TCP_NODELAY和TCP_CORK基本上控制了包的&#8220;Nagle化&#8221;，Nagle化在这里的含义是采用Nagle算法把较小的包组装为更大的帧。John&#160;Nagle是Nagle算法的发明人，后者就是用他的名字来命名的，他在1984年首次用这种方法来尝试解决福特汽车公司的网络拥塞问题（欲了解详情请参看IETF&#160;RFC&#160;896）。他解决的问题就是所谓的silly&#160;window&#160;syndrome&#160;，中文称&#8220;愚蠢窗口症候群&#8221;，具体含义是，因为普遍终端应用程序每产生一次击键操作就会发送一个包，而典型情况下一个包会拥有一个字节的数据载荷以及40个字节长的包头，于是产生4000%的过载，很轻易地就能令网络发生拥塞,。&#160;Nagle化后来成了一种标准并且立即在因特网上得以实现。它现在已经成为缺省配置了，但在我们看来，有些场合下把这一选项关掉也是合乎需要的。 
<br>现在让我们假设某个应用程序发出了一个请求，希望发送小块数据。我们可以选择立即发送数据或者等待产生更多的数据然后再一次发送两种策略。如果我们马上发送数据，那么交互性的以及客户/服务器型的应用程序将极大地受益。例如，当我们正在发送一个较短的请求并且等候较大的响应时，相关过载与传输的数据总量相比就会比较低，而且，如果请求立即发出那么响应时间也会快一些。以上操作可以通过设置套接字的TCP_NODELAY选项来完成，这样就禁用了Nagle算法。 
<br>另外一种情况则需要我们等到数据量达到最大时才通过网络一次发送全部数据，这种数据传输方式有益于大量数据的通信性能，典型的应用就是文件服务器。应用Nagle算法在这种情况下就会产生问题。但是，如果你正在发送大量数据，你可以设置TCP_CORK选项禁用Nagle化，其方式正好同TCP_NODELAY相反（TCP_CORK&#160;和&#160;TCP_NODELAY&#160;是互相排斥的）。下面就让我们仔细分析下其工作原理。 
<br>假设应用程序使用sendfile()函数来转移大量数据。应用协议通常要求发送某些信息来预先解释数据，这些信息其实就是报头内容。典型情况下报头很小，而且套接字上设置了TCP_NODELAY。有报头的包将被立即传输，在某些情况下（取决于内部的包计数器），因为这个包成功地被对方收到后需要请求对方确认。这样，大量数据的传输就会被推迟而且产生了不必要的网络流量交换。 
<br>但是，如果我们在套接字上设置了TCP_CORK（可以比喻为在管道上插入&#8220;塞子&#8221;）选项，具有报头的包就会填补大量的数据，所有的数据都根据大小自动地通过包传输出去。当数据传输完成时，最好取消TCP_CORK&#160;选项设置给连接&#8220;拔去塞子&#8221;以便任一部分的帧都能发送出去。这同&#8220;塞住&#8221;网络连接同等重要。 
<br>总而言之，如果你肯定能一起发送多个数据集合（例如HTTP响应的头和正文），那么我们建议你设置TCP_CORK选项，这样在这些数据之间不存在延迟。能极大地有益于WWW、FTP以及文件服务器的性能，同时也简化了你的工作。示例代码如下： 
<br><br>intfd,&#160;on&#160;=&#160;1; <br>&#8230; <br>/*&#160;此处是创建套接字等操作，出于篇幅的考虑省略*/ <br>&#8230; 
<br>setsockopt&#160;(fd,&#160;SOL_TCP,&#160;TCP_CORK,&#160;&amp;on,&#160;sizeof&#160;(on));&#160;/*&#160;cork&#160;*/ 
<br>write&#160;(fd,&#160;&#8230;); <br>fprintf&#160;(fd,&#160;&#8230;); <br>sendfile&#160;(fd,&#160;&#8230;); <br>write&#160;(fd,&#160;&#8230;); 
<br>sendfile&#160;(fd,&#160;&#8230;); <br>&#8230; <br>on&#160;=&#160;0; 
<br>setsockopt&#160;(fd,&#160;SOL_TCP,&#160;TCP_CORK,&#160;&amp;on,&#160;sizeof&#160;(on));&#160;/*&#160;拔去塞子&#160;*/ 
<br><br><br>不幸的是，许多常用的程序并没有考虑到以上问题。例如，Eric&#160;Allman编写的sendmail就没有对其套接字设置任何选项。 
<br><br>Apache&#160;HTTPD是因特网上最流行的Web服务器，它的所有套接字就都设置了TCP_NODELAY选项，而且其性能也深受大多数用户的满意。这是为什么呢？答案就在于实现的差别之上。由BSD衍生的TCP/IP协议栈（值得注意的是FreeBSD）在这种状况下的操作就不同。当在TCP_NODELAY&#160;模式下提交大量小数据块传输时，大量信息将按照一次write()函数调用发送一块数据的方式发送出去。然而，因为负责请求交付确认的记数器是面向字节而非面向包（在Linux上）的，所以引入延迟的概率就降低了很多。结果仅仅和全部数据的大小有关系。而&#160;Linux&#160;在第一包到达之后就要求确认，FreeBSD则在进行如此操作之前会等待好几百个包。 
<br><br>在Linux系统上，TCP_NODELAY的效果同习惯于BSD&#160;TCP/IP协议栈的开发者所期望的效果有很大不同，而且在Linux上的Apache性能表现也会更差些。其他在Linux上频繁采用TCP_NODELAY的应用程序也有同样的问题。 
<br><br><br>TCP_DEFER_ACCEPT 
<br><br>我们首先考虑的第1个选项是TCP_DEFER_ACCEPT（这是Linux系统上的叫法，其他一些操作系统上也有同样的选项但使用不同的名字）。为了理解TCP_DEFER_ACCEPT选项的具体思想，我们有必要大致阐述一下典型的HTTP客户/服务器交互过程。请回想下TCP是如何与传输数据的目标建立连接的。在网络上，在分离的单元之间传输的信息称为IP包（或IP&#160;数据报）。一个包总有一个携带服务信息的包头，包头用于内部协议的处理，并且它也可以携带数据负载。服务信息的典型例子就是一套所谓的标志，它把包标记代表TCP/IP协议栈内的特殊含义，例如收到包的成功确认等等。通常，在经过&#8220;标记&#8221;的包里携带负载是完全可能的，但有时，内部逻辑迫使TCP/IP协议栈发出只有包头的IP包。这些包经常会引发讨厌的网络延迟而且还增加了系统的负载，结果导致网络性能在整体上降低。 
<br>现在服务器创建了一个套接字同时等待连接。TCP/IP式的连接过程就是所谓&#8220;3次握手&#8221;。首先，客户程序发送一个设置SYN标志而且不带数据负载的TCP包（一个SYN包）。服务器则以发出带SYN/ACK标志的数据包（一个SYN/ACK包）作为刚才收到包的确认响应。客户随后发送一个ACK包确认收到了第2个包从而结束连接过程。在收到客户发来的这个SYN/ACK包之后，服务器会唤醒一个接收进程等待数据到达。当3次握手完成后，客户程序即开始把&#8220;有用的&#8221;的数据发送给服务器。通常，一个HTTP请求的量是很小的而且完全可以装到一个包里。但是，在以上的情况下，至少有4个包将用来进行双向传输，这样就增加了可观的延迟时间。此外，你还得注意到，在&#8220;有用的&#8221;数据被发送之前，接收方已经开始在等待信息了。 
<br>为了减轻这些问题所带来的影响，Linux（以及其他的一些操作系统）在其TCP实现中包括了TCP_DEFER_ACCEPT选项。它们设置在侦听套接字的服务器方，该选项命令内核不等待最后的ACK包而且在第1个真正有数据的包到达才初始化侦听进程。在发送SYN/ACK包之后，服务器就会等待客户程序发送含数据的IP包。现在，只需要在网络上传送3个包了，而且还显著降低了连接建立的延迟，对HTTP通信而言尤其如此。 
<br>这一选项在好些操作系统上都有相应的对等物。例如，在FreeBSD上，同样的行为可以用以下代码实现： 
<br><br>/*&#160;为明晰起见，此处略去无关代码&#160;*/ 
<br>struct&#160;accept_filter_arg&#160;af&#160;=&#160;{&#160;"dataready",&#160;""&#160;}; 
<br>setsockopt(s,&#160;SOL_SOCKET,&#160;SO_ACCEPTFILTER,&#160;&amp;af,&#160;sizeof(af)); 
<br>这个特征在FreeBSD上叫做&#8220;接受过滤器&#8221;，而且具有多种用法。不过，在几乎所有的情况下其效果与TCP_DEFER_ACCEPT是一样的：服务器不等待最后的ACK包而仅仅等待携带数据负载的包。要了解该选项及其对高性能Web服务器的重要意义的更多信息请参考Apache文档上的有关内容。 
<br>就HTTP客户/服务器交互而言，有可能需要改变客户程序的行为。客户程序为什么要发送这种&#8220;无用的&#8221;ACK包呢？这是因为，TCP协议栈无法知道ACK包的状态。如果采用FTP而非HTTP，那么客户程序直到接收了FTP服务器提示的数据包之后才发送数据。在这种情况下，延迟的ACK将导致客户/服务器交互出现延迟。为了确定ACK是否必要，客户程序必须知道应用程序协议及其当前状态。这样，修改客户行为就成为必要了。 
<br>对Linux客户程序来说，我们还可以采用另一个选项，它也被叫做TCP_DEFER_ACCEPT。我们知道，套接字分成两种类型，侦听套接字和连接套接字，所以它们也各自具有相应的TCP选项集合。因此，经常同时采用的这两类选项却具有同样的名字也是完全可能的。在连接套接字上设置该选项以后，客户在收到一个SYN/ACK包之后就不再发送ACK包，而是等待用户程序的下一个发送数据请求；因此，服务器发送的包也就相应减少了。 
<br><br>TCP_QUICKACK 
<br><br>阻止因发送无用包而引发延迟的另一个方法是使用TCP_QUICKACK选项。这一选项与&#160;TCP_DEFER_ACCEPT不同，它不但能用作管理连接建立过程而且在正常数据传输过程期间也可以使用。另外，它能在客户/服务器连接的任何一方设置。如果知道数据不久即将发送，那么推迟ACK包的发送就会派上用场，而且最好在那个携带数据的数据包上设置ACK&#160;标志以便把网络负载减到最小。当发送方肯定数据将被立即发送（多个包）时，TCP_QUICKACK选项可以设置为0。对处于&#8220;连接&#8221;状态下的套接字该选项的缺省值是1，首次使用以后内核将把该选项立即复位为1（这是个一次性的选项）。 
<br>在某些情形下，发出ACK包则非常有用。ACK包将确认数据块的接收，而且，当下一块被处理时不至于引入延迟。这种数据传输模式对交互过程是相当典型的，因为此类情况下用户的输入时刻无法预测。在Linux系统上这就是缺省的套接字行为。 
<br>在上述情况下，客户程序在向服务器发送HTTP请求，而预先就知道请求包很短所以在连接建立之后就应该立即发送，这可谓HTTP的典型工作方式。既然没有必要发送一个纯粹的ACK包，所以设置TCP_QUICKACK为0以提高性能是完全可能的。在服务器方，这两种选项都只能在侦听套接字上设置一次。所有的套接字，也就是被接受呼叫间接创建的套接字则会继承原有套接字的所有选项。 
<br>通过TCP_CORK、TCP_DEFER_ACCEPT和TCP_QUICKACK选项的组合，参与每一HTTP交互的数据包数量将被降低到最小的可接受水平（根据TCP协议的要求和安全方面的考虑）。结果不仅是获得更快的数据传输和请求处理速度而且还使客户/服务器双向延迟实现了最小化。 
<br></td></tr></tbody><tbody></tbody></table></span><br></p><img src ="http://www.cppblog.com/yunboy4/aggbug/91551.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yunboy4/" target="_blank">yunboy</a> 2009-07-29 08:33 <a href="http://www.cppblog.com/yunboy4/archive/2009/07/29/91551.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>非阻塞套接字的模式</title><link>http://www.cppblog.com/yunboy4/archive/2009/07/26/91231.html</link><dc:creator>yunboy</dc:creator><author>yunboy</author><pubDate>Sun, 26 Jul 2009 03:13:00 GMT</pubDate><guid>http://www.cppblog.com/yunboy4/archive/2009/07/26/91231.html</guid><wfw:comment>http://www.cppblog.com/yunboy4/comments/91231.html</wfw:comment><comments>http://www.cppblog.com/yunboy4/archive/2009/07/26/91231.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/yunboy4/comments/commentRss/91231.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yunboy4/services/trackbacks/91231.html</trackback:ping><description><![CDATA[<p>&nbsp;</p>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #000000">1</span><span style="COLOR: #000000">.非阻塞套接字的模式<br>(</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">)服务器端<br>&nbsp;&nbsp;&nbsp;&nbsp;通常socket运行后默认为阻塞模式。要调用ioctlsocket函数设置非阻塞模式。<br>如：<br><br>&nbsp;&nbsp;&nbsp;&nbsp;WSAData&nbsp;Data;<br>&nbsp;&nbsp;&nbsp;&nbsp;WSAStartup(MAKEWORD(</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">),&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">Data);<br>&nbsp;&nbsp;&nbsp;&nbsp;SerSocket&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;socket(AF_INET,&nbsp;SOCK_STREAM,&nbsp;IPPROTO_TCP);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(INVALID_SOCKET&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;SerSocket)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Invalid&nbsp;Socket!\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;u_long&nbsp;iMode&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;ioctlsocket(SerSocket,&nbsp;FIONBIO,&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">iMode);<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;在接受客户端请求的线程中，若接受成功就返回客户端的套接字，否则返回INVALID_SOCKET错误，<br>若错误代码为WSAEWOULDBLOCK，说明当前没有客户端请求。<br>如：<br></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">接受客户端请求线程</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">DWORD&nbsp;WINAPI&nbsp;AcceptClientPro(LPVOID&nbsp;LpP)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;SOCKADDR_IN&nbsp;ClientAdrr;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;AddrLen&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(SOCKADDR);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">非阻塞模式</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">IsConnet)<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ClientSock&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;accept(SerSocket,&nbsp;(SOCKADDR&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">ClientAdrr,&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">AddrLen&nbsp;);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(INVALID_SOCKET&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;ClientSock)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;n&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;WSAGetLastError();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">没有客户端请求</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(WSAEWOULDBLOCK&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;n)&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">没有客户端发出请求!</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">endl;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sleep(</span><span style="COLOR: #000000">1000</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">continue</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">出现错误!</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">endl;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sleep(</span><span style="COLOR: #000000">1000</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">已连接客户端!</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">endl;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IsConnet&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">break</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>}<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;就recv函数来说，在阻塞模式中，如果没有客户端发送数据过来，线程到这里会阻塞，直到有数<br>据发送过来为止。在非阻塞模式中，没有客户端发送数据过来，返回SOCKER_ERROR，错误代码为WSAEWOULDBLOCK。<br>如：<br></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">接收数据线程</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">DWORD&nbsp;WINAPI&nbsp;ReceiveDataPro(LPVOID&nbsp;LpP)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">IsConnet);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">保证连接后再接受数据</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">)<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(IsReadyRecei)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">保证缓冲区在未处理时不受新来的数据的影响</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;ReceiLen&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;recv(ClientSock,&nbsp;(</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">DataPack,&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(DataPack),&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(SOCKET_ERROR&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;ReceiLen)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;Err&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;WSAGetLastError();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(WSAEWOULDBLOCK&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;Err)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">没有收到数据</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">endl;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">continue</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(WSAENETDOWN&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;Err&nbsp;</span><span style="COLOR: #000000">||</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">客户端关闭了连接</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WSAETIMEDOUT&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;Err&nbsp;</span><span style="COLOR: #000000">||</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WSAECONNRESET&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;Err&nbsp;)&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">服务器关闭了连接</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">endl;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">break</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;ReceiLen)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">客户端关闭了连接</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">ReceiLen&nbsp;=&nbsp;0</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">endl;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">break</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(ReceiLen&nbsp;</span><span style="COLOR: #000000">&gt;=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(DataPack))&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">成功接收</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">已收到数据：</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">DataPack.buf</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">endl;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IsReadyRecei&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">false</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">break</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>}&nbsp;&nbsp;&nbsp;&nbsp;<br><br>(</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">)客户端<br>&nbsp;&nbsp;&nbsp;&nbsp;在客户端的连接请求线程中，connect函数会返回SOCKET_ERROR，这并不是说明连接失败，具体情况<br>要看它的WSAGetLastError()返回值，若它三次返回SOCKET_ERROR的Error代码依次为WSAEWOULDBLOCK，<br>WSAEINVAL，WSAEISCONN，就说明连接服务器成功，否则失败。但有的时候WSAEINVAL没有出现就有WSAEISCONN<br>了，所以我还是以WSAEISCONN为连接完成的标志，但要注意其实在三次返回代码中，第一次的WSAEWOULDBLOCK<br>之前的connect操作就成功了，如果没出意外服务器就要响应了。<br>如：<br></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">连接服务器线程</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">DWORD&nbsp;WINAPI&nbsp;ConnetServerPro(LPVOID&nbsp;LpP)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;SOCKADDR_IN&nbsp;ServerAddr;<br>&nbsp;&nbsp;&nbsp;&nbsp;ServerAddr.sin_family&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;AF_INET;<br>&nbsp;&nbsp;&nbsp;&nbsp;ServerAddr.sin_port&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;htons(</span><span style="COLOR: #000000">1200</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;ServerAddr.sin_addr.s_addr&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;inet_addr(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">192.168.1.100</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;BlockFlag&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;InvalFlag&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">IsConnet)<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;nResu&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;connect(ClientSock,&nbsp;(SOCKADDR&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">ServerAddr,&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(SOCKADDR));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(SOCKET_ERROR&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;nResu)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;n&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;WSAGetLastError();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(WSAEWOULDBLOCK&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;n&nbsp;)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">不能立即完成</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">过程1!</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">endl;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BlockFlag</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">continue</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(WSAEINVAL&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;n)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">监听状态</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">过程2!</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">endl;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;InvalFlag</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">continue</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(WSAEISCONN&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;n)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">连接完成</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">已连接服务器!</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">endl;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IsConnet&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">break</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000">&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">出现其他错误!\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">endl;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sleep(</span><span style="COLOR: #000000">1000</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;在发送数据线程中，send()返回的是发送数据的长度说明发送成功；返回SOCKET_ERROR时，若<br>错误代码为WSAEWOULDBLOCK就再重试，不是WSAEWOULDBLOCK就说明有错误。】<br>如：<br></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">发送数据线程</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">DWORD&nbsp;WINAPI&nbsp;SendDataPro(LPVOID&nbsp;LpP)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">IsConnet);&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">保证已连接服务器</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">)<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;len&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;send(ClientSock,&nbsp;(</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">DataPack,&nbsp;DataPack.Head.len,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(SOCKET_ERROR&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;len)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;Error&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;WSAGetLastError();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(WSAEWOULDBLOCK&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;Error)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">continue</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">发送成功</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">发送成功!</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">endl;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">break</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>}</span></div>
<img src ="http://www.cppblog.com/yunboy4/aggbug/91231.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yunboy4/" target="_blank">yunboy</a> 2009-07-26 11:13 <a href="http://www.cppblog.com/yunboy4/archive/2009/07/26/91231.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>阻塞模式</title><link>http://www.cppblog.com/yunboy4/archive/2009/07/26/91230.html</link><dc:creator>yunboy</dc:creator><author>yunboy</author><pubDate>Sun, 26 Jul 2009 03:09:00 GMT</pubDate><guid>http://www.cppblog.com/yunboy4/archive/2009/07/26/91230.html</guid><wfw:comment>http://www.cppblog.com/yunboy4/comments/91230.html</wfw:comment><comments>http://www.cppblog.com/yunboy4/archive/2009/07/26/91230.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yunboy4/comments/commentRss/91230.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yunboy4/services/trackbacks/91230.html</trackback:ping><description><![CDATA[<p>&nbsp;</p>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #000000">1</span><span style="COLOR: #000000">.阻塞模式<br>&nbsp;&nbsp;&nbsp;&nbsp;会造成线程阻塞的有下列四种操作：<br>(</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">)&nbsp;接受连接请求：accept()<br>(</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">)&nbsp;接受数据：recv()，recvfrom()<br>(</span><span style="COLOR: #000000">3</span><span style="COLOR: #000000">)&nbsp;请求连接：connect()<br>(</span><span style="COLOR: #000000">4</span><span style="COLOR: #000000">)&nbsp;发送数据：send()，sendto()<br>&nbsp;&nbsp;&nbsp;&nbsp;其中1、2最容易发生阻塞。<br>&nbsp;&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">、多线程的阻塞模式<br></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;CServerDlg&nbsp;:&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;CDialog<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;SOCKET&nbsp;m_ClientSock;<br>&nbsp;&nbsp;&nbsp;&nbsp;SOCKET&nbsp;m_ServerSock;<br>&nbsp;&nbsp;&nbsp;&nbsp;HANDLE&nbsp;m_RecvThread;<br>&nbsp;&nbsp;&nbsp;&nbsp;HANDLE&nbsp;m_AcceptThread;<br>&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.cppblog.com/Images/dot.gif"><img src="http://www.cppblog.com/Images/dot.gif">.<br>&nbsp;&nbsp;&nbsp;&nbsp;friend&nbsp;&nbsp;DWORD&nbsp;WINAPI&nbsp;RecvThreadPro(LPVOID&nbsp;LpP);<br>&nbsp;&nbsp;&nbsp;&nbsp;friend&nbsp;&nbsp;DWORD&nbsp;WINAPI&nbsp;AcceptThreadPro(LPVOID&nbsp;LpP);<br>};<br></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">创建线程</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">BOOL&nbsp;CServerDlg::OnInitDialog()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.cppblog.com/Images/dot.gif"><img src="http://www.cppblog.com/Images/dot.gif"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">创建线程</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;ThreadID;<br>&nbsp;&nbsp;&nbsp;&nbsp;m_RecvThread&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;CreateThread(NULL,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;RecvThreadPro,&nbsp;</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">,&nbsp;CREATE_SUSPENDED,&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">ThreadID);<br>&nbsp;&nbsp;&nbsp;&nbsp;m_AcceptThread&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;CreateThread(NULL,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;AcceptThreadPro,&nbsp;</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">,&nbsp;CREATE_SUSPENDED,&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">ThreadID);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;Count&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;ResumeThread(m_AcceptThread);<br>&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.cppblog.com/Images/dot.gif"><img src="http://www.cppblog.com/Images/dot.gif"><br>}<br></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">接收数据线程</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">DWORD&nbsp;WINAPI&nbsp;RecvThreadPro(LPVOID&nbsp;LpP)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;CServerDlg&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">pServer&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;(CServerDlg&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)LpP;<br>&nbsp;&nbsp;&nbsp;&nbsp;ZeroMemory(buf,&nbsp;</span><span style="COLOR: #000000">20</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;nLen&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;recv(pServer</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">m_ClientSock,&nbsp;buf,&nbsp;</span><span style="COLOR: #000000">20</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(SOCKET_ERROR&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;nLen)&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AfxMessageBox(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Recv&nbsp;Failed!</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AfxMessageBox(buf);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>}<br></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">接受客户端请求线程</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">DWORD&nbsp;WINAPI&nbsp;AcceptThreadPro(LPVOID&nbsp;LpP)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;CServerDlg&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">pServer&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;(CServerDlg&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)LpP;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;sockaddr&nbsp;ClientAddr;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;len&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(SOCKADDR_IN);<br>&nbsp;&nbsp;&nbsp;&nbsp;pServer</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">m_ClientSock&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;accept(pServer</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">m_ServerSock,&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">ClientAddr,&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">len);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(SOCKET_ERROR&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;pServer</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">m_ClientSock)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AfxMessageBox(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Accept&nbsp;Failed!</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>}<br></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">结束线程</span><span style="COLOR: #008000"><br></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;CServerDlg::OnClose()&nbsp;<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;TODO:&nbsp;Add&nbsp;your&nbsp;message&nbsp;handler&nbsp;code&nbsp;here&nbsp;and/or&nbsp;call&nbsp;default<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">结束AcceptThread</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;ThreadState;<br>&nbsp;&nbsp;&nbsp;&nbsp;GetExitCodeThread(m_AcceptThread,&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">ThreadState);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(ThreadState&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;STILL_ACTIVE)<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">TerminateThread(m_hThread,&nbsp;0);</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WaitForSingleObject(m_AcceptThread,</span><span style="COLOR: #000000">0xffffffff</span><span style="COLOR: #000000">);&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CloseHandle(m_AcceptThread);&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">结束RecvThread</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;GetExitCodeThread(m_RecvThread,&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">ThreadState);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(ThreadState&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;STILL_ACTIVE)<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">TerminateThread(m_RecvThread,&nbsp;0);</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WaitForSingleObject(m_RecvThread,</span><span style="COLOR: #000000">0xffffffff</span><span style="COLOR: #000000">);&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CloseHandle(m_RecvThread);&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.cppblog.com/Images/dot.gif"><img src="http://www.cppblog.com/Images/dot.gif"><br>&nbsp;&nbsp;&nbsp;&nbsp;CDialog::OnClose();<br>}</span></div>
<img src ="http://www.cppblog.com/yunboy4/aggbug/91230.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yunboy4/" target="_blank">yunboy</a> 2009-07-26 11:09 <a href="http://www.cppblog.com/yunboy4/archive/2009/07/26/91230.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>线程的同步</title><link>http://www.cppblog.com/yunboy4/archive/2009/07/25/91181.html</link><dc:creator>yunboy</dc:creator><author>yunboy</author><pubDate>Sat, 25 Jul 2009 14:48:00 GMT</pubDate><guid>http://www.cppblog.com/yunboy4/archive/2009/07/25/91181.html</guid><wfw:comment>http://www.cppblog.com/yunboy4/comments/91181.html</wfw:comment><comments>http://www.cppblog.com/yunboy4/archive/2009/07/25/91181.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yunboy4/comments/commentRss/91181.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yunboy4/services/trackbacks/91181.html</trackback:ping><description><![CDATA[<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #000000">1</span><span style="COLOR: #000000">.用事件对象来控制线程<br></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Define&nbsp;thread&nbsp;function</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">DWORD&nbsp;__stdcall&nbsp;ThreadFunOne(LPVOID&nbsp;lParam)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">(;;)<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WaitForSingleObject(hEvent,&nbsp;INFINITE);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">阻塞线程，直到事件对象为通知状态</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(WorkerID</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">MAXWORKERID)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WorkerID&nbsp;</span><span style="COLOR: #000000">+=</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sleep(</span><span style="COLOR: #000000">1000</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">ThreadOne&nbsp;print&nbsp;out:&nbsp;%i&nbsp;\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,WorkerID);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SetEvent(hEvent);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">设置事件为通知状态</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>}<br>DWORD&nbsp;__stdcall&nbsp;ThreadFunTwo(LPVOID&nbsp;lParam)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">(;;)<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WaitForSingleObject(hEvent,&nbsp;INFINITE);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(WorkerID</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">MAXWORKERID)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WorkerID&nbsp;</span><span style="COLOR: #000000">+=</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">ThreadTwo&nbsp;print&nbsp;out:&nbsp;%i&nbsp;\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,WorkerID);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sleep(</span><span style="COLOR: #000000">1000</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SetEvent(hEvent);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>}<br></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;main()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Define&nbsp;thread&nbsp;handle</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;HANDLE&nbsp;hThread1,hThread2;<br>&nbsp;&nbsp;&nbsp;&nbsp;hEvent&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;CreateEvent(NULL,&nbsp;FALSE,&nbsp;TRUE,&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Event</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Create&nbsp;thread</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;hThread1&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;::CreateThread(NULL,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,ThreadFunOne,NULL,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,NULL);<br>&nbsp;&nbsp;&nbsp;&nbsp;hThread2&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;::CreateThread(NULL,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,ThreadFunTwo,NULL,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,NULL);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Close&nbsp;thread&nbsp;handle</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;CloseHandle(hThread1);<br>&nbsp;&nbsp;&nbsp;&nbsp;CloseHandle(hThread2);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Note:&nbsp;Prevent&nbsp;process&nbsp;exiting</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">)<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br><br></span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">.用临界区来控制线程<br>DWORD&nbsp;__stdcall&nbsp;ThreadFunOne(LPVOID&nbsp;lParam)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">(;;)<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;EnterCriticalSection(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">Section);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(WorkerID</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">MAXWORKERID)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WorkerID&nbsp;</span><span style="COLOR: #000000">+=</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sleep(</span><span style="COLOR: #000000">1000</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">ThreadOne&nbsp;print&nbsp;out:&nbsp;%i&nbsp;\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,WorkerID);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LeaveCriticalSection(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">Section);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>}<br>DWORD&nbsp;__stdcall&nbsp;ThreadFunTwo(LPVOID&nbsp;lParam)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">(;;)<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;EnterCriticalSection(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">Section);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(WorkerID</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">MAXWORKERID)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WorkerID&nbsp;</span><span style="COLOR: #000000">+=</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">ThreadTwo&nbsp;print&nbsp;out:&nbsp;%i&nbsp;\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,WorkerID);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sleep(</span><span style="COLOR: #000000">1000</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LeaveCriticalSection(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">Section);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>}<br></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;main()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Define&nbsp;thread&nbsp;handle</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;HANDLE&nbsp;hThread1,hThread2;<br>&nbsp;&nbsp;&nbsp;&nbsp;InitializeCriticalSection(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">Section);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Create&nbsp;thread</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;hThread1&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;::CreateThread(NULL,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,ThreadFunOne,NULL,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,NULL);<br>&nbsp;&nbsp;&nbsp;&nbsp;hThread2&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;::CreateThread(NULL,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,ThreadFunTwo,NULL,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,NULL);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Close&nbsp;thread&nbsp;handle</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;CloseHandle(hThread1);<br>&nbsp;&nbsp;&nbsp;&nbsp;CloseHandle(hThread2);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Note:&nbsp;Prevent&nbsp;process&nbsp;exiting</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">)<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br><br></span><span style="COLOR: #000000">3</span><span style="COLOR: #000000">.用互斥来控制线程<br>DWORD&nbsp;__stdcall&nbsp;ThreadFunOne(LPVOID&nbsp;lParam)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">(;;)<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WaitForSingleObject(hMutex,&nbsp;INFINITE);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(WorkerID</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">MAXWORKERID)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WorkerID&nbsp;</span><span style="COLOR: #000000">+=</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sleep(</span><span style="COLOR: #000000">1000</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">ThreadOne&nbsp;print&nbsp;out:&nbsp;%i&nbsp;\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,WorkerID);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ReleaseMutex(hMutex);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>}<br>DWORD&nbsp;__stdcall&nbsp;ThreadFunTwo(LPVOID&nbsp;lParam)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">(;;)<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WaitForSingleObject(hMutex,&nbsp;INFINITE);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(WorkerID</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">MAXWORKERID)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WorkerID&nbsp;</span><span style="COLOR: #000000">+=</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">ThreadTwo&nbsp;print&nbsp;out:&nbsp;%i&nbsp;\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,WorkerID);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sleep(</span><span style="COLOR: #000000">1000</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ReleaseMutex(hMutex);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>}<br></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;main()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Define&nbsp;thread&nbsp;handle</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;HANDLE&nbsp;hThread1,hThread2;<br>&nbsp;&nbsp;&nbsp;&nbsp;hMutex&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;CreateMutex(NULL,&nbsp;FALSE,&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">mutex</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Create&nbsp;thread</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;hThread1&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;::CreateThread(NULL,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,ThreadFunOne,NULL,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,NULL);<br>&nbsp;&nbsp;&nbsp;&nbsp;hThread2&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;::CreateThread(NULL,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,ThreadFunTwo,NULL,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,NULL);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Close&nbsp;thread&nbsp;handle</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;CloseHandle(hThread1);<br>&nbsp;&nbsp;&nbsp;&nbsp;CloseHandle(hThread2);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Note:&nbsp;Prevent&nbsp;process&nbsp;exiting</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">)<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}</span></div>
 <img src ="http://www.cppblog.com/yunboy4/aggbug/91181.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yunboy4/" target="_blank">yunboy</a> 2009-07-25 22:48 <a href="http://www.cppblog.com/yunboy4/archive/2009/07/25/91181.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>