??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲精品白浆高清久久久久久,久久精品人人做人人爽97,亚洲精品乱码久久久久久久久久久久http://www.shnenglu.com/ccl0326/category/11336.htmlabout:blankzh-cnTue, 30 Mar 2010 04:56:01 GMTTue, 30 Mar 2010 04:56:01 GMT60iocp(我所见过讲的最通俗易懂的……)http://www.shnenglu.com/ccl0326/archive/2010/03/29/110911.htmlVincentVincentMon, 29 Mar 2010 13:05:00 GMThttp://www.shnenglu.com/ccl0326/archive/2010/03/29/110911.htmlhttp://www.shnenglu.com/ccl0326/comments/110911.htmlhttp://www.shnenglu.com/ccl0326/archive/2010/03/29/110911.html#Feedback0http://www.shnenglu.com/ccl0326/comments/commentRss/110911.htmlhttp://www.shnenglu.com/ccl0326/services/trackbacks/110911.html理解I/O Completion Port
摘自:http://gzlyb.cnblogs.com/archive/2005/09/30/247049.aspx
      Ƣ迎阅读此篇IOCP教程。我先l出IOCP的定义然后给出它的实现方法,最后剖析一个EchoE序来ؓ您拨开IOCP的谜云,除去你心中对IOCP的烦恹{OKQ但我不能保证你明白IOCP的一切,但我会尽我最大的努力。以下是我会在这文章中提到的相x术:
  I/O端口
  同步/异步
  堵塞/非堵?br>  服务?客户?br>  多线E程序设?br>  Winsock API 2.0
  在这之前Q我曄开发过一个项目,其中一块需要网l支持,当时q考虑C代码的可UL性,只要使用select,connect,accept,listen,sendq有recv,再加上几?ifdef的封装以用来处理Winsock和BSD套接字[socket]中间的不兼容性,一个网l子pȝ只用了几个小时很的代码写出来了,至今q让我很回味。那以后很长旉也就没再C?br>  前些日子Q我们策划做一个网l游戏,我主动承担下|络q一块,xq还不是case,心里L乐啊。网l游戏好啊,|络游戏为成百上千的玩家提供了乐和令h着U的游戏体验Q他们在U上互相战斗或是加入队伍L胜共同的敌h。我信心满满的准备开写我的网l,于是乎,发现q去的阻塞同步模式模式根本不能拿C个巨量多玩家[MMP]的架构中去,直接被否定掉了。于是乎Q就有了IOCPQ如果能q很L而D的搞掂IOCPQ也׃会有q篇教程了。下面请怽跟随我进入正题?/p>

什么是IOCPQ?br>先让我们看看对IOCP的评?br>I/O完成端口可能是Win32提供的最复杂的内核对象?br>[Advanced Windows 3rd] Jeffrey Richter
q是[IOCP]实现高容量网l服务器的最x法?br>[Windows Sockets2.0:Write Scalable Winsock Apps Using Completion Ports]
Microsoft Corporation
完成端口模型提供了最好的伸羃性。这个模型非帔R用来处理数百乃至上千个套接字?br>[Windows|络~程2nd] Anthony Jones & Jim Ohlund
I/O completion ports特别昑־重要Q因为它们是唯一适用于高负蝲服务器[必须同时l护许多q接U\]的一个技术。Completion ports利用一些线E,帮助q由I/Oh所引v的负载。这L架构特别适合用在SMPpȝ中生的”scalable”服务器?br>[Win32多线E程序设计] Jim Beveridge & Robert Wiener
 
看来我们完全有理q信IOCP是大型网l架构的首选?br>那IOCP到底是什么呢Q?br>  微Y在Winsock2中引入了IOCPq一概念 。IOCP全称I/O Completion PortQ中文译为I/O完成端口。IOCP是一个异步I/O的APIQ它可以高效地将I/O事g通知l应用程序。与使用select()或是其它异步Ҏ不同的是Q一个套接字[socket]与一个完成端口关联了hQ然后就可l进行正常的Winsock操作了。然而,当一个事件发生的时候,此完成端口就被操作pȝ加入一个队列中。然后应用程序可以对核心层进行查询以得到此完成端口?br>  q里我要对上面的一些概늕作补充,在解释[完成]两字之前Q我惛_单的提一下同步和异步q两个概念,逻辑上来讲做完一件事后再d另一件事是同步Q而同时一起做两g或两件以上事的话是异步了。你也可以拿单线E和多线E来作比喅R但是我们一定要同步和堵塞Q异步和非堵塞区分开来,所谓的堵塞函数诸如accept(…)Q当调用此函数后Q此时线E将挂vQ直到操作系l来通知它,”HEY兄弟Q有q来?#8221;Q那个挂LU程l进行工作,也就W合”生?消费?#8221;模型。堵塞和同步看上L两分怼Q但却是完全不同的概c大安知道I/O讑֤是个相对慢速的讑֤Q不论打印机Q调制解调器Q甚至硬盘,与CPU相比都是奇慢无比的,坐下来等I/O的完成是一件不甚明智的事情Q有时候数据的动率非常惊人,把数据从你的文g服务器中以Ethernet速度搬走Q其速度可能高达每秒一百万字节Q如果你试从文件服务器中读?00KBQ在用户的眼光来看几乎是瞬间完成Q但是,要知道,你的U程执行q个命oQ已l浪费了10个一百万ơCPU周期。所以说Q我们一般用另一个线E来q行I/O。重叠IO[overlapped I/O]是Win32的一Ҏ术,你可以要求操作系lؓ你传送数据,q且在传送完毕时通知你。这也就是[完成]的含义。这Ҏ术你的E序在I/Oq行q程中仍然能够l处理事务。事实上Q操作系l内部正是以U程来完成overlapped I/O。你可以获得U程所有利益,而不需要付Z么痛苦的代h?br>  完成端口中所谓的[端口]q不是我们在TCP/IP中所提到的端口,可以说是完全没有关系。我到现在也没想通一个I/O讑֤[I/O Device]和端口[IOCP中的Port]有什么关pR估计这个端口也qh了不h。IOCP只不q是用来q行d操作Q和文gI/O倒是有些cM。既然是一个读写设备,我们所能要求它的只是在处理M写上的高效。在文章的第三部分你会轻而易丄发现IOCP设计的真正用意?/p>

IOCP和网l又有什么关p?
int main()
{
    WSAStartup(MAKEWORD(2, 2), &wsaData);
    ListeningSocket = socket(AF_INET, SOCK_STREAM, 0);
    bind(ListeningSocket, (SOCKADDR*)&ServerAddr, sizeof(ServerAddr));
    listen(ListeningSocket, 5);
    int nlistenAddrLen = sizeof(ClientAddr);
    while(TRUE)
    {
        NewConnection = accept(ListeningSocket, (SOCKADDR*)&ClientAddr, &nlistenAddrLen);
        HANDLE hThread = CreateThread(NULL, 0, ThreadFunc, (void*) NewConnection, 0, &dwTreadId);
        CloseHandle(hThread);
    }
    return 0;
}
  怿只要写过|络的朋友,应该对这Ll构在熟悉不q了。accept后线E被挂vQ等待一个客户发求,而后创徏新线E来处理h。当新线E处理客戯求时Qv初的U程循环回去{待另一个客戯求。处理客戯求的U程处理完毕后终l?br>  在上q的q发模型中,Ҏ个客戯求都创徏了一个线E。其优点在于{待h的线E只需做很的工作。大多数旉中,该线E在休眠[因ؓrecv处于堵塞状态]?br>  但是当ƈ发模型应用在服务器端[ZWindows NT]QWindows NT组注意到这些应用程序的性能没有预料的那么高。特别的Q处理很多同时的客户h意味着很多U程q发地运行在pȝ中。因为所有这些线E都是可q行的[没有被挂起和{待发生什么事]QMicrosoft意识到NT内核p了太多的旉来{换运行线E的上下文[Context]Q线E就没有得到很多CPU旉来做它们的工作?br>  大家可能也都感觉到ƈ行模型的瓉在于它ؓ每一个客戯求都创徏了一个新U程。创建线E比起创E开销要小Q但也远不是没有开销的?br>  我们不妨设想一下:如果事先开好N个线E,让它们在那hold[堵塞]Q然后可以将所有用Lh都投递到一个消息队列中厅R然后那N个线E逐一从消息队列中d出消息ƈ加以处理。就可以避免针对每一个用戯求都开U程。不仅减了U程的资源,也提高了U程的利用率。理Z很不错,你想我等泛泛之辈都能惛_来的问题QMicrosoft又怎会没有考虑到呢 !
  q个问题的解x法就是一个称为I/O完成端口的内核对象,他首ơ在Windows NT3.5中被引入?br>  其实我们上面的构惛_该就差不多是IOCP的设计机理。其实说I了IOCP不就是一个消息队列嘛Q你说这和[端口]q两字有何联pR我的理解就是IOCP最多是应用E序和操作系l沟通的一个接口Ş了?br>  至于IOCP的具体设计那我也很难说得上来Q毕竟我没看q实现的代码Q但你完全可以进行模拟,只不q性能可能…Q如果想深入理解IOCPQ?Jeffrey Ritchter的Advanced Windows 3rd其中W?3章和W?4张有很多宝贵的内容,你可以拿来窥视一下系l是如何完成q一切的?br> 
实现Ҏ
Microsoft为IOCP提供了相应的API函数Q主要的׃个,我们逐一的来看一下:
HANDLE CreateIoCompletionPort (
    HANDLE FileHandle,                            // handle to file
    HANDLE ExistingCompletionPort,          // handle to I/O completion port
    ULONG_PTR CompletionKey,               // completion key
    DWORD NumberOfConcurrentThreads  // number of threads to execute concurrently
);
在讨论各参数之前Q首先要注意该函数实际用于两个截然不同的目的Q?br>1Q用于创Z个完成端口对?br>2Q将一个句柄[HANDLE]和完成端口关联到一?br>  在创Z个完成一个端口的时候,我们只需要填写一下NumberOfConcurrentThreadsq个参数可以了。它告诉pȝ一个完成端口上同时允许q行的线E最大数。在默认情况下,所开U程数和CPU数量相同Q但l验l我们一个公式:
  U程?= CPU?* 2 + 2
要完成端口有用Q你必须把它同一个或多个讑֤相关联。这也是调用CreateIoCompletionPort完成的。你要向该函C递一个已有的完成端口的句柄,我们既然要处理网l事Ӟ那也是客Lsocket作ؓHANDLE传进厅R和一个完成键[对你有意义的一?2位|也就是一个指针,操作pȝq不兛_你传什么]。每当你向端口关联一个设备时Q系l向该完成端口的讑֤列表中加入一条信息纪录?br>另一个API是
BOOL GetQueuedCompletionStatus(
    HANDLE CompletionPort,            // handle to completion port
    LPDWORD lpNumberOfBytes,      // bytes transferred
    PULONG_PTR lpCompletionKey,   // file completion key
    LPOVERLAPPED *lpOverlapped,   // buffer
    DWORD dwMilliseconds             // optional timeout value
);
W一个参数指ZU程要监视哪一个完成端口。很多服务应用程序只是用一个I/O完成端口Q所有的I/Oh完成以后的通知都将发给该端口。简单的_GetQueuedCompletionStatus使调用线E挂P直到指定的端口的I/O完成队列中出C一Ҏ直到时。同I/O完成端口相关联的W?个数据结构是使线E得到完成I/O中的信息:传输的字节数Q完成键和OVERLAPPEDl构的地址。该信息是通过传递给GetQueuedCompletionSatatus的lpdwNumberOfBytesTransferredQlpdwCompletionKey和lpOverlapped参数q回l线E的?br>Ҏ到目前ؓ止已l讲到的东西Q首先来构徏一个frame。下面ؓ您说明了如何使用完成端口来开发一个echo服务器。大致如下:
  1.初始化Winsock
  2.创徏一个完成端?br>  3.Ҏ服务器线E数创徏一定量的线E数
  4.准备好一个socketq行bind然后listen
  5.q入循环accept{待客户h
  6.创徏一个数据结构容Usocket和其他相关信?br>  7.连q来的socket同完成端口相兌
  8.投递一个准备接受的h
以后׃断的重复5?的过E?br>那好Q我们用具体的代码来展示一下细节的操作?br>  x文章也该告一D落?我带着您做了一旋风般的旅?游览了所谓的完成端口?br> 



Vincent 2010-03-29 21:05 发表评论
]]>
<?gt;c++指针的创?个h觉得讲的赞&清晰)http://www.shnenglu.com/ccl0326/archive/2010/03/18/109974.htmlVincentVincentThu, 18 Mar 2010 05:08:00 GMThttp://www.shnenglu.com/ccl0326/archive/2010/03/18/109974.htmlhttp://www.shnenglu.com/ccl0326/comments/109974.htmlhttp://www.shnenglu.com/ccl0326/archive/2010/03/18/109974.html#Feedback0http://www.shnenglu.com/ccl0326/comments/commentRss/109974.htmlhttp://www.shnenglu.com/ccl0326/services/trackbacks/109974.htmlzero 坐在桌前,机械的重?#8220;夹菜 -> 咀?-> 吞咽”的动作序列,怸用无形的大字写着Q我心不在焉。在他的寚w坐着 Solmyr Q慢条斯理的吃着他那份午,l持着他一贯很有修ȝ形象 ——?或者按?zero q些熟悉他本质的人的说法Q假象?/p>

“怎么?zero Q胃口不好么Q?#8221;Q基本填p子之后,Solmyr 觉得g应该兛_一下他的学徒了?/p>

“呃,没什么,只是 …… Solmyr QC++ Z么不支持垃圾攉呢?Q注Q垃圾收集是一U机Ӟ保证动态分配了的内存块会自动释放,Java {语a支持q一机制。)”

Solmyr 叹了口气Q用一U^静的眼神盯着 zero Q?#8220;是不是在 BBS 上和人吵 C++ ?Java 哪个更好Q而且吵输了?我早告诉q你Q这U争论再无聊不过了?#8221;

“?…… ?#8221;Qzero 不得不承?——?Solmyr 的眼虽然一点也不锐利,但是却莫名其妙的?zero 产生了微微的恐惧感?/p>

“而且Q谁告诉?C++ 不支持垃圾收集的Q?#8221;

“啊!Solmyr 你不是开玩笑吧?Q?#8221;

“zero 你得转变一下观c我问你QC++ 支不支持可以动态改变大的数组Q?#8221;

“q?…… 好象也没有吧Q?#8221;

“?vector 是什么东西?”

“?……”

“支持一U特性,q不是说非得把这个特性加到语法里去,我们也可以选择用现有的语言机制实现一个库来支持这个特征。以垃圾攉ZQ这里我们的d是要保证每一个被动态分配的内存块都能够被释放,也就是说 ……”QSolmyr 不知从哪里找Z一张纸、一支笔Q写刎ͼ

 

int* p = new int; // 1
delete p; // 2

 

“也就是说Q对于每一?1 Q我们要保证有一?2 被调用,1 ?2 必须成对出现。我来问你,C++ 中有什么东西是pa本n保证一定成对出现的Q?#8221;

“……”Qzero 露出了努力搜索记忆的表情Q不q很明显一无所莗?/p>

“提示一下,和类的创建有兟?#8221;

“哦!构造函C析构函数Q?#8221;

“正确。可惜普通指针没有构造函C析构函数Q所以我们必要写一个类来加一层包装,最单的pq样Q?#8221;

 

class my_intptr
{
    public:
    int* m_p;

    my_intptr(int* p){ m_p = p; }
    ~my_intptr(){ delete m_p; }
};

…………

my_intptr pi(new int);
*(pi.m_p) = 10;

…………

 

“q里我们可以攑ֿ的?my_intptr Q不用担心内存泄漏的问题Q一?pi q个变量被销毁,我们知道 pi.p 指向的内存块一定会被释放。不q如果每ơ?my_intptr 都得去访问它的成员未免太ȝ了。ؓ此,可以l这个类加上重蝲?* q算W:”

 

class my_intptr
{
    private:
        int* m_p;

    public:
        my_intptr(int* p){ m_p = p; }
        ~my_intptr(){ delete m_p; }

        int& operator*(){ return *m_p; }
};

…………

my_intptr pi;
*pi = 10;
int a = *pi;

…………

 

“现在是不是看h my_intptr 像是一个真正的指针了?正因为如此,q种技术被UCؓ指针。现在我问你Q这个类q缺哪些东西?”

zero q眉头Q眼睛一眨一眨,看上d像一台慢速电脑正在辛苦的往它的盘上拷贝文件。良久,zero 抬v头来Q不太确定的_“是不是还~少一个拷贝构造函数和一个赋D符Q?#8221;

“说说Z么?#8221;QSolmyr 昄不打就q样放过 zero?/p>

“因ؓ …… 我记得没错的?…… ?0 ?》(注:指《Effective C++ 2/e》一书)中提到过Q如果你的类里面有指针指向动态分配的内存Q那么一定要为它写一个拷贝构造函数和一个赋D符 …… 因ؓ …… 否则的话Q一旦你做了赋|会导致两个对象的指针指向同一块内存。对了!如果是上面的c,q样一来会D同一个指针被 delete 两次Q?#8221;

“正确。那么我们应该怎样来实现呢Q?#8221;

“q简单,我们?memcpy 把目标指针指向的内存中的内容拯q来?#8221;

“如果我们的智能指针指向一个类的对象怎么办?注意Q类的对象中可能有指针,不能?memcpy?#8221;

“?…… 我们用拷贝构造的办法?#8221;

“如果我们的智能指针指向的对象不能拯构造怎么办?它可能有一个私有的拯构造函数?#8221;

“?……”Qzero 了一,军_老实承认Q?#8220;我不知道?#8221;

“问题在哪你知道么Q在于你没有把智能指针看作指针。想象一下,如果我们对一个指针做赋|它的含义是什么?”

“呃,我明白了Q在q种情况下,应该惛_法让两个指针指向同一个对?…… 可是 Solmyr Q这样以来岂不是仍然要对同一个对象删除两遍?”

“是的Q我们得惛_法解册个问题,办法不只一U。比较好的一U是为每个指针维护一个引用计数|每次赋值或者拷贝构造,p计数值加一Q这意味着指向q个内存块的指针又多了一个;而每有一个智能指针被销毁,p计数值减一Q这意味着指向q个内存块的指针了一个;一旦计数gؓ 0 Q就释放内存块。象q样Q?#8221;

 

class my_intptr
{
    private:
        int* m_p;
        int* m_count;

    public:
        my_intptr(int* p)
        {
             m_p = p;
             m_count = new int;

            // 初始化计数gؓ 1
            *m_count = 1;
        }
        my_intptr(const my_intptr& rhs) // 拯构造函?
       {
            m_p = rhs.m_p; // 指向同一块内?
            m_count = rhs.m_count; // 使用同一个计数?
           (*m_count)++; // 计数值加 1
       }
       ~my_intptr()
      {
           (*m_count)--; // 计数值减 1
          if( *m_count == 0 ) // 已经没有别的指针指向该内存块?
         {
              delete m_p;
              delete m_count;
         }
      }

      my_intptr& operator=(const my_intptr& rhs)
     {
          if( m_p == rhs.m_p ) // 首先判断是否本来指向同一内存?
                return *this; // 是则直接q回

          (*m_count)--; // 计数值减 1 Q因指针不再指向原来内存块了
         if( *m_count == 0 ) // 已经没有别的指针指向原来内存块了
         {
              delete m_p;
              delete m_count;
          }

          m_p = rhs.m_p; // 指向同一块内?
          m_count = rhs.m_count; // 使用同一个计数?
         (*m_count)++; // 计数值加 1
    }

…………
};

 

“其他部分没有什么太大变化,我不费事了。现在想象一下我们怎样使用q种指针Q?#8221;QSolmyr 放下了笔Q再ơ拿起了{子Q有些惋惜的发现他爱吃的肉丸子已l冷了?/p>

zero 惌着Q有些迟疑?#8220;我们 …… 可以?new int 表达式作为构造函数的参数来构造一个智能指针,然后 …… 然后我们可以L的赋|”Q他开始抓住了思\Q越说越快,“L的用已经存在的智能指针来构造新的智能指针,指针的赋D符、拷贝构造函数和析构会保证计数值始l等于指向该内存块的指针数?#8221;zero g明白了他看到了怎样的功能,开始激动v来:“然后一旦计数gؓ 0 被分配的内存块就会释放!也就是说 …… 有指针指向内存块Q它׃释放Q一旦没有,它就自动释放Q太了Q我们只要一开始正的初始化智能指针,可以象普通指针那样用它Q而且完全不用担心内存释放的问题!太棒了!”zero Ȁ动的大叫Q?#8220;q就是垃圾收集!Solmyr Q我们在饭桌上实C一个垃圾收集器Q?#8221;

Solmyr 很明显没有分?zero 的激动:“我在吃饭Q你能不能不要大?#8216;饭桌上实C一个垃圾收集器’q种倒胃口的话?”了一,Solmyr 带着他招牌式的坏W,以一U可恶的口吻说道Q?#8220;而且h意一下自q形象?#8221;

“嗯?”Qzero 回过来Q发现自׃知什么时候站了v来,而整个餐厅里的h都在看着他嘿嘿偷W,q让他感觉自己像个傻瓜?/p>

zero U着脸坐下,压低了声音问 Solmyr Q?#8220;不过 Solmyr Q这实是一个的垃圾攉机制啊,只要我们把这个类Ҏ …… ?…… Ҏ模板c,象这P”zero 抓过了纸W,写到Q?/p>

 

template <typename T>
class my_ptr
{
    private:
    T* m_p;
    int* m_count;
    …………
};

 

“它不p支持Lcd的指针了吗?我们可以把它用在Q何地斏V?#8221;

Solmyr 摇了摇头Q?#8220;不,你把问题想的太简单了。对于简单的cdQ这个类实可以处理的很好,但实际情冉|很复杂的。考虑一个典型情况:c?Derived 是类 Base 的派生类Q我们希望这栯|”

Base* pb;
Derived pd;
…………
pb = pd;

“你倒说说看Q这U情况,怎样改用上面q个指针来处理?”

“……”Qzero 沉默了?/p>

“要实C个完整的垃圾攉机制q不ҎQ因为有许多l节要考虑?#8221;QSolmyr 开始ȝ了,“不过Q基本思\是上面说的q些。值得庆幸的是Q目前已l有了一个相当成熟的‘引用计数’指针Qboost::shared_ptr。大多数情况下,我们都可以用它。另外,除了指针之外Q还有一些技术也能够帮助我们避开释放内存的问题,比如内存池。但是,关键在于 ——?”

Solmyr 再度用那U^静的眼神盯着 zero Q?/p>

“wؓ C/C++ E序员,必须有创造力。那Uh在语a机制上不思进取的人,那种必须要靠语法强制才知道怎样~程的hQ那U没有别人告诉他该干什么就无所适从的hQ不适合q门语言?#8221;

 

 

Ƣ迎讉K梦断酒醒的博客:http://www.yanzhijun.com

 

本文来自CSDN博客Q{载请标明出处Q?a >http://blog.csdn.net/ishallwin/archive/2009/09/08/4533145.aspx



Vincent 2010-03-18 13:08 发表评论
]]>
ľþþƷww16 | ɫþˬˬƬaV| ۺϾþþ| þùֻоƷ| ޹ƷþþþþԻ| vĻþ| ޹ƷþSM| ݺɫۺϾþȥ | 99þerֻоƷ18| þù޾Ʒ鶹| ŷƷۺϾþ| Ʒŷ޺ձþ| þþƷȫۿ| һþaþþƷۺҹҹ| ŷպƷþ| þ㽶߿ۿ| þsmȤ| þùƷ԰| þԭƷ| ˾þô߽ۺ| 99þ99þþƷƬ| þþƷþþþùۿ99ˮ| Ʒþþþ| þþþۺþ| ˮϵþþƷ| þþƷƵһ| һõþۺϺݺAV| þþþþþþþ| Ʒþþ| þۺϸϾþù| ˼˼þ99ֻƵƷ66| ޹Ƶþ| ޹ƷۺϾþһ| ݺ޾þþþþۺ| ҹƷþþþþžŵӰ | ۲ӰԺþ99| 91Ʒ91þþþþ| Ʒþþþ㽶| þþƷAV| þþƷ}Ů| þˬˬˬ˾þþ|