??xml version="1.0" encoding="utf-8" standalone="yes"?>久久96国产精品久久久,91久久精品国产91性色也,久久精品国产清自在天天线http://www.shnenglu.com/singohgod/category/17452.html每天晚上入睡Q都迎来崭新的明天Q这是梦想Q?大宝天天?/description>zh-cnMon, 17 Oct 2011 09:24:01 GMTMon, 17 Oct 2011 09:24:01 GMT60[转蝲]Linux静态库和动态库http://www.shnenglu.com/singohgod/archive/2011/10/17/158546.html大宝天天?/dc:creator>大宝天天?/author>Mon, 17 Oct 2011 07:51:00 GMThttp://www.shnenglu.com/singohgod/archive/2011/10/17/158546.htmlhttp://www.shnenglu.com/singohgod/comments/158546.htmlhttp://www.shnenglu.com/singohgod/archive/2011/10/17/158546.html#Feedback0http://www.shnenglu.com/singohgod/comments/commentRss/158546.htmlhttp://www.shnenglu.com/singohgod/services/trackbacks/158546.html库从本质上来说是一U可执行代码的二q制格式Q可以被载入内存中执行。库分静态库和动态库两种?nbsp;

静态库和动态库的区?/h1>

1. 静态函数库

    q类库的名字一般是libxxx.aQ利用静态函数库~译成的文g比较大,因ؓ(f)整个 函数库的所有数据都?x)被整合q目标代码中Q他的优点就显而易见了Q即~译后的执行E序不需要外部的函数库支持,因ؓ(f)所有用的函数都已l被~译q去了。当然这也会(x)成ؓ(f)他的~点Q因为如果静态函数库改变了,那么你的E序必须重新~译?/p>

2. 动态函数库

    q类库的名字一般是libxxx.so;相对于静态函数库Q动态函数库在编译的时?q没有被~译q目标代码中Q你的程序执行到相关函数时才调用该函数库里的相应函数Q因此动态函数库所产生的可执行文g比较?yu)。由于函数库没有被整合进你的E序Q而是E序q行时动态的甌q调用,所以程序的q行环境中必L供相应的库。动态函数库的改变ƈ不媄响你的程序,所以动态函数库的升U比较方ѝ?nbsp;
linuxpȝ有几个重要的目录存放相应的函数库Q如/lib /usr/lib?/p>

静态库的?/h1>

静态库的操作工P(x)gcc和ar 命o(h)?nbsp;

~写?qing)用静态库 

(1)设计库源?pr1.c ?pr2.c 

[root@billstone make_lib]# cat pr1.c 

void print1() 

                printf("This is the first lib src!\n"); 

[root@billstone make_lib]# cat pr2.c 

void print2() 

                printf("This is the second src lib!\n"); 

       (2)  ~译.c 文g 

[bill@billstone make_lib]$ cc -O -c pr1.c pr2.c 

[bill@billstone make_lib]$ ls -l pr*.o 

-rw-rw-r--        1 bill          bill                    804    4 ?nbsp; 15 11:11 pr1.o 

-rw-rw-r--        1 bill          bill                    804    4 ?nbsp; 15 11:11 pr2.o 

(3)  链接静态库 

    Z在编译程序中正确扑ֈ库文?静态库必须按照 lib[name].a 的规则命?如下例中[name]=pr. 

[bill@billstone make_lib]$ ar -rsv libpr.a pr1.o pr2.o 

a - pr1.o 

a - pr2.o 

[bill@billstone make_lib]$ ls -l *.a 

-rw-rw-r--        1 bill          bill                  1822    4 ?nbsp; 15 11:12 libpr.a 

[bill@billstone make_lib]$ ar -t libpr.a 

pr1.o 

pr2.o 

(4)  调用库函C?main.c 

[bill@billstone make_lib]$ cat main.c 

int main() 

                print1(); 

                print2(); 

                return 0; 

(5)  ~译链接选项 

    -L ?l 参数攑֜后面.其中,-L 加蝲库文件\?-l 指明库文件名? 

[bill@billstone make_lib]$ gcc -o main main.c -L./ -lpr 

[bill@billstone make_lib]$ ls -l main* 

-rwxrwxr-x        1 bill          bill                11805    4 ?nbsp; 15 11:17 main 

-rw-rw-r--        1 bill          bill                      50    4 ?nbsp; 15 11:15 main.c 

(6)执行目标E序 

[bill@billstone make_lib]$ ./main 

This is the first lib src! 

This is the second src lib! 

[bill@billstone make_lib]$ 

动态库的?/h1>

~写动态库 

(1)设计库代?/strong> 

[bill@billstone make_lib]$ cat pr1.c 

int p = 2; 

void print(){ 

                printf("This is the first dll src!\n"); 

[bill@billstone make_lib]$   

(2)生成动态库 

[bill@billstone make_lib]$ gcc -O -fpic -shared -o dl.so pr1.c 

[bill@billstone make_lib]$ ls -l *.so 

-rwxrwxr-x        1 bill          bill                  6592    4 ?nbsp; 15 15:19 dl.so 

[bill@billstone make_lib]$ 

动态库的隐式调?/strong> 

  在编译调用库函数代码时指明动态库的位|及(qing)名字,  看下面实?nbsp;

[bill@billstone make_lib]$ cat main.c 

int main() 

                print(); 

                return 0; 

[bill@billstone make_lib]$ gcc -o tdl main.c ./dl.so 

[bill@billstone make_lib]$ ./tdl 

This is the first dll src! 

[bill@billstone make_lib]$ 

当动态库的位|活名字发生改变?  E序无法正常运?  而动态库取代静态库的好处之一则是通过更新动态库而随时升U库的内? 

动态库的显式调?/strong> 

  昑ּ调用动态库需要四个函数的支持,  函数 dlopen 打开动态库,  函数 dlsym 获取动态库中对象基址,  ?/strong>?dlerror 获取昑ּ动态库操作中的错误信息,  函数 doclose 关闭动态库.

[bill@billstone make_lib]$ cat main.c 

#include <dlfcn.h> 

int main() 

                void *pHandle; 

                void (*pFunc)();                                                    //  指向函数的指?nbsp;

                int *p; 

                pHandle = dlopen("./d1.so", RTLD_NOW);                  //  打开动态库 

                if(!pHandle){ 

                                printf("Can't find d1.so \n"); 

                                exit(1); 

                } 

                pFunc = (void (*)())dlsym(pHandle, "print");                //  获取库函?print 的地址 

                if(pFunc) 

                                pFunc(); 

                else 

                                printf("Can't find function print\n"); 

                p = (int *)dlsym(pHandle, "p");                                      //  获取库变?p 的地址 

                if(p) 

                                printf("p = %d\n", *p); 

                else 

                                printf("Can't find int p\n"); 

                dlclose(pHandle);                                                                //  关闭动态库 

                return 0; 

[bill@billstone make_lib]$ gcc -o tds main.c –ld1 –L.

此时q不能立?/tdsQ因为在动态函数库使用Ӟ?x)查?usr/lib?lib目录下的动态函数库Q而此时我们生成的库不在里辏V?q个时候有好几U方法可以让他成功运行:(x) 最直接最单的Ҏ(gu)是把libstr_out.so拉到/usr/lib?lib中去?q有一U方?export LD_LIBRARY_PATH=$(pwd) 另外q可以在/etc/ld.so.conf文g里加入我们生成的库的目录Q然?sbin/ldconfig?/etc/ld.so.conf是非帔R要的一个目录,里面存放的是链接器和加蝲器搜索共享库时要(g)查的目录Q默认是?usr/lib /lib中读取的Q所以想要顺利运行,我们也可以把我们库的目录加入到这个文件中q执?sbin/ldconfig 。另外还有个文g需要了?etc/ld.so.cache,里面保存了常用的动态函数库Q且?x)先把他们加载到内存中,因?f)内存的访问速度q远大于盘的访问速度Q这样可以提高Y件加载动态函数库的速度了?/p>

库依赖的查看

使用ldd命o(h)来查看执行文件依赖于哪些库?/p>

该命令用于判断某个可执行?binary 档案含有什么动态函式库?br /> [root@test root]# ldd [-vdr] [filename]
参数说明Q?br /> --version  打印l(f)dd的版本号
-v --verbose  打印所有信息,例如包括W号的版本信?br /> -d --data-relocs  执行W号重部|Ԍq报告缺的目标对象Q只对ELF格式适用Q?br /> -r --function-relocs  对目标对象和函数执行重新部vQƈ报告~少的目标对象和函数Q只对ELF格式适用Q?br /> --help 用法信息?/p>

如果命o(h)行中l定的库名字包含'/'Q这个程序的libc5版本用它作ؓ(f)库名字;否则它将在标准位|搜索库。运行一个当前目录下的共享库Q加前缀"./"?/p> @import url(http://www.shnenglu.com/CuteSoft_Client/CuteEditor/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);

]]>[转蝲]Windows完成端口与Linux epoll技术简?/title><link>http://www.shnenglu.com/singohgod/archive/2011/08/03/152376.html</link><dc:creator>大宝天天?/dc:creator><author>大宝天天?/author><pubDate>Wed, 03 Aug 2011 09:43:00 GMT</pubDate><guid>http://www.shnenglu.com/singohgod/archive/2011/08/03/152376.html</guid><wfw:comment>http://www.shnenglu.com/singohgod/comments/152376.html</wfw:comment><comments>http://www.shnenglu.com/singohgod/archive/2011/08/03/152376.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.shnenglu.com/singohgod/comments/commentRss/152376.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/singohgod/services/trackbacks/152376.html</trackback:ping><description><![CDATA[<p><strong>WINDOWS<strong>完成端口</strong>~程<br /> </strong>1、基本概?br /> 2、WINDOWS<strong>完成端口</strong>的特?br /> 3?strong>完成端口</strong>QCompletion Ports Q相x据结构和创徏<br /> 4?strong>完成端口</strong>U程的工作原?br /> 5、Windows<strong>完成端口</strong>的实例代?br /> <strong>Linux?strong>EPoll</strong>模型<br /> </strong>1、ؓ(f)什么select落后<br /> 2、内怸提高I(y)/O性能的新Ҏ(gu)<strong>epoll</strong><br /> 3?strong>epoll</strong>的优?br /> 4?strong>epoll</strong>的工作模?nbsp;<br /> 5?strong>epoll</strong>的用方?br /> 6、Linux?strong>EPOll</strong>~程实例<br /> <strong>ȝ</strong></p> <p><strong>WINDOWS<strong>完成端口</strong>~程<br /> </strong>        摘要Q开发网l程序从来都不是一件容易的事情Q尽只需要遵守很的一些规?创徏socket,发vq接Q接受连接,发送和接受数据。真正的困难在于Q让你的E序可以适应从单单一个连接到几千个连接乃至于上万个连接。利用Windowsq_<strong>完成端口</strong>q行重叠I/O的技术和Linux?.6版本的内怸引入?strong>EPOll</strong>技术,可以很方便在在在Windows和Linuxq_上开发出支持大量q接的网l服务程序。本文介l在Windows和Linuxq_上用的<strong>完成端口</strong>?strong>EPoll</strong>模型开发的基本原理Q同时给出实际的例子。本文主要关注C/Sl构的服务器端程序,因ؓ(f)一般来_(d)开发一个大定wQ具可扩展性的winsockE序一般就是指服务E序?br /> <strong><br /> 1、基本概?br /> </strong>    讑֤---windows操作pȝ上允?dng)R信的Q何东西,比如文g、目录、串行口、ƈ行口、邮件槽、命名管道、无名管道、套接字、控制台、逻辑盘、物理磁盘等。绝大多C讑֤打交道的函数都是CreateFile/ReadFile/WriteFile{。所以我们不能看?*File函数只惛_文g讑֤。与讑֤通信有两U方式,同步方式和异步方式。同步方式下Q当调用ReadFile函数Ӟ函数?x)等待系l执行完所要求的工作,然后才返回;异步方式下,ReadFileq类函数?x)直接返回,pȝ自己d成对讑֤的操作,然后以某U方式通知完成操作?br /> 重叠I/O----֐思义Q当你调用了某个函数Q比如ReadFileQ就立刻q回做自q其他动作的时候,同时pȝ也在对I/0讑֤q行你要求的操作Q在q段旉内你的程序和pȝ的内部动作是重叠的,因此有更好的性能。所以,重叠I/O是用于异步方式下使用I/O讑֤的?重叠I/O需要用的一个非帔R要的数据l构OVERLAPPED?br /> <strong><br /> 2、WINDOWS<strong>完成端口</strong>的特?br /> </strong>   Win32重叠I/O(Overlapped I/O)机制允许发v一个操作,然后在操作完成之后接受到信息。对于那U需要很长时间才能完成的操作来说Q重叠IO机制其有用Q因为发起重叠操作的U程在重叠请求发出后可以自q做别的事情了。在WinNT和W(xu)in2000上,提供的真正的可扩展的I/O模型是使用<strong>完成端口</strong>QCompletion PortQ的重叠I/O.<strong>完成端口</strong>---是一UWINDOWS内核对象?strong>完成端口</strong>用于异步方式的重叠I/0情况下,当然重叠I/O不一定非使用<strong>完成端口</strong>不可Q还有设备内核对象、事件对象、告警I/0{。但?strong>完成端口</strong>内部提供了线E池的管理,可以避免反复创徏U程的开销Q同时可以根据CPU的个数灵zȝ军_U程个数Q而且可以让减线E调度的ơ数从而提高性能其实cM于WSAAsyncSelect和select函数的机制更Ҏ(gu)兼容UnixQ但是难以实现我们想要的“扩展?#8221;。而且windows?strong>完成端口</strong>机制在操作系l内部已l作了优化,提供了更高的效率。所以,我们选择<strong>完成端口</strong>开始我们的服务器程序的开发?br /> 1、发h作不一定完成,pȝ?x)在完成的时候通知你,通过用户?strong>完成端口</strong>上的{待Q处理操作的l果。所以要有检?strong>完成端口</strong>Q取操作l果的线E。在<strong>完成端口</strong>上守候的U程pȝ有优化,除非在执行的U程dQ不?x)有新的U程被激z,以此来减线E切换造成的性能代h(hun)。所以如果程序中没有太多的阻塞操作,没有必要启动太多的线E,CPU数量的两倍,一般这h启动U程?br /> 2、操作与相关数据的绑定方式:(x)在提交数据的时候用户对数据打相应的标记Q记录操作的cdQ在用户处理操作l果的时候,通过(g)查自己打的标记和pȝ的操作结果进行相应的处理?nbsp;<br /> 3、操作返回的方式:一般操作完成后要通知E序q行后箋处理。但写操作可以不通知用户Q此时如果用户写操作不能马上完成Q写操作的相x据会(x)被暂存到到非交换~冲ZQ在操作完成的时候,pȝ?x)自动释攄冲区。此时发起完写操作,使用的内存就可以释放了。此时如果占用非交换~冲太多?x)ɾpȝ停止响应?br /> <strong><br /> 3?strong>完成端口</strong>QCompletion Ports Q相x据结构和创徏<br /> </strong>    其实可以?strong>完成端口</strong>看成pȝl护的一个队列,操作pȝ把重叠IO操作完成的事仉知攑ֈ该队列里Q由于是暴露 “操作完成”的事仉知Q所以命名ؓ(f)“<strong>完成端口</strong>”QCOmpletion PortsQ。一个socket被创建后Q可以在M时刻和一?strong>完成端口</strong>联系h?br /> <strong>完成端口</strong>相关最重要的是OVERLAPPED数据l构<br /> typedef struct _OVERLAPPED { <br />     ULONG_PTR Internal;//被系l内部赋|用来表示pȝ状?nbsp;<br />     ULONG_PTR InternalHigh;// 被系l内部赋|传输的字节数 <br />     union { <br />         struct { <br />             DWORD Offset;//和OffsetHigh合成一?4位的整数Q用来表CZ文g头部的多字节开?nbsp;<br />             DWORD OffsetHigh;//操作Q如果不是对文gI/O来操作,则必设定ؓ(f)0 <br />         }; <br />         PVOID Pointer; <br />     }; <br />     HANDLE hEvent;//如果不用,务必设?,否则误一个有效的Event句柄 <br /> } OVERLAPPED, *LPOVERLAPPED; <br /> <br /> 下面是异步方式用ReadFile的一个例?nbsp;<br /> OVERLAPPED Overlapped; <br /> Overlapped.Offset=345; <br /> Overlapped.OffsetHigh=0; <br /> Overlapped.hEvent=0; <br /> //假定其他参数都已l被初始?nbsp;<br /> ReadFile(hFile,buffer,sizeof(buffer),&dwNumBytesRead,&Overlapped); <br /> q样完成了异步方式L件的操作Q然后ReadFile函数q回Q由操作pȝ做自q事情Q下面介l几个与OVERLAPPEDl构相关的函?nbsp;<br /> {待重叠I/0操作完成的函?nbsp;<br /> BOOL GetOverlappedResult (<br /> HANDLE hFile,<br /> LPOVERLAPPED lpOverlapped,//接受q回的重叠I/0l构<br /> LPDWORD lpcbTransfer,//成功传输了多字节数<br /> BOOL fWait //TRUE只有当操作完成才q回QFALSE直接q回Q如果操作没有完成,通过?/用GetLastError ( )函数?x)返回ERROR_IO_INCOMPLETE <br /> );<br /> 宏HasOverlappedIoCompleted可以帮助我们试重叠I/0操作是否完成Q该宏对OVERLAPPEDl构的Internal成员q行了测试,查看是否{于STATUS_PENDING倹{?/p> <p>        一般来_(d)一个应用程序可以创建多个工作线E来处理<strong>完成端口</strong>上的通知事g。工作线E的数量依赖于程序的具体需要。但是在理想的情况下Q应该对应一个CPU创徏一个线E。因为在<strong>完成端口</strong>理想模型中,每个U程都可以从pȝ获得一?#8220;原子”性的旉片,轮番q行q检?strong>完成端口</strong>Q线E的切换是额外的开销。在实际开发的时候,q要考虑q些U程是否牉|到其他堵塞操作的情况。如果某U程q行堵塞操作Q系l则其挂vQ让别的U程获得q行旉。因此,如果有这L(fng)情况Q可以多创徏几个U程来尽量利用时间?br /> 应用<strong>完成端口</strong>Q?br />     创徏<strong>完成端口</strong>Q?strong>完成端口</strong>是一个内核对象,使用时他L要和臛_一个有效的讑֤句柄q行兌Q?strong>完成端口</strong>是一个复杂的内核对象Q创建它的函数是Q?br /> HANDLE CreateIoCompletionPort( <br />     IN HANDLE FileHandle, <br />     IN HANDLE ExistingCompletionPort, <br />     IN ULONG_PTR CompletionKey, <br />     IN DWORD NumberOfConcurrentThreads <br />     ); <br /> <br /> 通常创徏工作分两步:(x)<br /> W一步,创徏一个新?strong>完成端口</strong>内核对象Q可以用下面的函数Q?br />        HANDLE CreateNewCompletionPort(DWORD dwNumberOfThreads) <br /> { <br />           return CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,NULL,dwNumberOfThreads); <br /> };<br />        <br /> W二步,刚创徏?strong>完成端口</strong>和一个有效的讑֤句柄兌hQ可以用下面的函数Q?br />        bool AssicoateDeviceWithCompletionPort(HANDLE hCompPort,HANDLE hDevice,DWORD dwCompKey) <br /> { <br />           HANDLE h=CreateIoCompletionPort(hDevice,hCompPort,dwCompKey,0); <br />           return h==hCompPort; <br /> }; <br /> 说明 <br /> 1Q?CreateIoCompletionPort函数也可以一ơ性的既创?strong>完成端口</strong>对象Q又兌C个有效的讑֤句柄 <br /> 2Q?CompletionKey是一个可以自己定义的参数Q我们可以把一个结构的地址赋给它,然后在合适的时候取出来使用Q最好要保证l构里面的内存不是分配在栈上Q除非你有十分的把握内存?x)保留到你要使用的那一刅R?br /> 3Q?NumberOfConcurrentThreads通常用来指定要允许同时运行的的线E的最大个数。通常我们指定?Q这L(fng)l会(x)Ҏ(gu)CPU的个数来自动定。创建和兌的动作完成后Q系l会(x)?strong>完成端口</strong>兌的设备句柄、完成键作ؓ(f)一条纪录加入到q个<strong>完成端口</strong>的设备列表中。如果你有多?strong>完成端口</strong>Q就?x)有多个对应的设备列表。如果设备句柄被关闭Q则表中自动删除该纪录?br /> <strong><br /> 4?strong>完成端口</strong>U程的工作原?/strong><br /> <strong>完成端口</strong>可以帮助我们理U程池,但是U程池中的线E需要我们用_beginthreadex来创建,凭什么通知<strong>完成端口</strong>理我们的新U程呢?{案在函数GetQueuedCompletionStatus。该函数原型Q?nbsp;<br /> BOOL GetQueuedCompletionStatus( <br />     IN HANDLE CompletionPort, <br />     OUT LPDWORD lpNumberOfBytesTransferred, <br />     OUT PULONG_PTR lpCompletionKey, <br />     OUT LPOVERLAPPED *lpOverlapped, <br />     IN DWORD dwMilliseconds <br /> ); <br /> q个函数试图从指定的<strong>完成端口</strong>的I/0完成队列中抽取纪录。只有当重叠I/O动作完成的时候,完成队列中才有纪录。凡是调用这个函数的U程被攑օ?strong>完成端口</strong>的等待线E队列中Q因?strong>完成端口</strong>可以在自己的线E池中帮助我们维护这个线E?strong>完成端口</strong>的I/0完成队列中存放了当重叠I/0完成的结?--- 一条纪录,该纪录拥有四个字D,前三就对应GetQueuedCompletionStatus函数???参数Q最后一个字D|错误信息dwError。我们也可以通过调用PostQueudCompletionStatus模拟完成了一个重叠I/0操作?nbsp;<br /> 当I/0完成队列中出CU录Q?strong>完成端口</strong>会(x)(g)查等待线E队列,该队列中的线E都是通过调用GetQueuedCompletionStatus函数使自己加入队列的。等待线E队列很单,只是保存了这些线E的ID?strong>完成端口</strong>?x)按照后q先出的原则一个线E队列的ID攑օ到释攄E列表中Q同时该U程从{待GetQueuedCompletionStatus函数q回的睡眠状态中变ؓ(f)可调度状态等待CPU的调度。所以我们的U程要想成ؓ(f)<strong>完成端口</strong>理的线E,必要调用GetQueuedCompletionStatus函数。出于性能的优化,实际?strong>完成端口</strong>q维护了一个暂停线E列表,具体l节可以参考《Windows高~程指南》,我们现在知道的知识,已经_了?nbsp;<strong>完成端口</strong>U程间数据传递线E间传递数据最常用的办法是在_beginthreadex函数中将参数传递给U程函数Q或者用全局变量。但?strong>完成端口</strong>q有自己的传递数据的Ҏ(gu)Q答案就在于CompletionKey和OVERLAPPED参数?br /> CompletionKey被保存在<strong>完成端口</strong>的设备表中,是和讑֤句柄一一对应的,我们可以与讑֤句柄相关的数据保存到CompletionKey中,或者将CompletionKey表示为结构指针,q样可以传递更加丰富的内容。这些内容只能在一开始关?strong>完成端口</strong>和设备句柄的时候做Q因此不能在以后动态改变?br /> OVERLAPPED参数是在每次调用ReadFileq样的支持重叠I/0的函数时传递给<strong>完成端口</strong>的。我们可以看刎ͼ如果我们不是Ҏ(gu)件设备做操作Q该l构的成员变量就Ҏ(gu)们几乎毫无作用。我们需要附加信息,可以创徏自己的结构,然后OVERLAPPEDl构变量作ؓ(f)我们l构变量的第一个成员,然后传递第一个成员变量的地址lReadFile函数。因为类型匹配,当然可以通过~译。当GetQueuedCompletionStatus函数q回Ӟ我们可以获取到第一个成员变量的地址Q然后一个简单的强制转换Q我们就可以把它当作完整的自定义l构的指针用,q样可以传递很多附加的数据了。太好了Q只有一点要注意Q如果跨U程传递,h意将数据分配到堆上,q且接收端应该将数据用完后释放。我们通常需要将ReadFileq样的异步函数的所需要的~冲区放到我们自定义的结构中Q这样当GetQueuedCompletionStatus被返回时Q我们的自定义结构的~冲区变量中存放了I/0操作的数据。CompletionKey和OVERLAPPED参数Q都可以通过GetQueuedCompletionStatus函数获得?br /> U程的安全退?br />        很多U程Z不止一ơ的执行异步数据处理Q需要用如下语?br /> while (true)<br /> {<br />        ......<br />        GetQueuedCompletionStatus(...); <br />         ......<br /> }<br /> 那么如何退出呢Q答案就在于上面曾提到的PostQueudCompletionStatus函数Q我们可以用它发送一个自定义的包含了OVERLAPPED成员变量的结构地址Q里面包含一个状态变量,当状态变量ؓ(f)退出标志时Q线E就执行清除动作然后退出?br /> <strong><br /> 5、Windows<strong>完成端口</strong>的实例代码:(x)<br /> </strong>DWORD WINAPI WorkerThread(LPVOID lpParam)<br /> { <br /> ULONG_PTR *PerHandleKey;<br /> OVERLAPPED *Overlap;<br /> OVERLAPPEDPLUS *OverlapPlus,<br /> *newolp;<br /> DWORD dwBytesXfered;<br /> while (1)<br /> {<br /> ret = GetQueuedCompletionStatus(<br /> hIocp,<br /> &dwBytesXfered,<br /> (PULONG_PTR)&PerHandleKey,<br /> &Overlap,<br /> INFINITE);<br /> if (ret == 0)<br /> {<br /> // Operation failed<br /> continue;<br /> }<br /> OverlapPlus = CONTAINING_RECORD(Overlap, OVERLAPPEDPLUS, ol);<br /> switch (OverlapPlus->OpCode)<br /> {<br /> case OP_ACCEPT:<br /> // Client socket is contained in OverlapPlus.sclient<br /> // Add client to completion port<br /> CreateIoCompletionPort(<br /> (HANDLE)OverlapPlus->sclient,<br /> hIocp,<br /> (ULONG_PTR)0,<br /> 0);<br /> // Need a new OVERLAPPEDPLUS structure<br /> // for the newly accepted socket. Perhaps<br /> // keep a look aside list of free structures.<br /> newolp = AllocateOverlappedPlus();<br /> if (!newolp)<br /> {<br /> // Error<br /> }<br /> newolp->s = OverlapPlus->sclient;<br /> newolp->OpCode = OP_READ;<br /> // This function divpares the data to be sent<br /> PrepareSendBuffer(&newolp->wbuf);<br /> ret = WSASend(<br /> newolp->s,<br /> &newolp->wbuf,<br /> 1,<br /> &newolp->dwBytes,<br /> 0,<br /> &newolp.ol,<br /> NULL);<br /> if (ret == SOCKET_ERROR)<br /> {<br /> if (WSAGetLastError() != WSA_IO_PENDING)<br /> {<br /> // Error<br /> }<br /> }<br /> // Put structure in look aside list for later use<br /> FreeOverlappedPlus(OverlapPlus);<br /> // Signal accept thread to issue another AcceptEx<br /> SetEvent(hAcceptThread);<br /> break;<br /> case OP_READ:<br /> // Process the data read <br /> // Repost the read if necessary, reusing the same<br /> // receive buffer as before<br /> memset(&OverlapPlus->ol, 0, sizeof(OVERLAPPED));<br /> ret = WSARecv(<br /> OverlapPlus->s,<br /> &OverlapPlus->wbuf,<br /> 1,<br /> &OverlapPlus->dwBytes,<br /> &OverlapPlus->dwFlags,<br /> &OverlapPlus->ol,<br /> NULL);<br /> if (ret == SOCKET_ERROR)<br /> {<br /> if (WSAGetLastError() != WSA_IO_PENDING)<br /> {<br /> // Error<br /> }<br /> }<br /> break;<br /> case OP_WRITE:<br /> // Process the data sent, etc.<br /> break;<br /> } // switch<br /> } // while<br /> } // WorkerThread<br /> </p> <p>查看以上代码Q注意如果Overlapped操作立刻p|Q比如,q回SOCKET_ERROR或其他非WSA_IO_PENDING的错误)Q则没有M完成通知旉?x)被攑ֈ?strong>完成端口</strong>队列里。反之,则一定有相应的通知旉被放?strong>完成端口</strong>队列。更完善的关于Winsock?strong>完成端口</strong>机制Q可以参考MSDN的Microsoft PlatFormSDKQ那里有<strong>完成端口</strong>的例子。访?a >http://msdn.microsoft.com/library/techart/msdn_servrapp.htm</a>可以获得更多信息?/p> <p><strong>Linux?strong>EPoll</strong>模型<br /> </strong>Linux 2.6内核中提高网lI/O性能的新Ҏ(gu)-<strong>epoll</strong> I/O多\复用技术在比较多的TCP|络服务器中有用,x较多的用到select函数?br /> <br /> <strong>1、ؓ(f)什么select落后<br /> </strong>首先Q在Linux内核中,select所用到的FD_SET是有限的Q即内核中有个参数__FD_SETSIZE定义了每个FD_SET的句柄个敎ͼ在我用的2.6.15-25-386内核中,该值是1024Q搜索内核源代码得到Q?br /> include/linux/posix_types.h:#define __FD_SETSIZE         1024<br /> 也就是说Q如果想要同时检?025个句柄的可读状态是不可能用select实现的。或者同时检?025个句柄的可写状态也是不可能的。其ơ,内核中实现select是用轮询Ҏ(gu)Q即每次(g)都?x)遍历所有FD_SET中的句柄Q显Ӟselect函数执行旉与FD_SET中的句柄个数有一个比例关p,即select要检的句柄数越多就?x)越?gu)。当Ӟ在前文中我ƈ没有提及(qing)pollҎ(gu)Q事实上用select的朋友一定也试过pollQ我个h觉得select和poll大同异Q个人偏好于用select而已?/p> <p><strong>2、内怸提高I(y)/O性能的新Ҏ(gu)<strong>epoll</strong></strong><br /> <strong>epoll</strong>是什么?按照man手册的说法:(x)是ؓ(f)处理大批量句柄而作了改q的poll。要使用<strong>epoll</strong>只需要这三个pȝ调用Q?strong>epoll</strong>_create(2)Q?nbsp;<strong>epoll</strong>_ctl(2)Q?nbsp;<strong>epoll</strong>_wait(2)?br /> 当然Q这不是2.6内核才有的,它是?.5.44内核中被引进?<strong>epoll</strong>(4) is a new API introduced in Linux kernel 2.5.44)</p> <p>Linux2.6内核<strong>epoll</strong>介绍<br /> 先介l?本书《The Linux Networking Architecture--Design and Implementation of Network Protocols in the Linux Kernel》,?.4内核讲解Linux TCP/IP实现Q相当不?作ؓ(f)一个现实世界中的实玎ͼ很多时候你必须作很多权衡,q时候参考一个久l考验的系l更有实际意义。D个例?linux内核中sk_buffl构Zq求速度和安全,牺牲了部分内存,所以在发送TCP包的时候,无论应用层数据多?sk_buff最也?72的字?其实对于socket应用层程序来_(d)另外一本书《UNIX Network Programming Volume 1》意义更大一?2003q的时候,q本书出了最新的W?版本Q不q主要还是修订第2版本。其中第6章《I/O Multiplexing》是最重要的。Stevensl出了网lIO的基本模型。在q里最重要的莫q于select模型和Asynchronous I/O模型.从理Z_(d)AIOg是最高效的,你的IO操作可以立即q回Q然后等待os告诉你IO操作完成。但是一直以来,如何实现没有一个完的Ҏ(gu)。最著名的windows<strong>完成端口</strong>实现的AIO,实际上也是内部用U程池实现的|了Q最后的l果是IO有个U程池,你应用也需要一个线E池...... 很多文档其实已经指出了这带来的线Econtext-switch带来的代仗在linux q_上,关于|络AIO一直是改动最多的地方Q?.4的年代就有很多AIO内核patch,最著名的应该算是SGI那个。但是一直到2.6内核发布Q网l模块的AIO一直没有进入稳定内核版?大部分都是用用L(fng)E模拟方法,在用了NPTL的linux上面其实和windows?strong>完成端口</strong>基本上差不多??.6内核所支持的AIOҎ(gu)盘的AIO---支持io_submit(),io_getevents()以及(qing)对Direct IO的支?是l过VFSpȝbuffer直接写硬盘,对于服务器在内存^Ex上有相当帮??br /> 所以,剩下的select模型基本上就是我们在linux上面的唯一选择Q其实,如果加上no-block socket的配|,可以完成一??AIO的实玎ͼ只不q推动力在于你而不是os而已。不q传l的select/poll函数有着一些无法忍受的~点Q所以改q一直是2.4-2.5开发版本内核的dQ包?dev/pollQrealtime signal{等。最l,Davide Libenzi开发的<strong>epoll</strong>q入2.6内核成ؓ(f)正式的解x?br /> <strong><br /> 3?strong>epoll</strong>的优?/strong><br /> <1>支持一个进E打开大数目的socket描述W?FD)<br /> select 最不能忍受的是一个进E所打开的FD是有一定限制的Q由FD_SETSIZE讄Q默认值是2048。对于那些需要支持的上万q接数目的IM服务器来说显然太了。这时候你一是可以选择修改q个宏然后重新编译内核,不过资料也同时指样会(x)带来|络效率的下降,二是可以选择多进E的解决Ҏ(gu)(传统的ApacheҎ(gu))Q不q虽然linux上面创徏q程的代h较小Q但仍旧是不可忽视的Q加上进E间数据同步q比不上U程间同步的高效Q所以也不是一U完的Ҏ(gu)。不q?nbsp;<strong>epoll</strong>则没有这个限Ӟ它所支持的FD上限是最大可以打开文g的数目,q个数字一般远大于2048,举个例子,?GB内存的机器上大约?0万左叻I具体数目可以cat /proc/sys/fs/file-max察看,一般来说这个数目和pȝ内存关系很大?br /> <2>IO效率不随FD数目增加而线性下?br /> 传统的select/poll另一个致命弱点就是当你拥有一个很大的socket集合Q不q由于网lgӞM旉只有部分的socket?z跃"的,但是select/poll每次调用都会(x)U性扫描全部的集合Q导致效率呈现线性下降。但?strong>epoll</strong>不存在这个问题,它只?x)?z跃"的socketq行操作---q是因ؓ(f)在内核实C<strong>epoll</strong>是根据每个fd上面的callback函数实现的。那么,只有"z跃"的socket才会(x)d的去调用 callback函数Q其他idle状态socket则不?x),在这点上Q?strong>epoll</strong>实现了一??AIOQ因时候推动力在os内核。在一?benchmark中,如果所有的socket基本上都是活跃的---比如一个高速LAN环境Q?strong>epoll</strong>q不比select/poll有什么效率,相反Q如果过多?strong>epoll</strong>_ctl,效率相比q有E微的下降。但是一旦用idle connections模拟WAN环境,<strong>epoll</strong>的效率就q在select/poll之上了?br /> <3>使用mmap加速内怸用户I间的消息传递?br /> q点实际上涉?qing)?strong>epoll</strong>的具体实C。无论是select,pollq是<strong>epoll</strong>都需要内核把FD消息通知l用L(fng)_(d)如何避免不必要的内存拯很重要Q在q点上,<strong>epoll</strong>是通过内核于用L(fng)间mmap同一块内存实现的。而如果你x一样从2.5内核关?strong>epoll</strong>的话Q一定不?x)忘记手?mmapq一步的?br /> <4>内核微调<br /> q一点其实不?strong>epoll</strong>的优点了Q而是整个linuxq_的优炏V也怽可以怀疑linuxq_Q但是你无法回避linuxq_赋予你微调内核的能力。比如,内核TCP/IP协议栈用内存池理sk_buffl构Q那么可以在q行时期动态调整这个内存pool(skb_head_pool)的大?-- 通过echo XXXX>/proc/sys/net/core/hot_list_length完成。再比如listen函数的第2个参?TCP完成3ơ握手的数据包队列长?Q也可以Ҏ(gu)你^台内存大动态调整。更甚至在一个数据包面数目巨大但同时每个数据包本w大却很小的特D系l上试最新的NAPI|卡驱动架构?br /> 4?strong>epoll</strong>的工作模?br /> 令h高兴的是Q?.6内核?strong>epoll</strong>比其2.5开发版本的/dev/<strong>epoll</strong>z了许多Q所以,大部分情况下Q强大的东西往往是简单的。唯一有点ȝ?strong>epoll</strong>?U工作方?LT和ET?br /> LT(level triggered)是缺省的工作方式Qƈ且同时支持block和no-block socket.在这U做法中Q内核告诉你一个文件描q符是否qA了,然后你可以对q个qA的fdq行IO操作。如果你不作M操作Q内核还是会(x)l箋通知你的Q所以,q种模式~程出错误可能性要一炏V传l的select/poll都是q种模型的代表.<br /> ET (edge-triggered)是高速工作方式,只支持no-block socket。在q种模式下,当描q符从未qA变ؓ(f)qAӞ内核通过<strong>epoll</strong>告诉你。然后它?x)假设你知道文g描述W已l就l,q且不会(x)再ؓ(f)那个文g描述W发送更多的qA通知Q直C做了某些操作D那个文g描述W不再ؓ(f)qA状态了(比如Q你在发送,接收或者接收请求,或者发送接收的数据于一定量时导致了一个EWOULDBLOCK 错误Q。但是请注意Q如果一直不对这个fd作IO操作(从而导致它再次变成未就l?Q内怸?x)发送更多的通知(only once),不过在TCP协议中,ET模式的加速效用仍需要更多的benchmark认?br /> <strong>epoll</strong>只有<strong>epoll</strong>_create,<strong>epoll</strong>_ctl,<strong>epoll</strong>_wait 3个系l调用,具体用法请参?a >http://www.xmailserver.org/linux-patches/nio-improve.html</a> Q在<a >http://www.kegel.com/rn/</a>也有一个完整的例子Q大家一看就知道如何使用?br /> Leader/follower模式U程pool实现Q以?qing)?strong>epoll</strong>的配合?br /> <br /> <strong>5?nbsp;<strong>epoll</strong>的用方?/strong><br />     首先通过create_<strong>epoll</strong>(int maxfds)来创Z?strong>epoll</strong>的句柄,其中maxfdsZ<strong>epoll</strong>所支持的最大句柄数。这个函C(x)q回一个新?strong>epoll</strong>句柄Q之后的所有操作将通过q个句柄来进行操作。在用完之后Q记得用close()来关闭这个创建出来的<strong>epoll</strong>句柄?之后在你的网l主循环里面Q每一帧的调用<strong>epoll</strong>_wait(int epfd, <strong>epoll</strong>_event events, int max events, int timeout)来查询所有的|络接口Q看哪一个可以读Q哪一个可以写了。基本的语法为:(x) <br /> nfds = <strong>epoll</strong>_wait(kdpfd, events, maxevents, -1); <br /> 其中kdpfd为用<strong>epoll</strong>_create创徏之后的句柄,events是一?strong>epoll</strong>_event*的指针,?strong>epoll</strong>_waitq个函数操作成功之后Q?strong>epoll</strong>_events里面储存所有的d事g。max_events是当前需要监听的所有socket句柄数。最后一个timeout?strong>epoll</strong>_wait的超Ӟ?的时候表C马上返回,?1的时候表CZ直等下去Q直到有事g范围Qؓ(f)L正整数的时候表C等q么长的旉Q如果一直没有事Ӟ则范围。一般如果网l主循环是单独的U程的话Q可以用-1来等Q这样可以保证一些效率,如果是和主逻辑在同一个线E的话,则可以用0来保证主循环的效率?/p> <p><strong>epoll</strong>_wait范围之后应该是一个@环,遍利所有的事gQ?nbsp;<br /> for(n = 0; n < nfds; ++n) { <br />                 if(events[n].data.fd == listener) { //如果是主socket的事件的话,则表C有新连接进入了Q进行新q接的处理?nbsp;<br />                     client = accept(listener, (struct sockaddr *) &local, <br />                                     &addrlen); <br />                     if(client < 0){ <br />                         perror("accept"); <br />                         continue; <br />                     } <br />                     setnonblocking(client); // 新q接|于非阻塞模?nbsp;<br />                     ev.events = EPOLLIN | EPOLLET; // q且新q接也加?strong>EPOLL</strong>的监听队列?nbsp;<br /> 注意Q这里的参数EPOLLIN | EPOLLETq没有设|对写socket的监听,如果有写操作的话Q这个时?strong>epoll</strong>是不?x)返回事件的Q如果要对写操作也监听的话,应该是EPOLLIN | EPOLLOUT | EPOLLET <br />                     ev.data.fd = client; <br />                     if (<strong>epoll</strong>_ctl(kdpfd, <strong>EPOLL</strong>_CTL_ADD, client, &ev) < 0) { <br /> // 讄好event之后Q将q个新的event通过<strong>epoll</strong>_ctl加入?strong>epoll</strong>的监听队列里面,q里?strong>EPOLL</strong>_CTL_ADD来加一个新?strong>epoll</strong>事gQ通过<strong>EPOLL</strong>_CTL_DEL来减一?strong>epoll</strong>事gQ通过<strong>EPOLL</strong>_CTL_MOD来改变一个事件的监听方式?nbsp;<br />                         fprintf(stderr, "<strong>epoll</strong> set insertion error: fd=%d0, <br />                                 client); <br />                         return -1; <br />                     } <br />                 } <br />                 else // 如果不是主socket的事件的话,则代表是一个用户socket的事Ӟ则来处理q个用户socket的事情,比如说read(fd,xxx)之类的,或者一些其他的处理?nbsp;<br />                     do_use_fd(events[n].data.fd); <br /> }</p> <p>对,<strong>epoll</strong>的操作就q么单,d不过4个APIQ?strong>epoll</strong>_create, <strong>epoll</strong>_ctl, <strong>epoll</strong>_wait和close?nbsp;<br /> 如果(zhn)对<strong>epoll</strong>的效率还不太了解Q请参考我之前关于|络游戏的网l编E等相关的文章?/p> <p><br /> 以前公司的服务器都是使用HTTPq接Q但是这L(fng)话,在手机目前的|络情况下不但显得速度较慢Q而且不稳定。因此大家一致同意用SOCKET来进行连接。虽然用SOCKET之后Q对于用L(fng)费用可能?x)增?׃是用了CMNET而非CMWAP)Q但是,U着用户体验至上的原则,怿大家q是能够接受?希望那些玩家月末收到帐单不后能够保持克制...)?br /> q次的服务器设计中,最重要的一个突_(d)是用了<strong>EPOLL</strong>模型Q虽然对之也是一知半解,但是既然在各大PC|游中已l经q了如此严酷的考验Q相信他不会(x)让我们失望,使用后的l果Q确实也是表现相当不错。在q里Q我q是主要大致介绍一下这个模型的l构?br /> 6、Linux?strong>EPOll</strong>~程实例<br /> <strong>EPOLL</strong>模型g只有一U格式,所以大家只要参考我下面的代码,p够对<strong>EPOLL</strong>有所了解了,代码的解释都已经在注释中Q?/p> <p>while (TRUE)<br /> {<br /> int nfds = <strong>epoll</strong>_wait (m_<strong>epoll</strong>_fd, m_events, MAX_EVENTS, <strong>EPOLL</strong>_TIME_OUT);//{待<strong>EPOLL</strong>旉的发生,相当于监听,至于相关的端口,需要在初始?strong>EPOLL</strong>的时候绑定?br /> if (nfds <= 0)<br /> continue;<br /> m_bOnTimeChecking = FALSE;<br /> G_CurTime = time(NULL);<br /> for (int i=0; i<br /> {<br /> try<br /> {<br /> if (m_events[i].data.fd == m_listen_http_fd)//如果新监到一个HTTP用户q接到绑定的HTTP端口Q徏立新的连接。由于我们新采用了SOCKETq接Q所以基本没用?br /> {<br /> OnAcceptHttpEpoll ();<br /> }<br /> else if (m_events[i].data.fd == m_listen_sock_fd)//如果新监到一个SOCKET用户q接Cl定的SOCKET端口Q徏立新的连接?br /> {<br /> OnAcceptSockEpoll ();<br /> }<br /> else if (m_events[i].events & EPOLLIN)//如果是已l连接的用户Qƈ且收到数据,那么q行d?br /> {<br /> OnReadEpoll (i);<br /> }</p> <p>OnWriteEpoll (i);//查看当前的活动连接是否有需要写出的数据?br /> }<br /> catch (int)<br /> {<br /> PRINTF ("CATCH捕获错误\n");<br /> continue;<br /> }<br /> }<br /> m_bOnTimeChecking = TRUE;<br /> OnTimer ();//q行一些定时的操作Q主要就是删除一些短U用L(fng)?br /> }<br /> 其实<strong>EPOLL</strong>的精华,也就是上q的几段短短的代码,看来时代真的不同了,以前如何接受大量用户q接的问题,现在却被如此L的搞定,真是让h不得不感叹,对哪?/p> <p><br /> <strong>ȝ<br /> </strong>Windows<strong>完成端口</strong>与Linux <strong>epoll</strong>技术方案是q?个^C实现异步IO和设计开发一个大定wQ具可扩展性的winsockE序指服务程序的很好的选择Q本文对q?中技术的实现原理和实际的使用Ҏ(gu)做了一个详l的介绍?/p> @import url(http://www.shnenglu.com/CuteSoft_Client/CuteEditor/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);<img src ="http://www.shnenglu.com/singohgod/aggbug/152376.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/singohgod/" target="_blank">大宝天天?/a> 2011-08-03 17:43 <a href="http://www.shnenglu.com/singohgod/archive/2011/08/03/152376.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <p>лǵվܻԴȤ</p> <a href="http://www.shnenglu.com/" title="精品视频久久久久">精品视频久久久久</a> <div class="friend-links"> </div> </div> </footer> <a href="http://www.gzkyzc.com.cn" target="_blank">69Ʒþþþ9999APGF</a>| <a href="http://www.sxjax.cn" target="_blank">˾ھƷþþþ</a>| <a href="http://www.pcsaver.cn" target="_blank">þþþþavѿƬ</a>| <a href="http://www.ht228.cn" target="_blank">ƷþþþþþĻ </a>| <a href="http://www.173xp.cn" target="_blank">þۺɫ99žak</a>| <a href="http://www.asox.cn" target="_blank">ŷ龫Ʒþþþþþþžž</a>| <a href="http://www.xiewanliang.cn" target="_blank">ĻۺϾþ2</a>| <a href="http://www.bjyjyyy.cn" target="_blank">Ʒþþþþҹҹ</a>| <a href="http://www.qingjian8.cn" target="_blank">һŮȫƾþƬ </a>| <a href="http://www.pedl.cn" target="_blank">˾þں2019</a>| <a href="http://www.2pt.com.cn" target="_blank">þþþޱٸ</a>| <a href="http://www.eastmark.cn" target="_blank">޾ƷþþþþðĦ</a>| <a href="http://www.liuzirui597.cn" target="_blank">ƷþþƷ</a>| <a href="http://www.todouba.cn" target="_blank">þþƷƷ޾Ʒ</a>| <a href="http://www.hhh328.cn" target="_blank">Ʒþһ</a>| <a href="http://www.deartaobao.cn" target="_blank">ھƷþþþþþþõӰ </a>| <a href="http://www.52chaoyang.cn" target="_blank">޹Ʒþþþþ</a>| <a href="http://www.tmsystem888.cn" target="_blank">þþþþҹƷ</a>| <a href="http://www.fvxg.cn" target="_blank">99þۺϾƷվ</a>| <a href="http://www.cyjeans.com.cn" target="_blank">yy6080þ</a>| <a href="http://www.dgltjsh.cn" target="_blank">þþþAVרɫ</a>| <a href="http://www.iz.sd.cn" target="_blank">99þþƷ鶹</a>| <a href="http://www.led-dc.cn" target="_blank">ĻѾþ</a>| <a href="http://www.quheitou.net.cn" target="_blank">Ůͬþ</a>| <a href="http://www.lstweb.cn" target="_blank">þþþֻоƷ</a>| <a href="http://www.qwoj.cn" target="_blank">˾Ʒһþ</a>| <a href="http://www.ccum.cn" target="_blank">㽶þþƷ</a>| <a href="http://www.054q.cn" target="_blank">þþƷAV͵</a>| <a href="http://www.nxol.net.cn" target="_blank">޹Ʒ۲ӰԺþ</a>| <a href="http://www.dlucai.cn" target="_blank">þ99þëƬһ</a>| <a href="http://www.3344pltn.cn" target="_blank">99þþƷһ</a>| <a href="http://www.laowang66.com.cn" target="_blank">Ļһþ</a>| <a href="http://www.sdmtsk.cn" target="_blank">һþƵ</a>| <a href="http://www.fjqcbks.cn" target="_blank">Ժձһձþ </a>| <a href="http://www.jsmyy.cn" target="_blank">޾Ʒһۺ99þ</a>| <a href="http://www.jn249.cn" target="_blank">þþƷh</a>| <a href="http://www.by2043.cn" target="_blank">ҹþӰԺ</a>| <a href="http://www.ip-domain.com.cn" target="_blank">ƷŮþþþþ2018</a>| <a href="http://www.news222.cn" target="_blank">ٸþĻһ</a>| <a href="http://www.ajemy.cn" target="_blank">ĻƷþþþ</a>| <a href="http://www.pbxdt.com.cn" target="_blank">ɫۺϾþ88ɫۺ </a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>