﻿<?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++博客-Just enjoy programming-随笔分类-网络编程</title><link>http://www.cppblog.com/tankzhouqiang/category/16141.html</link><description /><language>zh-cn</language><lastBuildDate>Sun, 07 Aug 2011 15:08:24 GMT</lastBuildDate><pubDate>Sun, 07 Aug 2011 15:08:24 GMT</pubDate><ttl>60</ttl><item><title>linux RPC  测试（转载）</title><link>http://www.cppblog.com/tankzhouqiang/archive/2011/08/07/152718.html</link><dc:creator>周强</dc:creator><author>周强</author><pubDate>Sun, 07 Aug 2011 08:44:00 GMT</pubDate><guid>http://www.cppblog.com/tankzhouqiang/archive/2011/08/07/152718.html</guid><wfw:comment>http://www.cppblog.com/tankzhouqiang/comments/152718.html</wfw:comment><comments>http://www.cppblog.com/tankzhouqiang/archive/2011/08/07/152718.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tankzhouqiang/comments/commentRss/152718.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tankzhouqiang/services/trackbacks/152718.html</trackback:ping><description><![CDATA[<div>转自:<div>http://www.justwinit.cn/post/3960/</div><br /><br />RPC是glibc提供的函数参数/返回值封装服务, 并将封装结果通过网络传到服务器.<br />RPC服务端首先要启动portmapper服务.<br />测试一个简单的RPC传输示例, 先定义一个模板文件test.x<br /><br /><div>program TESTPROG{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;version VERSION{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int int_echo(int)=1;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int get_str_len(string)=2;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int add ( int, int ) = 3;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}=1;<br />}=30000;</div>内含3个函数, 注意其中一个有2个参数.<br />然后可以用rpcgen生成一个Makefile:<br /><br /><div>rpcgen -a -N test.x</div><br />这会生成Makefile, 客户端和服务端的程序, 和函数示例.<br />我们手工修改一下Makefile<br /><br /><div># This is a template Makefile generated by rpcgen<br /># Parameters<br />CLIENT = test_client<br />SERVER = test_server<br />SOURCES_CLNT.c =<br />SOURCES_CLNT.h =<br />SOURCES_SVC.c =<br />SOURCES_SVC.h =<br />SOURCES.x = test.x<br />TARGETS_SVC.c = test_svc.c test_server.c test_xdr.c<br />TARGETS_CLNT.c = test_clnt.c test_client.c test_xdr.c<br />TARGETS = test.h test_xdr.c test_clnt.c test_svc.c<br />OBJECTS_CLNT = $(SOURCES_CLNT.c:%.c=%.o) $(TARGETS_CLNT.c:%.c=%.o)<br />OBJECTS_SVC = $(SOURCES_SVC.c:%.c=%.o) $(TARGETS_SVC.c:%.c=%.o)<br /># Compiler flags<br />CFLAGS += -g -pipe<br />LDLIBS += -lnsl<br />RPCGENFLAGS = -N<br /># Targets<br />all : $(CLIENT) $(SERVER)<br />$(TARGETS) : $(SOURCES.x)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rpcgen $(RPCGENFLAGS) $(SOURCES.x)<br />$(OBJECTS_CLNT) : $(SOURCES_CLNT.c) $(SOURCES_CLNT.h) $(TARGETS_CLNT.c)<br />$(OBJECTS_SVC) : $(SOURCES_SVC.c) $(SOURCES_SVC.h) $(TARGETS_SVC.c)<br />$(CLIENT) : $(OBJECTS_CLNT)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$(LINK.c) -o $(CLIENT) $(OBJECTS_CLNT) $(LDLIBS)<br />$(SERVER) : $(OBJECTS_SVC)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$(LINK.c) -o $(SERVER) $(OBJECTS_SVC) $(LDLIBS)<br /> clean:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $(RM) core $(TARGETS) $(OBJECTS_CLNT) $(OBJECTS_SVC) $(CLIENT) $(SERVER)</div><br />修改test_server.c服务端的处理函数, 提供3种服务:<br /><br /><div>/*<br /> * This is sample code generated by rpcgen.<br /> * These are only templates and you can use them<br /> * as a guideline for developing your own functions.<br /> */<br />#include "test.h"<br />int *<br />int_echo_1_svc(int arg1,&nbsp;&nbsp;struct svc_req *rqstp)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;static int&nbsp;&nbsp;result;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//echo.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result=arg1;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("[RPC1] source=%d, echo=%d\n", arg1, result);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return &amp;result;<br />}<br />int *<br />get_str_len_1_svc(char *arg1,&nbsp;&nbsp;struct svc_req *rqstp)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;static int&nbsp;&nbsp;result;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//get strlen.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result=strlen(arg1);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("[PRC2] str=%s, len=%d\n", arg1, result);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return &amp;result;<br />}<br />int *<br />add_1_svc(int arg1, int arg2,&nbsp;&nbsp;struct svc_req *rqstp)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;static int&nbsp;&nbsp;result;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result=arg1+arg2;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("[RPC3] %d+%d=%d\n", arg1, arg2, result);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return &amp;result;<br />}</div><br />客户端test_client.c, 调用这三种服务:<br /><br /><div>/*<br /> * This is sample code generated by rpcgen.<br /> * These are only templates and you can use them<br /> * as a guideline for developing your own functions.<br /> */<br />#include "test.h"<br />void<br />testprog_1(char *host)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CLIENT *clnt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;*result_1;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int int_echo_1_arg1=55;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;*result_2;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;char *get_str_len_1_arg1="Hello, world";<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;*result_3;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int add_1_arg1=10;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int add_1_arg2=20;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;clnt = clnt_create (host, TESTPROG, VERSION, "udp");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (clnt == NULL) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;clnt_pcreateerror (host);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit (1);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result_1 = int_echo_1(int_echo_1_arg1, clnt);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (result_1 == (int *) NULL) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;clnt_perror (clnt, "call failed");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("[PRC1] echo %d, source %d\n", *result_1,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int_echo_1_arg1);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result_2 = get_str_len_1(get_str_len_1_arg1, clnt);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (result_2 == (int *) NULL) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;clnt_perror (clnt, "call failed");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("[RPC2] return %d, should %d\n", *result_2,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strlen(get_str_len_1_arg1));<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result_3 = add_1(add_1_arg1, add_1_arg2, clnt);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (result_3 == (int *) NULL) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;clnt_perror (clnt, "call failed");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("[PRC3] %d+%d=%d\n", add_1_arg1, add_1_arg2,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*result_3);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;clnt_destroy (clnt);<br />}</div>OK, 可以调用make了.<br />生成可执行程序test_server和test_client.<br />我们启动./test_server, 用rpcinfo看看:<br /><br /><div>$rpcinfo -p 127.0.0.1<br />program vers proto port<br />100000 2 tcp 111 portmapper<br />30000 1 udp 36307<br />30000 1 tcp 34883<br />Bingo! 启动成功.</div><br />再开个终端, 尝试一下调用.<br /><div><br />./test_client 127.0.0.1<br />[PRC1] echo 55, source 55<br />[RPC2] return 12, should 12<br />[PRC3] 10+20=30</div><br />正是我们期望的.<br /><br />Add By：Jackxiang<br /><div>make -f Makefile.test</div></div><img src ="http://www.cppblog.com/tankzhouqiang/aggbug/152718.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tankzhouqiang/" target="_blank">周强</a> 2011-08-07 16:44 <a href="http://www.cppblog.com/tankzhouqiang/archive/2011/08/07/152718.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>客户/服务器程序设计范式</title><link>http://www.cppblog.com/tankzhouqiang/archive/2011/04/04/143413.html</link><dc:creator>周强</dc:creator><author>周强</author><pubDate>Mon, 04 Apr 2011 11:38:00 GMT</pubDate><guid>http://www.cppblog.com/tankzhouqiang/archive/2011/04/04/143413.html</guid><wfw:comment>http://www.cppblog.com/tankzhouqiang/comments/143413.html</wfw:comment><comments>http://www.cppblog.com/tankzhouqiang/archive/2011/04/04/143413.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tankzhouqiang/comments/commentRss/143413.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tankzhouqiang/services/trackbacks/143413.html</trackback:ping><description><![CDATA[参考&nbsp; unix网络编程<br>客户/服务器程序设计范式有<br>（1）迭代服务器（无进程控制)<br>（2）并发服务器，每个客户请求fork 一个子进程<br>（3）预先派生子进程，每个子进程无保护地调用accept<br>（4）预先派生子进程，使用文件上锁保护accept<br>（5）预先派生子进程，使用线程互斥锁保护accept（共享内存)<br>（6）预先派生子进程，父进程向子进程传递套接口描述字<br>（7）并发服务器，每个客户请求创建一个线程<br>（8）预先创建线程服务器，使用互斥锁上锁保护accept<br>（9）预先创建线程服务器，由主线程调用accept.<br><br>测试用例 客户创建5个进程，每个发起500个连接，每个连接写四个字节数据<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 总的用户时间（秒） &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 总的系统时间（秒）<br>（1） &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0.012&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0.16001<br>（2） &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; 0.008 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0.256016<br>（3） &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; 0.016 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0.268016<br>（4） &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; 0.020001 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0.380023<br>（5） &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; 0.012 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0.308019<br>（6） &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; 0.068003 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0.464029<br>（7） &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; 0.024001 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0.224014<br>（8） &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; 0.012 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0.280017<br>（9） &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; 0.0160001 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0.268016 <br><br> <img src ="http://www.cppblog.com/tankzhouqiang/aggbug/143413.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tankzhouqiang/" target="_blank">周强</a> 2011-04-04 19:38 <a href="http://www.cppblog.com/tankzhouqiang/archive/2011/04/04/143413.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux下飞鸽传书实现</title><link>http://www.cppblog.com/tankzhouqiang/archive/2011/03/15/141915.html</link><dc:creator>周强</dc:creator><author>周强</author><pubDate>Tue, 15 Mar 2011 13:57:00 GMT</pubDate><guid>http://www.cppblog.com/tankzhouqiang/archive/2011/03/15/141915.html</guid><wfw:comment>http://www.cppblog.com/tankzhouqiang/comments/141915.html</wfw:comment><comments>http://www.cppblog.com/tankzhouqiang/archive/2011/03/15/141915.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tankzhouqiang/comments/commentRss/141915.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tankzhouqiang/services/trackbacks/141915.html</trackback:ping><description><![CDATA[<!--[if !mso]>
<style>
v\:* {behavior:url(#default#VML);}
o\:* {behavior:url(#default#VML);}
w\:* {behavior:url(#default#VML);}
.shape {behavior:url(#default#VML);}
</style>
<![endif]--><!--[if gte mso 9]><xml>
<w:worddocument>
<w:view>Normal</w:view>
<w:zoom>0</w:zoom>
<w:trackmoves/>
<w:trackformatting/>
<w:punctuationkerning/>
<w:drawinggridverticalspacing>7.8 磅</w:drawinggridverticalspacing>
<w:displayhorizontaldrawinggridevery>0</w:displayhorizontaldrawinggridevery>
<w:displayverticaldrawinggridevery>2</w:displayverticaldrawinggridevery>
<w:validateagainstschemas/>
<w:saveifxmlinvalid>false</w:saveifxmlinvalid>
<w:ignoremixedcontent>false</w:ignoremixedcontent>
<w:alwaysshowplaceholdertext>false</w:alwaysshowplaceholdertext>
<w:donotpromoteqf/>
<w:lidthemeother>EN-US</w:lidthemeother>
<w:lidthemeasian>ZH-CN</w:lidthemeasian>
<w:lidthemecomplexscript>X-NONE</w:lidthemecomplexscript>
<w:compatibility>
<w:spaceforul/>
<w:balancesinglebytedoublebytewidth/>
<w:donotleavebackslashalone/>
<w:ultrailspace/>
<w:donotexpandshiftreturn/>
<w:adjustlineheightintable/>
<w:breakwrappedtables/>
<w:snaptogridincell/>
<w:wraptextwithpunct/>
<w:useasianbreakrules/>
<w:dontgrowautofit/>
<w:splitpgbreakandparamark/>
<w:dontvertaligncellwithsp/>
<w:dontbreakconstrainedforcedtables/>
<w:dontvertalignintxbx/>
<w:word11kerningpairs/>
<w:cachedcolbalance/>
<w:usefelayout/>
</w:compatibility>
<w:browserlevel>MicrosoftInternetExplorer4</w:browserlevel>
<m:mathpr>
<m:mathfont m:val="Cambria Math"/>
<m:brkbin m:val="before"/>
<m:brkbinsub m:val="&#45;-"/>
<m:smallfrac m:val="off"/>
<m:dispdef/>
<m:lmargin m:val="0"/>
<m:rmargin m:val="0"/>
<m:defjc m:val="centerGroup"/>
<m:wrapindent m:val="1440"/>
<m:intlim m:val="subSup"/>
<m:narylim m:val="undOvr"/>
</m:mathpr></w:worddocument>
</xml><![endif]--><!--[if gte mso 9]><xml>
<w:latentstyles deflockedstate="false" defunhidewhenused="true"
DefSemiHidden="true" defqformat="false" defpriority="99"
LatentStyleCount="267">
<w:lsdexception locked="false" priority="0" semihidden="false"
UnhideWhenUsed="false" qformat="true" name="Normal"/>
<w:lsdexception locked="false" priority="9" semihidden="false"
UnhideWhenUsed="false" qformat="true" name="heading 1"/>
<w:lsdexception locked="false" priority="9" qformat="true" name="heading 2"/>
<w:lsdexception locked="false" priority="9" qformat="true" name="heading 3"/>
<w:lsdexception locked="false" priority="9" qformat="true" name="heading 4"/>
<w:lsdexception locked="false" priority="9" qformat="true" name="heading 5"/>
<w:lsdexception locked="false" priority="9" qformat="true" name="heading 6"/>
<w:lsdexception locked="false" priority="9" qformat="true" name="heading 7"/>
<w:lsdexception locked="false" priority="9" qformat="true" name="heading 8"/>
<w:lsdexception locked="false" priority="9" qformat="true" name="heading 9"/>
<w:lsdexception locked="false" priority="39" name="toc 1"/>
<w:lsdexception locked="false" priority="39" name="toc 2"/>
<w:lsdexception locked="false" priority="39" name="toc 3"/>
<w:lsdexception locked="false" priority="39" name="toc 4"/>
<w:lsdexception locked="false" priority="39" name="toc 5"/>
<w:lsdexception locked="false" priority="39" name="toc 6"/>
<w:lsdexception locked="false" priority="39" name="toc 7"/>
<w:lsdexception locked="false" priority="39" name="toc 8"/>
<w:lsdexception locked="false" priority="39" name="toc 9"/>
<w:lsdexception locked="false" priority="35" qformat="true" name="caption"/>
<w:lsdexception locked="false" priority="10" semihidden="false"
UnhideWhenUsed="false" qformat="true" name="Title"/>
<w:lsdexception locked="false" priority="1" name="Default Paragraph Font"/>
<w:lsdexception locked="false" priority="11" semihidden="false"
UnhideWhenUsed="false" qformat="true" name="Subtitle"/>
<w:lsdexception locked="false" priority="22" semihidden="false"
UnhideWhenUsed="false" qformat="true" name="Strong"/>
<w:lsdexception locked="false" priority="20" semihidden="false"
UnhideWhenUsed="false" qformat="true" name="Emphasis"/>
<w:lsdexception locked="false" priority="59" semihidden="false"
UnhideWhenUsed="false" name="Table Grid"/>
<w:lsdexception locked="false" unhidewhenused="false" name="Placeholder Text"/>
<w:lsdexception locked="false" priority="1" semihidden="false"
UnhideWhenUsed="false" qformat="true" name="No Spacing"/>
<w:lsdexception locked="false" priority="60" semihidden="false"
UnhideWhenUsed="false" name="Light Shading"/>
<w:lsdexception locked="false" priority="61" semihidden="false"
UnhideWhenUsed="false" name="Light List"/>
<w:lsdexception locked="false" priority="62" semihidden="false"
UnhideWhenUsed="false" name="Light Grid"/>
<w:lsdexception locked="false" priority="63" semihidden="false"
UnhideWhenUsed="false" name="Medium Shading 1"/>
<w:lsdexception locked="false" priority="64" semihidden="false"
UnhideWhenUsed="false" name="Medium Shading 2"/>
<w:lsdexception locked="false" priority="65" semihidden="false"
UnhideWhenUsed="false" name="Medium List 1"/>
<w:lsdexception locked="false" priority="66" semihidden="false"
UnhideWhenUsed="false" name="Medium List 2"/>
<w:lsdexception locked="false" priority="67" semihidden="false"
UnhideWhenUsed="false" name="Medium Grid 1"/>
<w:lsdexception locked="false" priority="68" semihidden="false"
UnhideWhenUsed="false" name="Medium Grid 2"/>
<w:lsdexception locked="false" priority="69" semihidden="false"
UnhideWhenUsed="false" name="Medium Grid 3"/>
<w:lsdexception locked="false" priority="70" semihidden="false"
UnhideWhenUsed="false" name="Dark List"/>
<w:lsdexception locked="false" priority="71" semihidden="false"
UnhideWhenUsed="false" name="Colorful Shading"/>
<w:lsdexception locked="false" priority="72" semihidden="false"
UnhideWhenUsed="false" name="Colorful List"/>
<w:lsdexception locked="false" priority="73" semihidden="false"
UnhideWhenUsed="false" name="Colorful Grid"/>
<w:lsdexception locked="false" priority="60" semihidden="false"
UnhideWhenUsed="false" name="Light Shading Accent 1"/>
<w:lsdexception locked="false" priority="61" semihidden="false"
UnhideWhenUsed="false" name="Light List Accent 1"/>
<w:lsdexception locked="false" priority="62" semihidden="false"
UnhideWhenUsed="false" name="Light Grid Accent 1"/>
<w:lsdexception locked="false" priority="63" semihidden="false"
UnhideWhenUsed="false" name="Medium Shading 1 Accent 1"/>
<w:lsdexception locked="false" priority="64" semihidden="false"
UnhideWhenUsed="false" name="Medium Shading 2 Accent 1"/>
<w:lsdexception locked="false" priority="65" semihidden="false"
UnhideWhenUsed="false" name="Medium List 1 Accent 1"/>
<w:lsdexception locked="false" unhidewhenused="false" name="Revision"/>
<w:lsdexception locked="false" priority="34" semihidden="false"
UnhideWhenUsed="false" qformat="true" name="List Paragraph"/>
<w:lsdexception locked="false" priority="29" semihidden="false"
UnhideWhenUsed="false" qformat="true" name="Quote"/>
<w:lsdexception locked="false" priority="30" semihidden="false"
UnhideWhenUsed="false" qformat="true" name="Intense Quote"/>
<w:lsdexception locked="false" priority="66" semihidden="false"
UnhideWhenUsed="false" name="Medium List 2 Accent 1"/>
<w:lsdexception locked="false" priority="67" semihidden="false"
UnhideWhenUsed="false" name="Medium Grid 1 Accent 1"/>
<w:lsdexception locked="false" priority="68" semihidden="false"
UnhideWhenUsed="false" name="Medium Grid 2 Accent 1"/>
<w:lsdexception locked="false" priority="69" semihidden="false"
UnhideWhenUsed="false" name="Medium Grid 3 Accent 1"/>
<w:lsdexception locked="false" priority="70" semihidden="false"
UnhideWhenUsed="false" name="Dark List Accent 1"/>
<w:lsdexception locked="false" priority="71" semihidden="false"
UnhideWhenUsed="false" name="Colorful Shading Accent 1"/>
<w:lsdexception locked="false" priority="72" semihidden="false"
UnhideWhenUsed="false" name="Colorful List Accent 1"/>
<w:lsdexception locked="false" priority="73" semihidden="false"
UnhideWhenUsed="false" name="Colorful Grid Accent 1"/>
<w:lsdexception locked="false" priority="60" semihidden="false"
UnhideWhenUsed="false" name="Light Shading Accent 2"/>
<w:lsdexception locked="false" priority="61" semihidden="false"
UnhideWhenUsed="false" name="Light List Accent 2"/>
<w:lsdexception locked="false" priority="62" semihidden="false"
UnhideWhenUsed="false" name="Light Grid Accent 2"/>
<w:lsdexception locked="false" priority="63" semihidden="false"
UnhideWhenUsed="false" name="Medium Shading 1 Accent 2"/>
<w:lsdexception locked="false" priority="64" semihidden="false"
UnhideWhenUsed="false" name="Medium Shading 2 Accent 2"/>
<w:lsdexception locked="false" priority="65" semihidden="false"
UnhideWhenUsed="false" name="Medium List 1 Accent 2"/>
<w:lsdexception locked="false" priority="66" semihidden="false"
UnhideWhenUsed="false" name="Medium List 2 Accent 2"/>
<w:lsdexception locked="false" priority="67" semihidden="false"
UnhideWhenUsed="false" name="Medium Grid 1 Accent 2"/>
<w:lsdexception locked="false" priority="68" semihidden="false"
UnhideWhenUsed="false" name="Medium Grid 2 Accent 2"/>
<w:lsdexception locked="false" priority="69" semihidden="false"
UnhideWhenUsed="false" name="Medium Grid 3 Accent 2"/>
<w:lsdexception locked="false" priority="70" semihidden="false"
UnhideWhenUsed="false" name="Dark List Accent 2"/>
<w:lsdexception locked="false" priority="71" semihidden="false"
UnhideWhenUsed="false" name="Colorful Shading Accent 2"/>
<w:lsdexception locked="false" priority="72" semihidden="false"
UnhideWhenUsed="false" name="Colorful List Accent 2"/>
<w:lsdexception locked="false" priority="73" semihidden="false"
UnhideWhenUsed="false" name="Colorful Grid Accent 2"/>
<w:lsdexception locked="false" priority="60" semihidden="false"
UnhideWhenUsed="false" name="Light Shading Accent 3"/>
<w:lsdexception locked="false" priority="61" semihidden="false"
UnhideWhenUsed="false" name="Light List Accent 3"/>
<w:lsdexception locked="false" priority="62" semihidden="false"
UnhideWhenUsed="false" name="Light Grid Accent 3"/>
<w:lsdexception locked="false" priority="63" semihidden="false"
UnhideWhenUsed="false" name="Medium Shading 1 Accent 3"/>
<w:lsdexception locked="false" priority="64" semihidden="false"
UnhideWhenUsed="false" name="Medium Shading 2 Accent 3"/>
<w:lsdexception locked="false" priority="65" semihidden="false"
UnhideWhenUsed="false" name="Medium List 1 Accent 3"/>
<w:lsdexception locked="false" priority="66" semihidden="false"
UnhideWhenUsed="false" name="Medium List 2 Accent 3"/>
<w:lsdexception locked="false" priority="67" semihidden="false"
UnhideWhenUsed="false" name="Medium Grid 1 Accent 3"/>
<w:lsdexception locked="false" priority="68" semihidden="false"
UnhideWhenUsed="false" name="Medium Grid 2 Accent 3"/>
<w:lsdexception locked="false" priority="69" semihidden="false"
UnhideWhenUsed="false" name="Medium Grid 3 Accent 3"/>
<w:lsdexception locked="false" priority="70" semihidden="false"
UnhideWhenUsed="false" name="Dark List Accent 3"/>
<w:lsdexception locked="false" priority="71" semihidden="false"
UnhideWhenUsed="false" name="Colorful Shading Accent 3"/>
<w:lsdexception locked="false" priority="72" semihidden="false"
UnhideWhenUsed="false" name="Colorful List Accent 3"/>
<w:lsdexception locked="false" priority="73" semihidden="false"
UnhideWhenUsed="false" name="Colorful Grid Accent 3"/>
<w:lsdexception locked="false" priority="60" semihidden="false"
UnhideWhenUsed="false" name="Light Shading Accent 4"/>
<w:lsdexception locked="false" priority="61" semihidden="false"
UnhideWhenUsed="false" name="Light List Accent 4"/>
<w:lsdexception locked="false" priority="62" semihidden="false"
UnhideWhenUsed="false" name="Light Grid Accent 4"/>
<w:lsdexception locked="false" priority="63" semihidden="false"
UnhideWhenUsed="false" name="Medium Shading 1 Accent 4"/>
<w:lsdexception locked="false" priority="64" semihidden="false"
UnhideWhenUsed="false" name="Medium Shading 2 Accent 4"/>
<w:lsdexception locked="false" priority="65" semihidden="false"
UnhideWhenUsed="false" name="Medium List 1 Accent 4"/>
<w:lsdexception locked="false" priority="66" semihidden="false"
UnhideWhenUsed="false" name="Medium List 2 Accent 4"/>
<w:lsdexception locked="false" priority="67" semihidden="false"
UnhideWhenUsed="false" name="Medium Grid 1 Accent 4"/>
<w:lsdexception locked="false" priority="68" semihidden="false"
UnhideWhenUsed="false" name="Medium Grid 2 Accent 4"/>
<w:lsdexception locked="false" priority="69" semihidden="false"
UnhideWhenUsed="false" name="Medium Grid 3 Accent 4"/>
<w:lsdexception locked="false" priority="70" semihidden="false"
UnhideWhenUsed="false" name="Dark List Accent 4"/>
<w:lsdexception locked="false" priority="71" semihidden="false"
UnhideWhenUsed="false" name="Colorful Shading Accent 4"/>
<w:lsdexception locked="false" priority="72" semihidden="false"
UnhideWhenUsed="false" name="Colorful List Accent 4"/>
<w:lsdexception locked="false" priority="73" semihidden="false"
UnhideWhenUsed="false" name="Colorful Grid Accent 4"/>
<w:lsdexception locked="false" priority="60" semihidden="false"
UnhideWhenUsed="false" name="Light Shading Accent 5"/>
<w:lsdexception locked="false" priority="61" semihidden="false"
UnhideWhenUsed="false" name="Light List Accent 5"/>
<w:lsdexception locked="false" priority="62" semihidden="false"
UnhideWhenUsed="false" name="Light Grid Accent 5"/>
<w:lsdexception locked="false" priority="63" semihidden="false"
UnhideWhenUsed="false" name="Medium Shading 1 Accent 5"/>
<w:lsdexception locked="false" priority="64" semihidden="false"
UnhideWhenUsed="false" name="Medium Shading 2 Accent 5"/>
<w:lsdexception locked="false" priority="65" semihidden="false"
UnhideWhenUsed="false" name="Medium List 1 Accent 5"/>
<w:lsdexception locked="false" priority="66" semihidden="false"
UnhideWhenUsed="false" name="Medium List 2 Accent 5"/>
<w:lsdexception locked="false" priority="67" semihidden="false"
UnhideWhenUsed="false" name="Medium Grid 1 Accent 5"/>
<w:lsdexception locked="false" priority="68" semihidden="false"
UnhideWhenUsed="false" name="Medium Grid 2 Accent 5"/>
<w:lsdexception locked="false" priority="69" semihidden="false"
UnhideWhenUsed="false" name="Medium Grid 3 Accent 5"/>
<w:lsdexception locked="false" priority="70" semihidden="false"
UnhideWhenUsed="false" name="Dark List Accent 5"/>
<w:lsdexception locked="false" priority="71" semihidden="false"
UnhideWhenUsed="false" name="Colorful Shading Accent 5"/>
<w:lsdexception locked="false" priority="72" semihidden="false"
UnhideWhenUsed="false" name="Colorful List Accent 5"/>
<w:lsdexception locked="false" priority="73" semihidden="false"
UnhideWhenUsed="false" name="Colorful Grid Accent 5"/>
<w:lsdexception locked="false" priority="60" semihidden="false"
UnhideWhenUsed="false" name="Light Shading Accent 6"/>
<w:lsdexception locked="false" priority="61" semihidden="false"
UnhideWhenUsed="false" name="Light List Accent 6"/>
<w:lsdexception locked="false" priority="62" semihidden="false"
UnhideWhenUsed="false" name="Light Grid Accent 6"/>
<w:lsdexception locked="false" priority="63" semihidden="false"
UnhideWhenUsed="false" name="Medium Shading 1 Accent 6"/>
<w:lsdexception locked="false" priority="64" semihidden="false"
UnhideWhenUsed="false" name="Medium Shading 2 Accent 6"/>
<w:lsdexception locked="false" priority="65" semihidden="false"
UnhideWhenUsed="false" name="Medium List 1 Accent 6"/>
<w:lsdexception locked="false" priority="66" semihidden="false"
UnhideWhenUsed="false" name="Medium List 2 Accent 6"/>
<w:lsdexception locked="false" priority="67" semihidden="false"
UnhideWhenUsed="false" name="Medium Grid 1 Accent 6"/>
<w:lsdexception locked="false" priority="68" semihidden="false"
UnhideWhenUsed="false" name="Medium Grid 2 Accent 6"/>
<w:lsdexception locked="false" priority="69" semihidden="false"
UnhideWhenUsed="false" name="Medium Grid 3 Accent 6"/>
<w:lsdexception locked="false" priority="70" semihidden="false"
UnhideWhenUsed="false" name="Dark List Accent 6"/>
<w:lsdexception locked="false" priority="71" semihidden="false"
UnhideWhenUsed="false" name="Colorful Shading Accent 6"/>
<w:lsdexception locked="false" priority="72" semihidden="false"
UnhideWhenUsed="false" name="Colorful List Accent 6"/>
<w:lsdexception locked="false" priority="73" semihidden="false"
UnhideWhenUsed="false" name="Colorful Grid Accent 6"/>
<w:lsdexception locked="false" priority="19" semihidden="false"
UnhideWhenUsed="false" qformat="true" name="Subtle Emphasis"/>
<w:lsdexception locked="false" priority="21" semihidden="false"
UnhideWhenUsed="false" qformat="true" name="Intense Emphasis"/>
<w:lsdexception locked="false" priority="31" semihidden="false"
UnhideWhenUsed="false" qformat="true" name="Subtle Reference"/>
<w:lsdexception locked="false" priority="32" semihidden="false"
UnhideWhenUsed="false" qformat="true" name="Intense Reference"/>
<w:lsdexception locked="false" priority="33" semihidden="false"
UnhideWhenUsed="false" qformat="true" name="Book Title"/>
<w:lsdexception locked="false" priority="37" name="Bibliography"/>
<w:lsdexception locked="false" priority="39" qformat="true" name="TOC Heading"/>
</w:latentstyles>
</xml><![endif]--><!--[if gte mso 10]>
<style>
/* Style Definitions */
table.MsoNormalTable
{mso-style-name:普通表格;
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-priority:99;
mso-style-qformat:yes;
mso-style-parent:"";
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
mso-para-margin:0cm;
mso-para-margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:10.5pt;
mso-bidi-font-size:11.0pt;
font-family:"Calibri","sans-serif";
mso-ascii-font-family:Calibri;
mso-ascii-theme-font:minor-latin;
mso-fareast-font-family:宋体;
mso-fareast-theme-font:minor-fareast;
mso-hansi-font-family:Calibri;
mso-hansi-theme-font:minor-latin;
mso-bidi-font-family:"Times New Roman";
mso-bidi-theme-font:minor-bidi;
mso-font-kerning:1.0pt;}
</style>
<![endif]-->
<p class="MsoPlainText"><span lang="EN-US">Linux </span><span>下飞鸽传书设计实现<span lang="EN-US"></span></span></p>
<p class="MsoPlainText"><span lang="EN-US">1.</span><span>系统功能<span lang="EN-US"></span></span></p>
<p class="MsoPlainText"><span>根据飞鸽传书协议在<span lang="EN-US"> linux </span>下实现飞鸽传输程序<span lang="EN-US">,</span>并且与<span lang="EN-US"> windows </span>下飞鸽兼容。具体功能模块包括用户上线<span lang="EN-US">,</span>下线<span lang="EN-US">,</span>刷新查看在线用户<span lang="EN-US">,</span>收发消息<span lang="EN-US">,</span>传送文件<span lang="EN-US">/</span>文件夹功能模块。<span lang="EN-US"></span></span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">2.</span><span>具体实现<span lang="EN-US"></span></span></p>
<p class="MsoPlainText"><span lang="EN-US">2.1 </span><span>关键数据结构<span lang="EN-US"></span></span></p>
<p class="MsoPlainText"><span lang="EN-US">/*</span><span>命令的结构<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US">typedef struct _command</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;{</span></p>
<p class="MsoPlainText"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span>int version;/*</span><span>命令的版本<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span>int seq;/*</span><span>包编号<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span>char
srcName[100];/*</span><span>发送者姓名<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span>char
srcHost[100];/*</span><span>发送者主机名<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span>int flag;/*</span><span>命令<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span>char
addtion[100];/*</span><span>附加字段<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;}command;</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">/*</span><span>在线用户信息<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US">typedef struct _userInfo</span></p>
<p class="MsoPlainText"><span lang="EN-US">{</span></p>
<p class="MsoPlainText"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span>char
name[MAXLINE];<span>&nbsp;&nbsp;&nbsp;&nbsp; </span>/*</span><span>姓名<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span>char
host[MAXLINE];<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>/*</span><span>主机名<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span>char
group[MAXLINE];<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>/*</span><span>所在的组名<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span>struct
sockaddr_in addr;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>/*</span><span>地址信息<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span>struct
_userInfo next;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>/*</span><span>链表中下一个<span lang="EN-US">*/ </span></span></p>
<p class="MsoPlainText"><span lang="EN-US">}userInfo;</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">/*</span><span>在线用户列表<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US">typedef struct _uList</span></p>
<p class="MsoPlainText"><span lang="EN-US">{</span></p>
<p class="MsoPlainText"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span>userInfo
*userListHead;<span>&nbsp;&nbsp;&nbsp;&nbsp; </span>/*</span><span>链表头<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span>userInfo
userListTail;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>/*</span><span>链表尾<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US">}uList;</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">/*</span><span>消息队列<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US">typedef struct _mesList</span></p>
<p class="MsoPlainText"><span lang="EN-US">{</span></p>
<p class="MsoPlainText"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span>command
*mesHead;</span></p>
<p class="MsoPlainText"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span>command
*mesTail;</span></p>
<p class="MsoPlainText"><span lang="EN-US">}mesList;</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">2.2 </span><span>程序主要结构<span lang="EN-US"></span></span></p>
<p class="MsoPlainText"><span>本程序主要采用多线程结构<span lang="EN-US">,</span>分为<span lang="EN-US"> receive(</span>接收消息<span lang="EN-US">), process(</span>处理收到的消息<span lang="EN-US">), sendData(</span>发送文件<span lang="EN-US">) </span>三个子线程。线程间通信互斥锁与<span lang="EN-US"> Posix </span>信号量进行通信。<span lang="EN-US"></span></span></p>
<p class="MsoPlainText"><span lang="EN-US"><br></span><span lang="EN-US"></span></p>
<p class="MsoPlainText"><span lang="EN-US">2.3 </span><span>函数接口<span lang="EN-US"></span></span></p>
<p class="MsoPlainText"><span lang="EN-US">(1) /*</span><span>从文件描述符<span lang="EN-US">fd</span>中读取<span lang="EN-US">count</span>个字符存入<span lang="EN-US">buf</span>中<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US"><span>&nbsp;</span>ssize_t
readn(int fd,void *buf,size_t count)</span><span>；<span lang="EN-US"></span></span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(2) /*</span><span>将<span lang="EN-US">buf</span>所指向的存储区中的<span lang="EN-US">len</span>个字符吸入文件描述符<span lang="EN-US">fd</span>中<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US"><span>&nbsp;</span>ssize_t
writen(int fd,char *buf,int len);</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(3) /*</span><span>用于字符串转换<span lang="EN-US">,</span>网络传输中用<span lang="EN-US">gb2312</span>编码，<span lang="EN-US">linux</span>下<span lang="EN-US">gtk</span>用<span lang="EN-US">utf-8</span>编码，需要进行转换<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US"><span>&nbsp;</span>int
code_convert(char *from_charset,char *to_charset,char *inbuf,int inlen,char
*outbuf,int outlen);</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(4) /*</span><span>在用户链表中加入新用户信息，加入成功返回<span lang="EN-US">1</span>，否则返回<span lang="EN-US">0,</span>使用<span lang="EN-US">userInfoMutex</span>进行线程间通信控制<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US"><span>&nbsp; </span>int
pushBack(uList *list,userInfo user);</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(5) /*</span><span>在用户链表中删除指定地址信息的用户，删除成功后返回<span lang="EN-US">1</span>，否则返回<span lang="EN-US">0</span>，使用<span lang="EN-US">userInfoMutex</span>进行线程间控制<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US"><span>&nbsp; </span>int
delUser(uList *list, struct sockaddr_in addr);</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(6) /*</span><span>判断该用户是否已经存在，已经存在则返回<span lang="EN-US">1</span>，否则返回<span lang="EN-US">0,</span>使用<span lang="EN-US">userInfoMutex</span>进行线程间控制<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US">int isExist(uList *list,struct sockaddr_in addr);</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(7)</span><span>清空用户链表，释放空间，用于用户退出和用户刷新时释放空间<span lang="EN-US">,</span>使用<span lang="EN-US">userInfoMutex</span>进行线程间控制<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US">int destroyList(uList *list);</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(8)/*</span><span>创建命令字<span lang="EN-US">,com</span>为要返回的命令字<span lang="EN-US">,flag </span>为消息标志<span lang="EN-US">,addtion </span>为附加标志<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US">void createCmd(command &amp; com,int flag,char
addtion[])</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(9)/*</span><span>发送消息，<span lang="EN-US">com</span>为要发送的消息，<span lang="EN-US">servaddr</span>为要发送的地址，<span lang="EN-US">attach</span>为文件附件信息<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">void sendCmd(command com, struct sockaddr_in
servaddr,char attach[]);</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(10) /*</span><span>把收到的消息加入到消息队列中<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US">void addMes(mesList *mHead,command cmd);</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(11) /*</span><span>把消息队列中头部的节点消息提取出来用于处理<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US">int delMes(mesList *mHead,command *cmd);</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(12)/*</span><span>初始化操作，飞鸽登录时初始化消息链表，用户链表，信号量，套接字信息<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US"><span>&nbsp;</span>void init();</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(13)/*</span><span>登录操作<span lang="EN-US">,</span>发送用户上线消息<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US">void login();</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(14)/*</span><span>解析收到的消息命令，提取各个字段<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US"><span>&nbsp;</span>int
analysisCmd(command *cmd,char *buf);</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(15) /*</span><span>接收消息线程处理函数<span lang="EN-US">,</span>将收到的消息加入消息队列中，通过信号量<span lang="EN-US">waitNoFull</span>和<span lang="EN-US">waitNoEmpty</span>和消息处理线程进行通信。消息队列用<span lang="EN-US">mesMutex</span>与其他线程进行通信，保证消息队列的正确性<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US"><span>&nbsp;</span>void
*receive(void *arg);</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(16)/*gtk</span><span>界面中显示在线用户信息<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US">void showUser(uList *list);</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(17)/*</span><span>在<span lang="EN-US">gtk</span>界面中显示消息<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US">void showMessage(char *message);</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(18)/*</span><span>显示收到的信息<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US">void showRecvMessage(char *host,char *message);</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(19)/*</span><span>分析文件的信息，提取有用的字段<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US">void fileAnalysis(char *recv,int *fNum,char *fName,int
*fSize,int *fTime,int *fType);</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(20) /*</span><span>保存收到的单个文件<span lang="EN-US">,saveName</span>为保存的文件名<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US">void saveSignalFile(char *saveName);</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(21)/*</span><span>分析目录附件，获得目录文件的文件名，文件大小，文件类型<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US">void getDirInfo(char *recv,char *fName,int *fSize,int
*fType);</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(22) /*</span><span>保存目录<span lang="EN-US">,saveName</span>为要保存的目录<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US">void saveDir(char *saveName);</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(23)/*</span><span>保存文件<span lang="EN-US">,recvType=1</span>为保存文件，<span lang="EN-US">recvType=2</span>为保存的目录<span lang="EN-US">,</span>使用<span lang="EN-US">fileMutex</span>来设置互斥性<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US">void saveFile();</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(24)/*</span><span>收到单个文件<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US">void receiveSignalFile(char *recvFileName);</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(25)/*</span><span>收到单个目录<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US">void receiveDir(char *recvDirName);</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(26)/*</span><span>接收文件<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US">void receiveFile(command cmd);</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(27)/*</span><span>信号处理线程<span lang="EN-US">,</span>从消息队列中取出消息进行处理<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US">void *process(void *arg);</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(28)/*</span><span>发送消息<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US">int sendMes();</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(29) /*</span><span>将文件名进行转换<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US">char *transName(char *fileName);</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(30)/*</span><span>发送文件<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US">void sendFile();</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(31)/*</span><span>发送文件夹<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US">void sendDir();</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(32)/*</span><span>用户点击刷新<span lang="EN-US">,</span>刷新在线用户<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US">void refresh();</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(33) /*</span><span>用户退出<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US">void quit();</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(34)/*</span><span>传输文件夹数据，递归函数<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US">void transferDir(int fd,char *dir);</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(35)/*</span><span>监听<span lang="EN-US">TCP</span>套接口，发送文件与文件夹线程<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US">void *sendData(void *arg);</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(36)/*</span><span>创建菜单<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US">static void create_popup_menu(GtkWidget
*menu,GtkWidget *view);</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(37)/*</span><span>右击选中<span lang="EN-US">treeview,</span>显示传送文件与文件夹菜单<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US">static gboolean showTreeView(GtkWidget
*eventBox,GdkEventButton *event,GtkWidget *menu);</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(38)/*</span><span>选择要发送的文件<span lang="EN-US"> */</span></span></p>
<p class="MsoPlainText"><span lang="EN-US">static void selectFile();</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(39)/*</span><span>选择要发送的文件夹<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US">static void selectDir();</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">(40)/*</span><span>选择要保存的文件名或文件夹名<span lang="EN-US">*/</span></span></p>
<p class="MsoPlainText"><span lang="EN-US">static void selectSaveFile();</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">3.</span><span>总结<span lang="EN-US"></span></span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span></span><span>实现了<span lang="EN-US">linux</span>下飞鸽传书的基本功能，并且能与<span lang="EN-US">window</span>下飞鸽进行通信，传文件。熟悉了<span lang="EN-US">linux</span>下网络编程，多线程编程及线程间通信（主要用到信号量与互斥锁）。但加密解密那块没有完成，程序结构不是很好，界面做得太差。有空应该看看设计模式<span lang="EN-US">.</span></span></p>
<p class="MsoPlainText">界面截图（界面比较垃圾)：</p>
<p class="MsoPlainText"><img  src="http://www.cppblog.com/images/cppblog_com/tankzhouqiang/Screenshot.png" border="0"><br><span><span lang="EN-US"></span></span></p>
<p class="MsoPlainText"><span><span lang="EN-US">附：</span></span></p>
<p class="MsoPlainText"><span><span lang="EN-US">飞鸽协议： http://bbs.chinaunix.net/viewthread.php?tid=1015775<br></span></span></p>
<p class="MsoPlainText"><span>&nbsp;<span lang="EN-US"></span></span></p>
<p class="MsoPlainText"><span lang="EN-US"><br></span><span lang="EN-US"></span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoPlainText"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoNormal"><span lang="EN-US">&nbsp;</span></p><img src ="http://www.cppblog.com/tankzhouqiang/aggbug/141915.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tankzhouqiang/" target="_blank">周强</a> 2011-03-15 21:57 <a href="http://www.cppblog.com/tankzhouqiang/archive/2011/03/15/141915.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>epoll模型（转载）</title><link>http://www.cppblog.com/tankzhouqiang/archive/2011/03/02/140973.html</link><dc:creator>周强</dc:creator><author>周强</author><pubDate>Wed, 02 Mar 2011 04:23:00 GMT</pubDate><guid>http://www.cppblog.com/tankzhouqiang/archive/2011/03/02/140973.html</guid><wfw:comment>http://www.cppblog.com/tankzhouqiang/comments/140973.html</wfw:comment><comments>http://www.cppblog.com/tankzhouqiang/archive/2011/03/02/140973.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tankzhouqiang/comments/commentRss/140973.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tankzhouqiang/services/trackbacks/140973.html</trackback:ping><description><![CDATA[<h1 class="postTitle"><a  href="http://www.cnblogs.com/OnlyXP/archive/2007/08/10/851222.html" id="ctl02_TitleUrl" class="postTitle2">epoll精髓</a>
</h1>
<p>
在linux的网络编程中，很长的时间都在使用select来做事件触发。在linux新的内核中，有了一种替换它的机制，就是epoll。<br>
相比于select，epoll最大的好处在于它不会随着监听fd数目的增长而降低效率。因为在内核中的select实现中，它是采用轮询来处理的，轮询的fd数目越多，自然耗时越多。并且，在linux/posix_types.h头文件有这样的声明：<br>
<span style="color: #ff0102;">#define __FD_SETSIZE&nbsp;&nbsp;&nbsp; 1024</span>
<br>
表示select最多同时监听1024个fd，当然，可以通过修改头文件再重编译内核来扩大这个数目，但这似乎并不治本。<br>
<br>
epoll的接口非常简单，一共就三个函数：<br>
<span style="color: #ff0102;">1. int epoll_create(int size);</span>
<br>
创
建一个epoll的句柄，size用来告诉内核这个监听的数目一共有多大。这个参数不同于select()中的第一个参数，给出最大监听的fd+1的值。
需要注意的是，当创建好epoll句柄后，它就是会占用一个fd值，在linux下如果查看/proc/进程id/fd/，是能够看到这个fd的，所以在
使用完epoll后，必须调用close()关闭，否则可能导致fd被耗尽。<br>
<br>
<br>
<span style="color: #ff0102;">2. int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);</span>
<br>
epoll的事件注册函数，它不同与select()是在监听事件时告诉内核要监听什么类型的事件，而是在这里先注册要监听的事件类型。第一个参数是epoll_create()的返回值，第二个参数表示动作，用三个宏来表示：<br>
EPOLL_CTL_ADD：注册新的fd到epfd中；<br>
EPOLL_CTL_MOD：修改已经注册的fd的监听事件；<br>
EPOLL_CTL_DEL：从epfd中删除一个fd；<br>
第三个参数是需要监听的fd，第四个参数是告诉内核需要监听什么事，struct epoll_event结构如下：<br>
struct epoll_event {<br>
&nbsp; __uint32_t events;&nbsp; /* Epoll events */<br>
&nbsp; epoll_data_t data;&nbsp; /* User data variable */<br>
};<br>
<br>
events可以是以下几个宏的集合：<br>
EPOLLIN ：表示对应的文件描述符可以读（包括对端SOCKET正常关闭）；<br>
EPOLLOUT：表示对应的文件描述符可以写；<br>
EPOLLPRI：表示对应的文件描述符有紧急的数据可读（这里应该表示有带外数据到来）；<br>
EPOLLERR：表示对应的文件描述符发生错误；<br>
EPOLLHUP：表示对应的文件描述符被挂断；<br>
EPOLLET： 将EPOLL设为边缘触发(Edge Triggered)模式，这是相对于水平触发(Level Triggered)来说的。<br>
EPOLLONESHOT：只监听一次事件，当监听完这次事件之后，如果还需要继续监听这个socket的话，需要再次把这个socket加入到EPOLL队列里<br>
<br>
<br>
<span style="color: #ff0102;">3. int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);</span>
<br>
等
待事件的产生，类似于select()调用。参数events用来从内核得到事件的集合，maxevents告之内核这个events有多大，这个
maxevents的值不能大于创建epoll_create()时的size，参数timeout是超时时间（毫秒，0会立即返回，-1将不确定，也有
说法说是永久阻塞）。该函数返回需要处理的事件数目，如返回0表示已超时。<br>
<br>
--------------------------------------------------------------------------------------------<br>
<br>
从man手册中，得到ET和LT的具体描述如下<br>
<br>
EPOLL事件有两种模型：<br>
Edge Triggered (ET)<br>
Level Triggered (LT)<br>
<br>
假如有这样一个例子：<br>
1. 我们已经把一个用来从管道中读取数据的文件句柄(RFD)添加到epoll描述符<br>
2. 这个时候从管道的另一端被写入了2KB的数据<br>
3. 调用epoll_wait(2)，并且它会返回RFD，说明它已经准备好读取操作<br>
4. 然后我们读取了1KB的数据<br>
5. 调用epoll_wait(2)......<br>
<br>
Edge Triggered 工作模式：<br>
如
果我们在第1步将RFD添加到epoll描述符的时候使用了EPOLLET标志，那么在第5步调用epoll_wait(2)之后将有可能会挂起，因为剩
余的数据还存在于文件的输入缓冲区内，而且数据发出端还在等待一个针对已经发出数据的反馈信息。只有在监视的文件句柄上发生了某个事件的时候 ET
工作模式才会汇报事件。因此在第5步的时候，调用者可能会放弃等待仍在存在于文件输入缓冲区内的剩余数据。在上面的例子中，会有一个事件产生在RFD句柄
上，因为在第2步执行了一个写操作，然后，事件将会在第3步被销毁。因为第4步的读取操作没有读空文件输入缓冲区内的数据，因此我们在第5步调用
epoll_wait(2)完成后，是否挂起是不确定的。epoll工作在ET模式的时候，必须使用非阻塞套接口，以避免由于一个文件句柄的阻塞读/阻塞
写操作把处理多个文件描述符的任务饿死。最好以下面的方式调用ET模式的epoll接口，在后面会介绍避免可能的缺陷。<br>
&nbsp;&nbsp; i&nbsp;&nbsp;&nbsp; 基于非阻塞文件句柄<br>
&nbsp;&nbsp; ii&nbsp;&nbsp; 只有当read(2)或者write(2)返回EAGAIN时才需要挂起，等待。<span style="font-weight: bold; color: #0001ff;">但这并不是说每次read()时都需要循环读，直到读到产生一个EAGAIN才认为此次事件处理完成，当read()返回的读到的数据长度小于请求的数据长度时，就可以确定此时缓冲中已没有数据了，也就可以认为此事读事件已处理完成。</span>
<br>
<br>
Level Triggered 工作模式<br>
相
反的，以LT方式调用epoll接口的时候，它就相当于一个速度比较快的poll(2)，并且无论后面的数据是否被使用，因此他们具有同样的职能。因为即
使使用ET模式的epoll，在收到多个chunk的数据的时候仍然会产生多个事件。调用者可以设定EPOLLONESHOT标志，在
epoll_wait(2)收到事件后epoll会与事件关联的文件句柄从epoll描述符中禁止掉。因此当EPOLLONESHOT设定后，使用带有
EPOLL_CTL_MOD标志的epoll_ctl(2)处理文件句柄就成为调用者必须作的事情。<br>
<br>
<br>
然后详细解释ET, LT:<br>
<br>
LT(level
triggered)是缺省的工作方式，并且同时支持block和no-block
socket.在这种做法中，内核告诉你一个文件描述符是否就绪了，然后你可以对这个就绪的fd进行IO操作。如果你不作任何操作，内核还是会继续通知你
的，所以，这种模式编程出错误可能性要小一点。传统的select/poll都是这种模型的代表．<br>
<br>
ET(edge-triggered)
是高速工作方式，只支持no-block
socket。在这种模式下，当描述符从未就绪变为就绪时，内核通过epoll告诉你。然后它会假设你知道文件描述符已经就绪，并且不会再为那个文件描述
符发送更多的就绪通知，直到你做了某些操作导致那个文件描述符不再为就绪状态了(比如，你在发送，接收或者接收请求，或者发送接收的数据少于一定量时导致
了一个EWOULDBLOCK 错误）。但是请注意，如果一直不对这个fd作IO操作(从而导致它再次变成未就绪)，内核不会发送更多的通知(only
once),<span style="font-weight: bold; font-style: italic;">不过在TCP协议中，ET模式的加速效用仍需要更多的benchmark确认（这句话不理解）。</span>
<br>
<br>
<span style="font-style: italic;">在
许多测试中我们会看到如果没有大量的idle
-connection或者dead-connection，epoll的效率并不会比select/poll高很多，但是当我们遇到大量的idle-
connection(例如WAN环境中存在大量的慢速连接)，就会发现epoll的效率大大高于select/poll。（未测试）</span>
<br>
<br>
<br>
<br>
另外，当使用epoll的ET模型来工作时，当产生了一个EPOLLIN事件后，<br>
<span style="color: #ff0102;">读数据的时候需要考虑的是当recv()返回的大小如果等于请求的大小，那么很有可能是缓冲区还有数据未读完，也意味着该次事件还没有处理完，所以还需要再次读取</span>
：<br>
while(rs)<br>
{<br>
&nbsp; buflen = recv(activeevents[i].data.fd, buf, sizeof(buf), 0);<br>
&nbsp; if(buflen &lt; 0)<br>
&nbsp; {<br>
&nbsp;&nbsp;&nbsp; // 由于是非阻塞的模式,所以当errno为EAGAIN时,表示当前缓冲区已无数据可读<br>
&nbsp;&nbsp;&nbsp; // 在这里就当作是该次事件已处理处.<br>
&nbsp;&nbsp;&nbsp; if(errno == EAGAIN)<br>
&nbsp;&nbsp;&nbsp;&nbsp; break;<br>
&nbsp;&nbsp;&nbsp; else<br>
&nbsp;&nbsp;&nbsp;&nbsp; return;<br>
&nbsp;&nbsp; }<br>
&nbsp;&nbsp; else if(buflen == 0)<br>
&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp; // 这里表示对端的socket已正常关闭.<br>
&nbsp;&nbsp; }<br>
<span style="color: #ff0102;">&nbsp;&nbsp; if(buflen == sizeof(buf)</span>
<br style="color: #ff0102;">
<span style="color: #ff0102;">&nbsp;&nbsp;&nbsp;&nbsp; rs = 1;&nbsp;&nbsp; // 需要再次读取</span>
<br>
&nbsp;&nbsp; else<br>
&nbsp;&nbsp;&nbsp;&nbsp; rs = 0;<br>
}<br>
<br>
<br>
<span style="font-weight: bold; color: #ff0102;">还
有，假如发送端流量大于接收端的流量(意思是epoll所在的程序读比转发的socket要快),由于是非阻塞的socket,那么send()函数虽然
返回,但实际缓冲区的数据并未真正发给接收端,这样不断的读和发，当缓冲区满后会产生EAGAIN错误(参考man
send),同时,不理会这次请求发送的数据.所以,需要封装socket_send()的函数用来处理这种情况,该函数会尽量将数据写完再返回，返回
-1表示出错。在socket_send()内部,当写缓冲已满(send()返回-1,且errno为EAGAIN),那么会等待后再重试.这种方式并
不很完美,在理论上可能会长时间的阻塞在socket_send()内部,但暂没有更好的办法.</span>
<br>
<br>
ssize_t socket_send(int sockfd, const char* buffer, size_t buflen)<br>
{<br>
&nbsp; ssize_t tmp;<br>
&nbsp; size_t total = buflen;<br>
&nbsp; const char *p = buffer;<br>
<br>
&nbsp; while(1)<br>
&nbsp; {<br>
&nbsp;&nbsp;&nbsp; tmp = send(sockfd, p, total, 0);<br>
&nbsp;&nbsp;&nbsp; if(tmp &lt; 0)<br>
&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 当send收到信号时,可以继续写,但这里返回-1.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(errno == EINTR)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 当socket是非阻塞时,如返回此错误,表示写缓冲队列已满,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 在这里做延时后再重试.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(errno == EAGAIN)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; usleep(1000);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; continue;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; if((size_t)tmp == total)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return buflen;<br>
<br>
&nbsp;&nbsp;&nbsp; total -= tmp;<br>
&nbsp;&nbsp;&nbsp; p += tmp;<br>
&nbsp; }<br>
<br>
&nbsp; return tmp;<br>
}
</p><img src ="http://www.cppblog.com/tankzhouqiang/aggbug/140973.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tankzhouqiang/" target="_blank">周强</a> 2011-03-02 12:23 <a href="http://www.cppblog.com/tankzhouqiang/archive/2011/03/02/140973.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>epoll模型实例（转载）</title><link>http://www.cppblog.com/tankzhouqiang/archive/2011/03/02/140972.html</link><dc:creator>周强</dc:creator><author>周强</author><pubDate>Wed, 02 Mar 2011 04:22:00 GMT</pubDate><guid>http://www.cppblog.com/tankzhouqiang/archive/2011/03/02/140972.html</guid><wfw:comment>http://www.cppblog.com/tankzhouqiang/comments/140972.html</wfw:comment><comments>http://www.cppblog.com/tankzhouqiang/archive/2011/03/02/140972.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tankzhouqiang/comments/commentRss/140972.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tankzhouqiang/services/trackbacks/140972.html</trackback:ping><description><![CDATA[<h1 class="title_txt"><cite class="fav_csdnstylebykimi"> </cite>
</h1>
<div class="blogstory">
<h2>
<a  href="http://www.cppblog.com/converse/archive/2008/04/29/48482.html" id="viewpost1_TitleUrl">epoll学习笔记</a>
</h2>
<p>
epoll有两种模式,Edge Triggered(简称ET) 和 Level
Triggered(简称LT).在采用这两种模式时要注意的是,如果采用ET模式,那么仅当状态发生变化时才会通知,而采用LT模式类似于原来的
select/poll操作,只要还有没有处理的事件就会一直通知.<br>
<br>
以代码来说明问题:<br>
首先给出server的代码,需要说明的是每次accept的连接,加入可读集的时候采用的都是ET模式,而且接收缓冲区是5字节的,也就是每次只接收5字节的数据:</p>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><span style="color: #000000;">#include&nbsp;</span>
<span style="color: #000000;">&lt;</span>
<span style="color: #000000;">iostream</span>
<span style="color: #000000;">&gt;</span>
<span style="color: #000000;"><br>
#include&nbsp;</span>
<span style="color: #000000;">&lt;</span>
<span style="color: #000000;">sys</span>
<span style="color: #000000;">/</span>
<span style="color: #000000;">socket.h</span>
<span style="color: #000000;">&gt;</span>
<span style="color: #000000;"><br>
#include&nbsp;</span>
<span style="color: #000000;">&lt;</span>
<span style="color: #000000;">sys</span>
<span style="color: #000000;">/</span>
<span style="color: #000000;">epoll.h</span>
<span style="color: #000000;">&gt;</span>
<span style="color: #000000;"><br>
#include&nbsp;</span>
<span style="color: #000000;">&lt;</span>
<span style="color: #000000;">netinet</span>
<span style="color: #000000;">/</span>
<span style="color: #000000;">in.h</span>
<span style="color: #000000;">&gt;</span>
<span style="color: #000000;"><br>
#include&nbsp;</span>
<span style="color: #000000;">&lt;</span>
<span style="color: #000000;">arpa</span>
<span style="color: #000000;">/</span>
<span style="color: #000000;">inet.h</span>
<span style="color: #000000;">&gt;</span>
<span style="color: #000000;"><br>
#include&nbsp;</span>
<span style="color: #000000;">&lt;</span>
<span style="color: #000000;">fcntl.h</span>
<span style="color: #000000;">&gt;</span>
<span style="color: #000000;"><br>
#include&nbsp;</span>
<span style="color: #000000;">&lt;</span>
<span style="color: #000000;">unistd.h</span>
<span style="color: #000000;">&gt;</span>
<span style="color: #000000;"><br>
#include&nbsp;</span>
<span style="color: #000000;">&lt;</span>
<span style="color: #000000;">stdio.h</span>
<span style="color: #000000;">&gt;</span>
<span style="color: #000000;"><br>
#include&nbsp;</span>
<span style="color: #000000;">&lt;</span>
<span style="color: #000000;">errno.h</span>
<span style="color: #000000;">&gt;</span>
<span style="color: #000000;"><br>
<br>
using&nbsp;namespace&nbsp;std;<br>
<br>
#define&nbsp;MAXLINE&nbsp;</span>
<span style="color: #000000;">5</span>
<span style="color: #000000;"><br>
#define&nbsp;OPEN_MAX&nbsp;</span>
<span style="color: #000000;">100</span>
<span style="color: #000000;"><br>
#define&nbsp;LISTENQ&nbsp;</span>
<span style="color: #000000;">20</span>
<span style="color: #000000;"><br>
#define&nbsp;SERV_PORT&nbsp;</span>
<span style="color: #000000;">5000</span>
<span style="color: #000000;"><br>
#define&nbsp;INFTIM&nbsp;</span>
<span style="color: #000000;">1000</span>
<span style="color: #000000;"><br>
<br>
void&nbsp;setnonblocking(</span>
<span style="color: #0000ff;">int</span>
<span style="color: #000000;">&nbsp;sock)<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span style="color: #0000ff;">int</span>
<span style="color: #000000;">&nbsp;opts;<br>
&nbsp;&nbsp;&nbsp;&nbsp;opts</span>
<span style="color: #000000;">=</span>
<span style="color: #000000;">fcntl(sock,F_GETFL);<br>
&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span style="color: #0000ff;">if</span>
<span style="color: #000000;">(opts</span>
<span style="color: #000000;">&lt;</span>
<span style="color: #000000;">0</span>
<span style="color: #000000;">)<br>
&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;perror(</span>
<span style="color: #000000;">"</span>
<span style="color: #000000;">fcntl(sock,GETFL)</span>
<span style="color: #000000;">"</span>
<span style="color: #000000;">);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span style="color: #0000ff;">exit</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;opts&nbsp;</span>
<span style="color: #000000;">=</span>
<span style="color: #000000;">&nbsp;opts|O_NONBLOCK;<br>
&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span style="color: #0000ff;">if</span>
<span style="color: #000000;">(fcntl(sock,F_SETFL,opts)</span>
<span style="color: #000000;">&lt;</span>
<span style="color: #000000;">0</span>
<span style="color: #000000;">)<br>
&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;perror(</span>
<span style="color: #000000;">"</span>
<span style="color: #000000;">fcntl(sock,SETFL,opts)</span>
<span style="color: #000000;">"</span>
<span style="color: #000000;">);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span style="color: #0000ff;">exit</span>
<span style="color: #000000;">(</span>
<span style="color: #000000;">1</span>
<span style="color: #000000;">);<br>
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;<br>
}<br>
<br>
</span>
<span style="color: #0000ff;">int</span>
<span style="color: #000000;">&nbsp;main()<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span style="color: #0000ff;">int</span>
<span style="color: #000000;">&nbsp;i,&nbsp;maxi,&nbsp;listenfd,&nbsp;connfd,&nbsp;sockfd,epfd,nfds;<br>
&nbsp;&nbsp;&nbsp;&nbsp;ssize_t&nbsp;n;<br>
&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;line[MAXLINE];<br>
&nbsp;&nbsp;&nbsp;&nbsp;socklen_t&nbsp;clilen;<br>
&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span style="color: #000000;">//</span>
<span style="color: #000000;">声明epoll_event结构体的变量,ev用于注册事件,数组用于回传要处理的事件<br>
&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;epoll_event&nbsp;ev,events[</span>
<span style="color: #000000;">20</span>
<span style="color: #000000;">];<br>
&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span style="color: #000000;">//</span>
<span style="color: #000000;">生成用于处理accept的epoll专用的文件描述符<br>
&nbsp;&nbsp;&nbsp;&nbsp;epfd</span>
<span style="color: #000000;">=</span>
<span style="color: #000000;">epoll_create(</span>
<span style="color: #000000;">256</span>
<span style="color: #000000;">);<br>
&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;sockaddr_in&nbsp;clientaddr;<br>
&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;sockaddr_in&nbsp;serveraddr;<br>
&nbsp;&nbsp;&nbsp;&nbsp;listenfd&nbsp;</span>
<span style="color: #000000;">=</span>
<span style="color: #000000;">&nbsp;socket(AF_INET,&nbsp;SOCK_STREAM,&nbsp;</span>
<span style="color: #000000;">0</span>
<span style="color: #000000;">);<br>
&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span style="color: #000000;">//</span>
<span style="color: #000000;">把socket设置为非阻塞方式<br>
&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span style="color: #000000;">//</span>
<span style="color: #000000;">setnonblocking(listenfd);<br>
&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span style="color: #000000;">//</span>
<span style="color: #000000;">设置与要处理的事件相关的文件描述符<br>
&nbsp;&nbsp;&nbsp;&nbsp;ev.data.fd</span>
<span style="color: #000000;">=</span>
<span style="color: #000000;">listenfd;<br>
&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span style="color: #000000;">//</span>
<span style="color: #000000;">设置要处理的事件类型<br>
&nbsp;&nbsp;&nbsp;&nbsp;ev.events</span>
<span style="color: #000000;">=</span>
<span style="color: #000000;">EPOLLIN|EPOLLET;<br>
&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span style="color: #000000;">//</span>
<span style="color: #000000;">ev.events</span>
<span style="color: #000000;">=</span>
<span style="color: #000000;">EPOLLIN;<br>
&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span style="color: #000000;">//</span>
<span style="color: #000000;">注册epoll事件<br>
&nbsp;&nbsp;&nbsp;&nbsp;epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,</span>
<span style="color: #000000;">&amp;</span>
<span style="color: #000000;">ev);<br>
&nbsp;&nbsp;&nbsp;&nbsp;bzero(</span>
<span style="color: #000000;">&amp;</span>
<span style="color: #000000;">serveraddr,&nbsp;sizeof(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;char&nbsp;</span>
<span style="color: #000000;">*</span>
<span style="color: #000000;">local_addr</span>
<span style="color: #000000;">=</span>
<span style="color: #000000;">"</span>
<span style="color: #000000;">127.0.0.1</span>
<span style="color: #000000;">"</span>
<span style="color: #000000;">;<br>
&nbsp;&nbsp;&nbsp;&nbsp;inet_aton(local_addr,</span>
<span style="color: #000000;">&amp;</span>
<span style="color: #000000;">(serveraddr.sin_addr));</span>
<span style="color: #000000;">//</span>
<span style="color: #000000;">htons(SERV_PORT);<br>
&nbsp;&nbsp;&nbsp;&nbsp;serveraddr.sin_port</span>
<span style="color: #000000;">=</span>
<span style="color: #000000;">htons(SERV_PORT);<br>
&nbsp;&nbsp;&nbsp;&nbsp;bind(listenfd,(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;sizeof(serveraddr));<br>
&nbsp;&nbsp;&nbsp;&nbsp;listen(listenfd,&nbsp;LISTENQ);<br>
&nbsp;&nbsp;&nbsp;&nbsp;maxi&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;">for</span>
<span style="color: #000000;">&nbsp;(&nbsp;;&nbsp;;&nbsp;)&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span style="color: #000000;">//</span>
<span style="color: #000000;">等待epoll事件的发生<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nfds</span>
<span style="color: #000000;">=</span>
<span style="color: #000000;">epoll_wait(epfd,events,</span>
<span style="color: #000000;">20</span>
<span style="color: #000000;">,</span>
<span style="color: #000000;">500</span>
<span style="color: #000000;">);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span style="color: #000000;">//</span>
<span style="color: #000000;">处理所发生的所有事件&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span style="color: #0000ff;">for</span>
<span style="color: #000000;">(i</span>
<span style="color: #000000;">=</span>
<span style="color: #000000;">0</span>
<span style="color: #000000;">;i</span>
<span style="color: #000000;">&lt;</span>
<span style="color: #000000;">nfds;</span>
<span style="color: #000000;">++</span>
<span style="color: #000000;">i)<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;">if</span>
<span style="color: #000000;">(events[i].data.fd</span>
<span style="color: #000000;">==</span>
<span style="color: #000000;">listenfd)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</span>
</div>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>
<span style="color: #000000;">clilen=sizeof(struct sockaddr);</span>
<br>
<span style="color: #000000;">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;connfd&nbsp;</span>
<span style="color: #000000;">=</span>
<span style="color: #000000;">&nbsp;accept(listenfd,(struct sockaddr&nbsp;</span>
<span style="color: #000000;">*</span>
<span style="color: #000000;">)</span>
<span style="color: #000000;">&amp;</span>
<span style="color: #000000;">clientaddr,&nbsp;</span>
<span style="color: #000000;">&amp;</span>
<span style="color: #000000;">clilen);<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;">(connfd</span>
<span style="color: #000000;">&lt;</span>
<span style="color: #000000;">0</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;perror(</span>
<span style="color: #000000;">"</span>
<span style="color: #000000;">connfd&lt;0</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;</span>
<span style="color: #0000ff;">exit</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;&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: #000000;">//</span>
<span style="color: #000000;">setnonblocking(connfd);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;</span>
<span style="color: #000000;">*</span>
<span style="color: #000000;">str&nbsp;</span>
<span style="color: #000000;">=</span>
<span style="color: #000000;">&nbsp;inet_ntoa(clientaddr.sin_addr);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;</span>
<span style="color: #000000;">&lt;&lt;</span>
<span style="color: #000000;">&nbsp;</span>
<span style="color: #000000;">"</span>
<span style="color: #000000;">accapt&nbsp;a&nbsp;connection&nbsp;from&nbsp;</span>
<span style="color: #000000;">"</span>
<span style="color: #000000;">&nbsp;</span>
<span style="color: #000000;">&lt;&lt;</span>
<span style="color: #000000;">&nbsp;str&nbsp;</span>
<span style="color: #000000;">&lt;&lt;</span>
<span style="color: #000000;">&nbsp;endl;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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;ev.data.fd</span>
<span style="color: #000000;">=</span>
<span style="color: #000000;">connfd;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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;ev.events</span>
<span style="color: #000000;">=</span>
<span style="color: #000000;">EPOLLIN|EPOLLET;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span style="color: #000000;">//</span>
<span style="color: #000000;">ev.events</span>
<span style="color: #000000;">=</span>
<span style="color: #000000;">EPOLLIN;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span style="color: #000000;">//</span>
<span style="color: #000000;">注册ev<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,</span>
<span style="color: #000000;">&amp;</span>
<span style="color: #000000;">ev);<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;">(events[i].events</span>
<span style="color: #000000;">&amp;</span>
<span style="color: #000000;">EPOLLIN)<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&nbsp;</span>
<span style="color: #000000;">&lt;&lt;</span>
<span style="color: #000000;">&nbsp;</span>
<span style="color: #000000;">"</span>
<span style="color: #000000;">EPOLLIN</span>
<span style="color: #000000;">"</span>
<span style="color: #000000;">&nbsp;</span>
<span style="color: #000000;">&lt;&lt;</span>
<span style="color: #000000;">&nbsp;endl;<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;">&nbsp;(&nbsp;(sockfd&nbsp;</span>
<span style="color: #000000;">=</span>
<span style="color: #000000;">&nbsp;events[i].data.fd)&nbsp;</span>
<span style="color: #000000;">&lt;</span>
<span style="color: #000000;">&nbsp;</span>
<span style="color: #000000;">0</span>
<span style="color: #000000;">)&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;continue;<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;">&nbsp;(&nbsp;(n&nbsp;</span>
<span style="color: #000000;">=</span>
<span style="color: #000000;">&nbsp;read(sockfd,&nbsp;line,&nbsp;MAXLINE))&nbsp;</span>
<span style="color: #000000;">&lt;</span>
<span style="color: #000000;">&nbsp;</span>
<span style="color: #000000;">0</span>
<span style="color: #000000;">)&nbsp;{<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;">if</span>
<span style="color: #000000;">&nbsp;(errno&nbsp;</span>
<span style="color: #000000;">==</span>
<span style="color: #000000;">&nbsp;ECONNRESET)&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;close(sockfd);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;events[i].data.fd&nbsp;</span>
<span style="color: #000000;">=</span>
<span style="color: #000000;">&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;&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout</span>
<span style="color: #000000;">&lt;&lt;</span>
<span style="color: #000000;">"</span>
<span style="color: #000000;">readline&nbsp;error</span>
<span style="color: #000000;">"</span>
<span style="color: #000000;">&lt;&lt;</span>
<span style="color: #000000;">std::endl;<br>
&nbsp;&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;(n&nbsp;</span>
<span style="color: #000000;">==</span>
<span style="color: #000000;">&nbsp;</span>
<span style="color: #000000;">0</span>
<span style="color: #000000;">)&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;close(sockfd);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;events[i].data.fd&nbsp;</span>
<span style="color: #000000;">=</span>
<span style="color: #000000;">&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;&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;line[n]&nbsp;</span>
<span style="color: #000000;">=</span>
<span style="color: #000000;">&nbsp;</span>
<span style="color: #008000;">'</span>
<span style="color: #008000;">\0';</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;cout&nbsp;</span>
<span style="color: #000000;">&lt;&lt;</span>
<span style="color: #000000;">&nbsp;</span>
<span style="color: #000000;">"</span>
<span style="color: #000000;">read&nbsp;</span>
<span style="color: #000000;">"</span>
<span style="color: #000000;">&nbsp;</span>
<span style="color: #000000;">&lt;&lt;</span>
<span style="color: #000000;">&nbsp;line&nbsp;</span>
<span style="color: #000000;">&lt;&lt;</span>
<span style="color: #000000;">&nbsp;endl;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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;ev.data.fd</span>
<span style="color: #000000;">=</span>
<span style="color: #000000;">sockfd;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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;ev.events</span>
<span style="color: #000000;">=</span>
<span style="color: #000000;">EPOLLOUT|EPOLLET;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span style="color: #000000;">//</span>
<span style="color: #000000;">修改sockfd上要处理的事件为EPOLLOUT<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span style="color: #000000;">//</span>
<span style="color: #000000;">epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,</span>
<span style="color: #000000;">&amp;</span>
<span style="color: #000000;">ev);<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;">(events[i].events</span>
<span style="color: #000000;">&amp;</span>
<span style="color: #000000;">EPOLLOUT)<br>
&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;sockfd&nbsp;</span>
<span style="color: #000000;">=</span>
<span style="color: #000000;">&nbsp;events[i].data.fd;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;write(sockfd,&nbsp;line,&nbsp;n);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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;ev.data.fd</span>
<span style="color: #000000;">=</span>
<span style="color: #000000;">sockfd;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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;ev.events</span>
<span style="color: #000000;">=</span>
<span style="color: #000000;">EPOLLIN|EPOLLET;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span style="color: #000000;">//</span>
<span style="color: #000000;">修改sockfd上要处理的事件为EPOLIN<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,</span>
<span style="color: #000000;">&amp;</span>
<span style="color: #000000;">ev);<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;return&nbsp;</span>
<span style="color: #000000;">0</span>
<span style="color: #000000;">;<br>
}<br>
<br>
</span>
</div>
<p>
<br>
下面给出测试所用的Perl写的client端,在client中发送10字节的数据,同时让client在发送完数据之后进入死循环, 也就是在发送完之后连接的状态不发生改变--既不再发送数据, 也不关闭连接,这样才能观察出server的状态:</p>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><span style="color: #000000;">#!</span>
<span style="color: #000000;">/</span>
<span style="color: #000000;">usr</span>
<span style="color: #000000;">/</span>
<span style="color: #000000;">bin</span>
<span style="color: #000000;">/</span>
<span style="color: #000000;">perl<br>
<br>
use&nbsp;IO::Socket;<br>
<br>
my&nbsp;$host&nbsp;</span>
<span style="color: #000000;">=</span>
<span style="color: #000000;">&nbsp;</span>
<span style="color: #000000;">"</span>
<span style="color: #000000;">127.0.0.1</span>
<span style="color: #000000;">"</span>
<span style="color: #000000;">;<br>
my&nbsp;$port&nbsp;</span>
<span style="color: #000000;">=</span>
<span style="color: #000000;">&nbsp;</span>
<span style="color: #000000;">5000</span>
<span style="color: #000000;">;<br>
<br>
my&nbsp;$socket&nbsp;</span>
<span style="color: #000000;">=</span>
<span style="color: #000000;">&nbsp;IO::Socket::INET</span>
<span style="color: #000000;">-&gt;</span>
<span style="color: #0000ff;">new</span>
<span style="color: #000000;">(</span>
<span style="color: #000000;">"</span>
<span style="color: #000000;">$host:$port</span>
<span style="color: #000000;">"</span>
<span style="color: #000000;">)&nbsp;</span>
<span style="color: #0000ff;">or</span>
<span style="color: #000000;">&nbsp;die&nbsp;</span>
<span style="color: #000000;">"</span>
<span style="color: #000000;">create&nbsp;socket&nbsp;error&nbsp;$@</span>
<span style="color: #000000;">"</span>
<span style="color: #000000;">;<br>
my&nbsp;$msg_out&nbsp;</span>
<span style="color: #000000;">=</span>
<span style="color: #000000;">&nbsp;</span>
<span style="color: #000000;">"</span>
<span style="color: #000000;">1234567890</span>
<span style="color: #000000;">"</span>
<span style="color: #000000;">;<br>
print&nbsp;$socket&nbsp;$msg_out;<br>
print&nbsp;</span>
<span style="color: #000000;">"</span>
<span style="color: #000000;">now&nbsp;send&nbsp;over,&nbsp;go&nbsp;to&nbsp;sleep<img  src="http://www.cppblog.com/Images/dot.gif" alt="">
\n</span>
<span style="color: #000000;">"</span>
<span style="color: #000000;">;<br>
<br>
</span>
<span style="color: #0000ff;">while</span>
<span style="color: #000000;">&nbsp;(</span>
<span style="color: #000000;">1</span>
<span style="color: #000000;">)<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;sleep(</span>
<span style="color: #000000;">1</span>
<span style="color: #000000;">);<br>
}<br>
</span>
</div>
<p>
运行server和client发现,server仅仅读取了5字节的数据,而client其实发送了10字节的数据,也就是说,server仅当第一次
监听到了EPOLLIN事件,由于没有读取完数据,而且采用的是ET模式,状态在此之后不发生变化,因此server再也接收不到EPOLLIN事件了.<br>
(友情提示:上面的这个测试客户端,当你关闭它的时候会再次出发IO可读事件给server,此时server就会去读取剩下的5字节数据了,但是这一事件与前面描述的ET性质并不矛盾.)<br>
<br>
如果我们把client改为这样:</p>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><span style="color: #000000;">#!</span>
<span style="color: #000000;">/</span>
<span style="color: #000000;">usr</span>
<span style="color: #000000;">/</span>
<span style="color: #000000;">bin</span>
<span style="color: #000000;">/</span>
<span style="color: #000000;">perl<br>
<br>
use&nbsp;IO::Socket;<br>
<br>
my&nbsp;$host&nbsp;</span>
<span style="color: #000000;">=</span>
<span style="color: #000000;">&nbsp;</span>
<span style="color: #000000;">"</span>
<span style="color: #000000;">127.0.0.1</span>
<span style="color: #000000;">"</span>
<span style="color: #000000;">;<br>
my&nbsp;$port&nbsp;</span>
<span style="color: #000000;">=</span>
<span style="color: #000000;">&nbsp;</span>
<span style="color: #000000;">5000</span>
<span style="color: #000000;">;<br>
<br>
my&nbsp;$socket&nbsp;</span>
<span style="color: #000000;">=</span>
<span style="color: #000000;">&nbsp;IO::Socket::INET</span>
<span style="color: #000000;">-&gt;</span>
<span style="color: #0000ff;">new</span>
<span style="color: #000000;">(</span>
<span style="color: #000000;">"</span>
<span style="color: #000000;">$host:$port</span>
<span style="color: #000000;">"</span>
<span style="color: #000000;">)&nbsp;</span>
<span style="color: #0000ff;">or</span>
<span style="color: #000000;">&nbsp;die&nbsp;</span>
<span style="color: #000000;">"</span>
<span style="color: #000000;">create&nbsp;socket&nbsp;error&nbsp;$@</span>
<span style="color: #000000;">"</span>
<span style="color: #000000;">;<br>
my&nbsp;$msg_out&nbsp;</span>
<span style="color: #000000;">=</span>
<span style="color: #000000;">&nbsp;</span>
<span style="color: #000000;">"</span>
<span style="color: #000000;">1234567890</span>
<span style="color: #000000;">"</span>
<span style="color: #000000;">;<br>
print&nbsp;$socket&nbsp;$msg_out;<br>
print&nbsp;</span>
<span style="color: #000000;">"</span>
<span style="color: #000000;">now&nbsp;send&nbsp;over,&nbsp;go&nbsp;to&nbsp;sleep<img  src="http://www.cppblog.com/Images/dot.gif" alt="">
\n</span>
<span style="color: #000000;">"</span>
<span style="color: #000000;">;<br>
sleep(</span>
<span style="color: #000000;">5</span>
<span style="color: #000000;">);<br>
print&nbsp;</span>
<span style="color: #000000;">"</span>
<span style="color: #000000;">5&nbsp;second&nbsp;gone<img  src="http://www.cppblog.com/Images/dot.gif" alt="">
send&nbsp;another&nbsp;line\n</span>
<span style="color: #000000;">"</span>
<span style="color: #000000;">;<br>
print&nbsp;$socket&nbsp;$msg_out;<br>
<br>
</span>
<span style="color: #0000ff;">while</span>
<span style="color: #000000;">&nbsp;(</span>
<span style="color: #000000;">1</span>
<span style="color: #000000;">)<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;sleep(</span>
<span style="color: #000000;">1</span>
<span style="color: #000000;">);<br>
}<br>
</span>
</div>
<p>
<br>
可以发现,在server接收完5字节的数据之后一直监听不到client的事件,而当client休眠5秒之后重新发送数据,server再次监听到了变化,只不过因为只是读取了5个字节,仍然有10个字节的数据(client第二次发送的数据)没有接收完.<br>
<br>
如果上面的实验中,对accept的socket都采用的是LT模式,那么只要还有数据留在buffer中,server就会继续得到通知,读者可以自行改动代码进行实验.<br>
<br>
基
于这两个实验,可以得出这样的结论:ET模式仅当状态发生变化的时候才获得通知,这里所谓的状态的变化并不包括缓冲区中还有未处理的数据,也就是说,如果
要采用ET模式,需要一直read/write直到出错为止,很多人反映为什么采用ET模式只接收了一部分数据就再也得不到通知了,大多因为这样;而LT
模式是只要有数据没有处理就会一直通知下去的.</p>
<div id="message8301479" class="t_msgfont">补充说明一下这里一直强调的"状态变化"是什么:<br>
<br>
1)对于监听可读事件时,如果是socket是监听socket,那么当有新的主动连接到来为状态发生变化;对一般的socket而言,协议栈中相应的缓
冲区有新的数据为状态发生变化.但是,如果在一个时间同时接收了N个连接(N&gt;1),但是监听socket只accept了一个连接,那么其它未
accept的连接将不会在ET模式下给监听socket发出通知,此时状态不发生变化;对于一般的socket,就如例子中而言,如果对应的缓冲区本身
已经有了N字节的数据,而只取出了小于N字节的数据,那么残存的数据不会造成状态发生变化.<br>
<br>
2)对于监听可写事件时,同理可推,不再详述.<br>
<br>
而不论是监听可读还是可写,对方关闭socket连接都将造成状态发生变化,比如在例子中,如果强行中断client脚本,也就是主动中断了socket连接,那么都将造成server端发生状态的变化,从而server得到通知,将已经在本方缓冲区中的数据读出.<br>
<br>
把前面的描述可以总结如下:仅当对方的动作(发出数据,关闭连接等)造成的事件才能导致状态发生变化,而本方协议栈中已经处理的事件(包括接收了对方的数
据,接收了对方的主动连接请求)并不是造成状态发生变化的必要条件,状态变化一定是对方造成的.所以在ET模式下的,必须一直处理到出错或者完全处理完
毕,才能进行下一个动作,否则可能会发生错误.</div>
<p>
<br>
另外,从这个例子中,也可以阐述一些基本的网络编程概念.首先,连接的两端中,一端发送成功并不代表着对方上层应用程序接收成功,
就拿上面的client测试程序来说,10字节的数据已经发送成功,但是上层的server并没有调用read读取数据,因此发送成功仅仅说明了数据被对
方的协议栈接收存放在了相应的buffer中,而上层的应用程序是否接收了这部分数据不得而知;同样的,读取数据时也只代表着本方协议栈的对应
buffer中有数据可读,而此时时候在对端是否在发送数据也不得而知.</p>
</div><img src ="http://www.cppblog.com/tankzhouqiang/aggbug/140972.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tankzhouqiang/" target="_blank">周强</a> 2011-03-02 12:22 <a href="http://www.cppblog.com/tankzhouqiang/archive/2011/03/02/140972.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>