﻿<?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++博客-elva-随笔分类-Unix</title><link>http://www.cppblog.com/elva/category/4331.html</link><description /><language>zh-cn</language><lastBuildDate>Sat, 18 Feb 2012 12:08:00 GMT</lastBuildDate><pubDate>Sat, 18 Feb 2012 12:08:00 GMT</pubDate><ttl>60</ttl><item><title>Ubuntu 更新源签名错误 –BADSIG 40976EAF437D05B5</title><link>http://www.cppblog.com/elva/archive/2012/02/18/165876.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Fri, 17 Feb 2012 19:10:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2012/02/18/165876.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/165876.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2012/02/18/165876.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/165876.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/165876.html</trackback:ping><description><![CDATA[<div><h1><a href="http://www.linuxbyte.org/ubuntu-geng-xin-yuan-qian-ming-cuo-wu-badsig-40976eaf437d05b5.html" rel="bookmark" title="Permanent Link: Ubuntu 更新源签名错误 &#8211;BADSIG 40976EAF437D05B5">Ubuntu 更新源签名错误 &#8211;BADSIG 40976EAF437D05B5</a></h1> 			<p>2011-02-19 xiao H Posted in <a href="http://www.linuxbyte.org/category/%e7%b3%bb%e7%bb%9f%e7%ae%a1%e7%90%86" title="查看 系统管理 中的全部文章" rel="category tag">系统管理</a>   <a href="http://www.jiathis.com/share/?uid=900752" target="_blank"><img src="http://www.linuxbyte.org/jiathis.gif" border="0"  alt="" /></a>   </p> 	 				<p>错误提示：</p>  <div><div><pre style="font-family:monospace;">GPG 错误：http://mirrors.163.com maverick-updates Release: 下列签名无效： BADSIG 40976EAF437D05B5 Ubuntu Archive Automatic Signing Key <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ftpmaster</span> @ubuntu.com<span style="color: #000000; font-weight: bold;">&gt;</span></span> <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/ftpmaster<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>  <div>   </div><br /> 修复方法  <div><div><pre style="font-family:monospace;">gpg <span style="color: #660033;">--keyserver</span> keyserver.ubuntu.com <span style="color: #660033;">--recv</span> 40976EAF437D05B5 gpg <span style="color: #660033;">--export</span> <span style="color: #660033;">--armor</span> 40976EAF437D05B5 <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">apt-key</span> add -</pre></div></div>  <p>上面的方法不行可以试试下面这个</p>  <div><div><pre style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">aptitude</span> <span style="color: #660033;">-o</span> Acquire::http::No-Cache=True <span style="color: #660033;">-o</span> Acquire::<span style="color: #007800;">BrokenProxy</span>=<span style="color: #c20cb9; font-weight: bold;">true</span> update</pre></div></div>  <p>终极大法</p>  <div><div><pre style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">apt-get</span> clean <span style="color: #7a0874; font-weight: bold;">cd</span> <span style="color: #000000; font-weight: bold;">/</span>var<span style="color: #000000; font-weight: bold;">/</span>lib<span style="color: #000000; font-weight: bold;">/</span>apt <span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">mv</span> lists lists.old <span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">mkdir</span> <span style="color: #660033;">-p</span> lists<span style="color: #000000; font-weight: bold;">/</span>partial <span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">apt-get</span> clean <span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">apt-get</span> update</pre></div></div>  <p>以上方法来自：</p> <p>http://forum.ubuntu.org.</p></div><br /><br />转自：<br /><div>http://www.linuxbyte.org/ubuntu-geng-xin-yuan-qian-ming-cuo-wu-badsig-40976eaf437d05b5.html</div><img src ="http://www.cppblog.com/elva/aggbug/165876.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2012-02-18 03:10 <a href="http://www.cppblog.com/elva/archive/2012/02/18/165876.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux无法登录，显示module is unknown</title><link>http://www.cppblog.com/elva/archive/2012/01/06/163709.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Fri, 06 Jan 2012 04:35:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2012/01/06/163709.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/163709.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2012/01/06/163709.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/163709.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/163709.html</trackback:ping><description><![CDATA[<div>今天在配置Oracle安装环境时，更改了一些系统参数，注销重新登录时发现即使输入正确的用户名和密码，也无法登录，在按回车的那一瞬间可以看到密码下方有一行快速闪过的提示&#8220;module is unknown&#8221;。不解何意。 <p>&nbsp;&nbsp;&nbsp; 本人的系统默认是命令行界面启动的。于是重启以RunLevel 5进入图形界面。发现图形界面可以正常进入。下面就查询日志吧：</p> <div> <pre>   1:  # cd /var/log/</pre> <pre>   2:  #cat security </pre> </div>   <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:8747F07C-CDE8-481f-B0DF-C6CFD074BF67:93ebaf94-94cb-43ef-9431-ab7c7cce5a9e"><a href="http://www.zhaofengcao.com/wp-content/uploads/2011/08/Log8x6.jpg" title="" rel="thumbnail"><img src="http://www.zhaofengcao.com/wp-content/uploads/2011/08/Log.png" height="265" border="0" width="335"  alt="" /></a></div> <p>在日志文件中，我看到了如下信息：</p> <p>PAM unable to dlopen(/lib/security/pam_limits.so)</p> <p>PAM [error: /lib/security/pam_limits.so: wrong ELF class: ELFCLASS32]</p> <p>PAM adding faulty module: /lib/security/pam_limits.so</p> <p>pam_unix(login:session): session opened for user Oracle by LOGIN(uid=0)</p> <p>Module is unknown</p> <p>看到这里，我想起我在/etc/pam.d/login中加入了:</p> <p>session required /lib/security/pam_limits.so</p> <p>session required pam_limits.so</p> <p>两条配置语句。根据日志信息以上Login上的其他配置信息，将第一条语句注释掉：<br />   </p> <p>#session required /lib/security/pam_limits.so</p> <p>session required pam_limits.so</p> <p>重启，登录，一切正常。问题解决》</p> <p>########################更新##########################33</p> <p>以上问题的出现是由于操作系统的问题。我本想安装32位centos，结果错手拿了一个64bit Centos安装，然后按照32位的配置进行了配置。正确配置在64位下应为：</p> <div> <pre>   1:  session required /lib64/security/pam_limits.so</pre> <pre>   2:  &nbsp;</pre> <pre>   3:  session required pam_limits.so</pre> </div>  </div><br /><br />转自：<div>http://www.zhaofengcao.com/archives/138</div><img src ="http://www.cppblog.com/elva/aggbug/163709.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2012-01-06 12:35 <a href="http://www.cppblog.com/elva/archive/2012/01/06/163709.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>/dev/sdc is apparently in use by the system; will not make a filesystem here! </title><link>http://www.cppblog.com/elva/archive/2011/11/22/160717.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Tue, 22 Nov 2011 08:20:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2011/11/22/160717.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/160717.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2011/11/22/160717.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/160717.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/160717.html</trackback:ping><description><![CDATA[<div class="smallfont"><strong>Re: /dev/sdc is apparently in use by the system; will not make a filesystem here!</strong> </div>
<hr style="background-color: #ffffff; color: #ffffff" size="1" />

<!-- / icon and title --><!-- message -->

<div id="post_message_11225690" class="vbclean_msgtext">
<div style="margin: 5px 20px 20px">
<div style="margin-bottom: 2px" class="smallfont">Quote:</div>
<table border="0" cellspacing="0" cellpadding="6" width="100%">
<tbody>
<tr>
<td class="ubuntu_quotebackground">
<div>Originally Posted by <strong>abriejo</strong> <a href="http://ubuntuforums.org/showthread.php?p=5486933#post5486933" rel="nofollow"><img class="inlineimg" title="View Post" border="0" alt="View Post" src="http://ubuntuforums.org/images/buttons/viewpost.gif" /></a> </div>
<div style="font-style: italic">Hi<br /><br />I was about to try the CD startup when I tried one last thing again.<br /><br />sudo mdadm --stop /dev/md0<br /><br />It worked, but I find it strange because I did it before and md0 did not appear in the fdisk -l screen.<br /><br />Immdiately after that I was able to run the sudo mkfs.ext3 /dev/sdc <br /><br /><br />Maybe it is because I ran the zero-superblock tasks overnight - something that made me nervous, since I have no idea what it does.<br /><br />Than You for your help!</div></td></tr></tbody></table></div><br />It worked for me. Thanks!</div><!-- / message --><img src ="http://www.cppblog.com/elva/aggbug/160717.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2011-11-22 16:20 <a href="http://www.cppblog.com/elva/archive/2011/11/22/160717.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux Signals</title><link>http://www.cppblog.com/elva/archive/2010/08/11/123050.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Wed, 11 Aug 2010 04:12:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2010/08/11/123050.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/123050.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2010/08/11/123050.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/123050.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/123050.html</trackback:ping><description><![CDATA[<h3>Signals</h3>
<p>
Linux Signals are:
</p>
<table>
    <tbody>
        <tr>
            <td>Signal Name</td>
            <td>Number</td>
            <td>Description</td>
        </tr>
        <tr>
            <td>SIGHUP</td>
            <td>1</td>
            <td>Hangup (POSIX)</td>
        </tr>
        <tr>
            <td>SIGINT</td>
            <td>2</td>
            <td>Terminal interrupt (ANSI)</td>
        </tr>
        <tr>
            <td>SIGQUIT</td>
            <td>3</td>
            <td>Terminal quit (POSIX)</td>
        </tr>
        <tr>
            <td>SIGILL</td>
            <td>4</td>
            <td>Illegal instruction (ANSI)</td>
        </tr>
        <tr>
            <td>SIGTRAP</td>
            <td>5</td>
            <td>Trace trap (POSIX)</td>
        </tr>
        <tr>
            <td>SIGIOT</td>
            <td>6</td>
            <td>IOT Trap (4.2 BSD)</td>
        </tr>
        <tr>
            <td>SIGBUS</td>
            <td>7</td>
            <td>BUS error (4.2 BSD)</td>
        </tr>
        <tr>
            <td>SIGFPE</td>
            <td>8</td>
            <td>Floating point exception (ANSI)</td>
        </tr>
        <tr>
            <td>SIGKILL</td>
            <td>9</td>
            <td>Kill(can't be caught or ignored) (POSIX)</td>
        </tr>
        <tr>
            <td>SIGUSR1</td>
            <td>10</td>
            <td>User defined signal 1 (POSIX)</td>
        </tr>
        <tr>
            <td>SIGSEGV</td>
            <td>11</td>
            <td>Invalid memory segment access (ANSI)</td>
        </tr>
        <tr>
            <td>SIGUSR2</td>
            <td>12</td>
            <td>User defined signal 2 (POSIX)</td>
        </tr>
        <tr>
            <td>SIGPIPE</td>
            <td>13</td>
            <td>Write on a pipe with no reader, Broken pipe (POSIX)</td>
        </tr>
        <tr>
            <td>SIGALRM</td>
            <td>14</td>
            <td>Alarm clock (POSIX)</td>
        </tr>
        <tr>
            <td>SIGTERM</td>
            <td>15</td>
            <td>Termination (ANSI)</td>
        </tr>
        <tr>
            <td>SIGSTKFLT</td>
            <td>16</td>
            <td>Stack fault</td>
        </tr>
        <tr>
            <td>SIGCHLD</td>
            <td>17</td>
            <td>Child process has stopped or exited, changed (POSIX)</td>
        </tr>
        <tr>
            <td>SIGCONT</td>
            <td>18</td>
            <td>	Continue executing, if stopped (POSIX)</td>
        </tr>
        <tr>
            <td>SIGSTOP</td>
            <td>19</td>
            <td>Stop executing(can't be caught or ignored) (POSIX)</td>
        </tr>
        <tr>
            <td>SIGTSTP</td>
            <td>20</td>
            <td>Terminal stop signal (POSIX)</td>
        </tr>
        <tr>
            <td>SIGTTIN</td>
            <td>21</td>
            <td>Background process trying to read, from TTY (POSIX)</td>
        </tr>
        <tr>
            <td>SIGTTOU</td>
            <td>22</td>
            <td>Background process trying to write, to TTY (POSIX)</td>
        </tr>
        <tr>
            <td>SIGURG</td>
            <td>23</td>
            <td>Urgent condition on socket (4.2 BSD)</td>
        </tr>
        <tr>
            <td>SIGXCPU</td>
            <td>24</td>
            <td>CPU limit exceeded (4.2 BSD)</td>
        </tr>
        <tr>
            <td>SIGXFSZ</td>
            <td>25</td>
            <td>File size limit exceeded (4.2 BSD)</td>
        </tr>
        <tr>
            <td>SIGVTALRM</td>
            <td>26</td>
            <td>Virtual alarm clock (4.2 BSD)</td>
        </tr>
        <tr>
            <td>SIGPROF</td>
            <td>27</td>
            <td>Profiling alarm clock (4.2 BSD)</td>
        </tr>
        <tr>
            <td>SIGWINCH</td>
            <td>28</td>
            <td>Window size change (4.3 BSD, Sun)</td>
        </tr>
        <tr>
            <td>SIGIO</td>
            <td>29</td>
            <td>I/O now possible (4.2 BSD)</td>
        </tr>
        <tr>
            <td>SIGPWR</td>
            <td>30</td>
            <td>Power failure restart (System V)</td>
        </tr>
    </tbody>
</table>
<br>
<p>
As noted above, processes can ignore, block, or catch all signals except
SIGSTOP and SIGKILL.  If a process catches a signal, it means that it
includes code that will take appropriate action when the signal is
received.  If the signal is not caught by the process, the kernel will
take default action for the signal.
</p>
<h3>FIFOs</h3>
<p>
FIFOs are permanent objects and can be created using the mkfifo(1) or
mknod(1) command.  Inside the program, the FIFO can be created using the
mknod command, then opened and read from or written to just like a
normal file.  The FIFO is normally in blocking mode when attempting to
perform read operations. <br></p>
<p><br></p>
<p>引用自：http://www.comptechdoc.org/os/linux/programming/linux_pgsignals.html</p>
<p><br></p>
<p><br></p>
<div id="blog_text" class="cnt">
<p><font color="#000000" size="2"><strong> 在终端使用kill -l 命令可以显示所有的信号。<br>
$kill -l<br>
1) SIGHUP</strong> </font><font color="#000000" size="2"><strong>  2) SIGINT 3) SIGQUIT 4) SIGILL<br>
5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE<br>
9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2<br>
13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGSTKFLT<br>
17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP<br>
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU<br>
25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH<br>
29) SIGIO 30) SIGPWR 31) SIGSYS 34) SIGRTMIN<br>
35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3 38) SIGRTMIN+4<br>
39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8<br>
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12<br>
47) SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14<br>
51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10<br>
55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7 58) SIGRTMAX-6<br>
59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2<br>
63) SIGRTMAX-1 64) SIGRTMAX</strong> </font></p>
<p><font color="#000000" size="2"><strong> 其中前面31个信号为不可靠信号(非实时的，可能会出现信号的丢失)，后面的信号为可靠信号(实时的real_time,对信号<br>
排队，不会丢失)。</strong> </font></p>
<p><font color="#000000" size="2"><strong> 1) SIGHUP (挂起) 当运行进程的用户注销时通知该进程，使进程终止</strong> </font></p>
<p><font color="#000000" size="2"><strong> 2) SIGINT (中断) 当用户按下时,通知前台进程组终止进程</strong> </font></p>
<p><font color="#000000" size="2"><strong> 3) SIGQUIT (退出) 用户按下或时通知进程，使进程终止</strong> </font></p>
<p><font color="#000000" size="2"><strong> 4) SIGILL (非法指令) 执行了非法指令，如可执行文件本身出现错误、试图执行数据段、堆栈溢出</strong> </font></p>
<p><font color="#000000" size="2"><strong> 5) SIGTRAP 由断点指令或其它trap指令产生. 由debugger使用</strong> </font></p>
<p><font color="#000000" size="2"><strong> 6) SIGABRT (异常中止) 调用abort函数生成的信号</strong> </font></p>
<p><font color="#000000" size="2"><strong> 7) SIGBUS 非法地址, 包括内存地址对齐(alignment)出错. eg: 访问一个四个字长的整数, 但其地址不是4的倍数.</strong> </font></p>
<p><font color="#000000" size="2"><strong> 8) SIGFPE (算术异常) 发生致命算术运算错误,包括浮点运算错误、溢出及除数为0.</strong> </font></p>
<p><font color="#000000" size="2"><strong> 9) SIGKILL (确认杀死) 当用户通过kill -9命令向进程发送信号时，可靠的终止进程</strong> </font></p>
<p><font color="#000000" size="2"><strong> 10) SIGUSR1 用户使用</strong> </font></p>
<p><font color="#000000" size="2"><strong> 11) SIGSEGV (段越界) 当进程尝试访问不属于自己的内存空间导致内存错误时，终止进程</strong> </font></p>
<p><font color="#000000" size="2"><strong> 12) SIGUSR2 用户使用</strong> </font></p>
<p><font color="#000000" size="2"><strong> 13) SIGPIPE 写至无读进程的管道, 或者Socket通信SOCT_STREAM的读进程已经终止，而再写入。</strong> </font></p>
<p><font color="#000000" size="2"><strong> 14) SIGALRM (超时) alarm函数使用该信号，时钟定时器超时响应</strong> </font></p>
<p><font color="#000000" size="2"><strong> 15) SIGTERM (软中断) 使用不带参数的kill命令时终止进程</strong> </font></p>
<p><font color="#000000" size="2"><strong> 17) SIGCHLD (子进程结束) 当子进程终止时通知父进程</strong> </font></p>
<p><font color="#000000" size="2"><strong> 18) SIGCONT (暂停进程继续) 让一个停止(stopped)的进程继续执行. 本信号不能被阻塞.</strong> </font></p>
<p><font color="#000000" size="2"><strong> 19) SIGSTOP (停止) 作业控制信号,暂停停止(stopped)进程的执行. 本信号不能被阻塞, 处理或忽略.</strong> </font></p>
<p><font color="#000000" size="2"><strong> 20) SIGTSTP (暂停/停止) 交互式停止信号, Ctrl-Z 发出这个信号</strong> </font></p>
<p><font color="#000000" size="2"><strong> 21) SIGTTIN 当后台作业要从用户终端读数据时, 终端驱动程序产生SIGTTIN信号</strong> </font></p>
<p><font color="#000000" size="2"><strong> 22) SIGTTOU 当后台作业要往用户终端写数据时, 终端驱动程序产生SIGTTOU信号</strong> </font></p>
<p><font color="#000000" size="2"><strong> 23) SIGURG 有"紧急"数据或网络上带外数据到达socket时产生.</strong> </font></p>
<p><font color="#000000" size="2"><strong> 24) SIGXCPU 超过CPU时间资源限制. 这个限制可以由getrlimit/setrlimit来读取/改变。</strong> </font></p>
<p><font color="#000000" size="2"><strong> 25) SIGXFSZ 当进程企图扩大文件以至于超过文件大小资源限制。</strong> </font></p>
<p><font color="#000000" size="2"><strong> 26) SIGVTALRM 虚拟时钟信号. 类似于SIGALRM, 但是计算的是该进程占用的CPU时间.</strong> </font></p>
<p><font color="#000000" size="2"><strong> 27) SIGPROF (梗概时间超时) setitimer(2)函数设置的梗概统计间隔计时器(profiling interval timer)</strong> </font></p>
<p><font color="#000000" size="2"><strong> 28) SIGWINCH 窗口大小改变时发出.</strong> </font></p>
<p><font color="#000000" size="2"><strong> 29) SIGIO(异步I/O) 文件描述符准备就绪, 可以开始进行输入/输出操作.</strong> </font></p>
<p><font color="#000000" size="2"><strong> 30) SIGPWR 电源失效/重启动</strong> </font></p>
<p><font color="#000000" size="2"><strong> 31) SIGSYS 非法的系统调用。</strong> </font></p>
<p><font color="#000000" size="2"><strong> 在以上列出的信号中，<br>
程序不可捕获、阻塞或忽略的信号有：SIGKILL,SIGSTOP<br>
不能恢复至默认动作的信号有：SIGILL,SIGTRAP<br>
默认会导致进程流产的信号有：SIGABRT,SIGBUS,SIGFPE,SIGILL,SIGIOT,SIGQUIT,SIGSEGV,SIGTRAP,SIGXCPU,SIGXFSZ<br>
默认会导致进程退出的信号有：SIGALRM,SIGHUP,SIGINT,SIGKILL,SIGPIPE,SIGPOLL,SIGPROF,SIGSYS,SIGTERM,SIGUSR1,SIGUSR2,SIGVTALRM<br>
默认会导致进程停止的信号有：SIGSTOP,SIGTSTP,SIGTTIN,SIGTTOU<br>
默认进程忽略的信号有：SIGCHLD,SIGPWR,SIGURG,SIGWINCH</strong> </font></p>
<p><font color="#000000" size="2"><strong> 此外，SIGIO在SVR4是退出，在4.3BSD中是忽略；SIGCONT在进程挂起时是继续，否则是忽略，不能被阻塞。</strong> </font></p>
<p> </p>
<p><font color="#000000" size="2"><strong> 在Unix/Linux中signal函数是比较复杂的一个,其定义原型如下:<br>
void (*signal(int signo,void (*func)(int))) (int)<br>
这个函数中,最外层的函数体<br>
void (* XXX )(int)表明是一个指针,指向一个函数XXX的指针,XXX所代表的函数需要一个int型的参数,返回void<br>
signal(int signo, void(*func)(int))是signal函数的主体.<br>
需要两个参数int型的signo以及一个指向函数的函数.<br>
void (*func)(int).<br>
正是由于其复杂性,在[Plauger 1992]用typedef来对其进行简化<br>
typedef void Sigfuc(int);//这里可以看成一个返回值 .<br>
再对signal函数进行简化就是这样的了<br>
Sigfunc *signal(int,Sigfuc *);<br>
<br>
<br>
在signal.h头文件中还有以下几个定义<br>
#define SIG_ERR (void (*)())-1<br>
#define SIG_DFL (void (*)())0<br>
#define SIG_IGN (void (*)())1</strong> </font></p>
<p><br>
<font color="#000000" size="2"><strong> 本文来自CSDN博客，转载请标明出处：</strong> </font><a href="http://blog.csdn.net/nevercgoodbye/archive/2008/11/25/3367853.aspx"><font color="#000000" size="2"><strong> http://blog.csdn.net/nevercgoodbye/archive/2008/11/25/3367853.aspx</strong> </font></a></p>
</div>
<p><br></p>
<br><img src ="http://www.cppblog.com/elva/aggbug/123050.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2010-08-11 12:12 <a href="http://www.cppblog.com/elva/archive/2010/08/11/123050.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>gdb多线程调试1</title><link>http://www.cppblog.com/elva/archive/2010/08/02/121940.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Mon, 02 Aug 2010 03:41:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2010/08/02/121940.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/121940.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2010/08/02/121940.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/121940.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/121940.html</trackback:ping><description><![CDATA[<span style="WIDOWS: 2; TEXT-TRANSFORM: none; TEXT-INDENT: 0px; BORDER-COLLAPSE: separate; FONT: medium Simsun; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: rgb(0,0,0); WORD-SPACING: 0px; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class=Apple-style-span><span style="TEXT-ALIGN: left; LINE-HEIGHT: 21px; FONT-FAMILY: verdana, sans-serif; FONT-SIZE: 14px" class=Apple-style-span>
<p style="PADDING-BOTTOM: 0px; MARGIN: 1em 0px 0.5em; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">gdb对于多线程程序的调试有如下的支持：<br>　　<br>　　线程产生通知：在产生新的线程时, gdb会给出提示信息<br>　　(gdb) r<br>　　Starting program: /root/thread&nbsp;<br>　　[New Thread 1073951360 (LWP 12900)]&nbsp;<br>　　[New Thread 1082342592 (LWP 12907)]---以下三个为新产生的线程<br>　　[New Thread 1090731072 (LWP 12908)]<br>　　[New Thread 1099119552 (LWP 12909)]<br>　　<br>　　查看线程：使用info threads可以查看运行的线程。<br>　　(gdb) info threads<br>　　 4 Thread 1099119552 (LWP 12940) 0xffffe002 in ?? ()<br>　　 3 Thread 1090731072 (LWP 12939) 0xffffe002 in ?? ()<br>　　 2 Thread 1082342592 (LWP 12938) 0xffffe002 in ?? ()<br>　　* 1 Thread 1073951360 (LWP 12931) main (argc=1, argv=0xbfffda04) at thread.c:21<br>　　(gdb)&nbsp;<br>　　<br>　　<br>　　注意，行首的蓝色文字为gdb分配的线程号，对线程进行切换时，使用该该号码，而不是上文标出的绿色数字。<br>　　<br>　　另外，行首的红色星号标识了当前活动的线程<br>　　<br>　　切换线程：使用 thread THREADNUMBER 进行切换，THREADNUMBER 为上文提到的线程号。下例显示将活动线程从 1 切换至 4。<br>　　(gdb) info threads<br>　　 4 Thread 1099119552 (LWP 12940) 0xffffe002 in ?? ()<br>　　 3 Thread 1090731072 (LWP 12939) 0xffffe002 in ?? ()<br>　　 2 Thread 1082342592 (LWP 12938) 0xffffe002 in ?? ()<br>　　* 1 Thread 1073951360 (LWP 12931) main (argc=1, argv=0xbfffda04) at thread.c:21<br>　　(gdb) thread 4<br>　　[Switching to thread 4 (Thread 1099119552 (LWP 12940))]#0 0xffffe002 in ?? ()<br>　　(gdb) info threads<br>　　* 4 Thread 1099119552 (LWP 12940) 0xffffe002 in ?? ()<br>　　 3 Thread 1090731072 (LWP 12939) 0xffffe002 in ?? ()<br>　　 2 Thread 1082342592 (LWP 12938) 0xffffe002 in ?? ()<br>　　 1 Thread 1073951360 (LWP 12931) main (argc=1, argv=0xbfffda04) at thread.c:21<br>　　(gdb)&nbsp;<br>　　<br>　　<br>　　 以上即为使用gdb提供的对多线程进行调试的一些基本命令。另外，gdb也提供对线程的断点设置以及对指定或所有线程发布命令的命令。<br>　　<br>　　 初次接触gdb下多线程的调试，往往会忽视gdb中活动线程的概念。一般来讲，在使用gdb调试的时候，只有一个线程为活动线程，如果希望得到其他的线程的输出结果，必须使用thread命令切换至指定的线程，才能对该线程进行调试或观察输出结果。</p>
</span></span><br class=Apple-interchange-newline>
<img src ="http://www.cppblog.com/elva/aggbug/121940.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2010-08-02 11:41 <a href="http://www.cppblog.com/elva/archive/2010/08/02/121940.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>time命令详解</title><link>http://www.cppblog.com/elva/archive/2009/09/21/96829.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Mon, 21 Sep 2009 02:43:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2009/09/21/96829.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/96829.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2009/09/21/96829.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/96829.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/96829.html</trackback:ping><description><![CDATA[<span class=Apple-style-span style="WORD-SPACING: 0px; FONT: 16px simsun; TEXT-TRANSFORM: none; COLOR: rgb(0,0,0); TEXT-INDENT: 0px; WHITE-SPACE: normal; LETTER-SPACING: normal; BORDER-COLLAPSE: separate; orphans: 2; widows: 2; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px"><span class=Apple-style-span style="FONT-SIZE: 14px; COLOR: rgb(83,66,59); LINE-HEIGHT: 20px; FONT-FAMILY: Arial; -webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px">
<p style="TEXT-INDENT: 0pt; LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" size=3><span style="LINE-HEIGHT: normal">【命令】time — 执行命令并计时</span></font></p>
<p style="TEXT-INDENT: 0pt; LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" size=3><span style="LINE-HEIGHT: normal">【格式】time [-p] command [arguments...]</span></font></p>
<p style="TEXT-INDENT: 0pt; LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" size=3><span style="LINE-HEIGHT: normal">【说明】</span></font></p>
<p style="TEXT-INDENT: 20pt; LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" size=3>执行命令行"command [arguments...]"，命令行执行结束时在标准输出中打印执行该命令行的时间统计结果，其统计结果包含以下数据：</font></p>
<p style="TEXT-INDENT: 20pt; LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" size=3>1)实际时间(real time): 从command命令行开始执行到运行终止的消逝时间；</font></p>
<p style="TEXT-INDENT: 20pt; LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" size=3>2)用户CPU时间(user CPU time): 命令执行完成花费的用户CPU时间，即命令在用户态中执行时间总和；</font></p>
<p style="TEXT-INDENT: 20pt; LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" size=3>3)系统CPU时间(system CPU time): 命令执行完成花费的系统CPU时间，即命令在核心态中执行时间总和。</font></p>
<p style="TEXT-INDENT: 20pt; LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" size=3>其中，用户CPU时间和系统CPU时间之和为CPU时间，即命令占用CPU执行的时间总和。实际时间要大于CPU时间，因为Linux是多任务操作系统，往往在执行一条命令时，系统还要处理其它任务。</font></p>
<p style="TEXT-INDENT: 20pt; LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" size=3>另一个需要注意的问题是即使每次执行相同命令，但所花费的时间也是不一样，其花费时间是与系统运行相关的。</font></p>
<p style="TEXT-INDENT: 20pt; LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" size=3>例1：</font></p>
<p style="LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" size=3>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1. # time date<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2. Sun Mar 26 22:45:34 GMT-8 2006<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.<span class=Apple-converted-space>&nbsp;</span><br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4. real&nbsp;&nbsp;&nbsp; 0m0.136s<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5. user&nbsp;&nbsp;&nbsp; 0m0.010s<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6. sys&nbsp;&nbsp;&nbsp;&nbsp; 0m0.070s<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 7. #<br style="LINE-HEIGHT: normal"></font></p>
<p style="TEXT-INDENT: 20pt; LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" size=3>在例1中，执行命令"time date"(见第1行)。系统先执行命令"date"，第2行为命令"date"的执行结果。第3-6行为执行命令"date"的时间统计结果，其中第4 行"real"为实际时间，第5行"user"为用户CPU时间，第6行"sys"为系统CPU时间。以上三种时间的显示格式均为 MMmNN[.FFF]s。</font></p>
<p style="TEXT-INDENT: 20pt; LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" size=3>在例1中，CPU时间 = 用户CPU时间 + 系统CPU时间 = 0m0.010s + 0m0.070s = 0m0.080s，实际时间大于CPU时间，说明在date命令运行的同时，还有其它任务在运行。</font></p>
<p style="TEXT-INDENT: 0pt; LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" size=3><span style="LINE-HEIGHT: normal">【参数说明】</span></font></p>
<p style="TEXT-INDENT: 20pt; LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" size=3>-p 以POSIX缺省的时间格式打印时间统计结果，单位为秒。详细的输出格式见例2。</font></p>
<p style="TEXT-INDENT: 20pt; LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" size=3>例2：</font></p>
<font style="LINE-HEIGHT: normal" size=3>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1. # time -p date<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2. Wed Mar 27 00:33:11 GMT-8 2006<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3. real 0.11<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4. user 0.00<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5. sys 0.02<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6. #<br style="LINE-HEIGHT: normal"></font>
<p style="TEXT-INDENT: 20pt; LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" size=3>在例2中，同样执行命令"time date"(见第1行)。系统先执行命令 "date"，第2行为该命令的执行结果。第3-5行为执行命令"date"的时间统计结果。注意本例的时间格式与例1中的时间格式差别，使用-p 参数后的时间显示格式为NN.FF，其单位为秒。</font></p>
<p style="TEXT-INDENT: 0pt; LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" size=3><span style="LINE-HEIGHT: normal">【相关环境变量说明】</span></font></p>
<p style="TEXT-INDENT: 20pt; LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" size=3>TIMEFORMAT 自定义输出的时间格式。</font></p>
<p style="TEXT-INDENT: 20pt; LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" size=3>我们也可以通过环境变量TIMEFORMAT来自定义输出的时间格式[1]。格式中使用和标准C中的函数printf一致的转义符，以及使用以下的转义序列来指定输出的时间格式：</font></p>
<div class=blogstory style="FONT-SIZE: 12px; FILTER: none; VISIBILITY: visible! important; WORD-BREAK: break-all; LINE-HEIGHT: normal; ZOOM: 1! important; FONT-FAMILY: Arial; WORD-WRAP: break-word"><xmp style="LINE-HEIGHT: normal">&lt;font size=&quot;3&quot;&gt; %[prec][l][RUS]&lt;br&gt;&lt;/font&gt;</xmp>
<p style="TEXT-INDENT: 20pt; LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" size=3>其中，选项prec为指定时间精度，即小数点后面的位数；选项l表示使用分秒(具体格式为：MMmNN[.FFF]s)的格式；最后一个字符表示时间的类型，其中R表示实际时间，U表示用户CPU时间，S表示系统CPU 时间，它们的单位均为秒。</font></p>
<p style="TEXT-INDENT: 20pt; LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" size=3>time命令缺省输出的时间格式同 TIMEFORMAT=$'\nreal\t%3lR\nuser\t%3lU\nsys\t%3lS'。</font></p>
<p style="TEXT-INDENT: 20pt; LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" size=3>使用-p参数的time命令输出的时间格式同 TIMEFORMAT=$'real %2R\nuser %2U\nsys %2S'。</font></p>
<p style="TEXT-INDENT: 20pt; LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" size=3>例3：</font></p>
<font style="LINE-HEIGHT: normal" size=3>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1. # export TIMEFORMAT=$'real %2R\nuser %2U\nsys %2S'<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2. # time date<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3. Wed Mar 27 00:52:03 GMT-8 2006<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4. real 0.04<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5. user 0.00<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6. sys 0.01<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 7. #<br style="LINE-HEIGHT: normal"></font>
<p style="TEXT-INDENT: 20pt; LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" size=3>比较例2和例3显示结果，很容易发现例3虽然没有使用参数-p，但其输出的结果和例2一模一样。</font></p>
<p style="TEXT-INDENT: 20pt; LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" size=3>当然，我们也可以修改为任何自己喜欢的时间格式。</font></p>
<p style="TEXT-INDENT: 20pt; LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" size=3>例4：</font></p>
<font style="LINE-HEIGHT: normal" size=3>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1. # export TIMEFORMAT=$'\nHello, ThinkerABC!\nreal time :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %lR\nuser CUP time :&nbsp;&nbsp; %lU\nsystem CPU time : %lS'<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2. # time date<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3. Wed Mar 27 01:09:26 GMT-8 2006<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4.<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5. Hello, ThinkerABC!<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6. real time :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0m0.016s<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 7. user CUP time :&nbsp;&nbsp; 0m0.006s<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8. system CPU time : 0m0.008s<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 9. #<br style="LINE-HEIGHT: normal"></font>
<p style="TEXT-INDENT: 20pt; LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" size=3>例4的第4-8行正是我们自定义的输出格式。</font></p>
<p style="TEXT-INDENT: 20pt; LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" size=3>从以上介绍了三种指定时间格式的方法，即缺省的时间格式、使用参数-p的POSIX缺省的时间格式和设定环境变量TIMEFORMAT自定义的时间格式，Linux系统使用的先后顺序如下：</font></p>
<p style="TEXT-INDENT: 20pt; LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" size=3>1.参数-p的POSIX缺省时间格式；</font></p>
<p style="TEXT-INDENT: 20pt; LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" size=3>2.环境变量TIMEFORMAT自定义的时间格式；</font></p>
<p style="TEXT-INDENT: 20pt; LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" size=3>3.缺省的时间格式。</font></p>
<p style="TEXT-INDENT: 0pt; LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" size=3><span style="LINE-HEIGHT: normal">【退出状态说明】</span></font></p>
<p style="TEXT-INDENT: 20pt; LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" size=3>如果能执行command命令，则返回该命令的退出状态，否则返回如下的退出状态值：</font></p>
<p style="TEXT-INDENT: 20pt; LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" size=3>127 命令未找到</font></p>
<p style="TEXT-INDENT: 20pt; LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" size=3>126 命令找到，但不能执行</font></p>
<p style="TEXT-INDENT: 20pt; LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" size=3>1-125 其它错误</font></p>
</div>
</span></span>
<img src ="http://www.cppblog.com/elva/aggbug/96829.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2009-09-21 10:43 <a href="http://www.cppblog.com/elva/archive/2009/09/21/96829.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在Debian中打造属于自己的deb包</title><link>http://www.cppblog.com/elva/archive/2009/08/25/94373.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Tue, 25 Aug 2009 08:03:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2009/08/25/94373.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/94373.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2009/08/25/94373.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/94373.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/94373.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 问题：如果你要在Debian系统中发布一款软件或者一个包，该如何做呢？如果你的项目中有各种二进制包，该如何维护呢？如果你自己做了一款小小的实用软件，该如何与朋友分享呢？&#8230;&#8230;.&nbsp;&nbsp;案例：假如我从网上下载了eclipse-SDK-3.1-linux-gtk.tar.gz压缩文件，我想把他安装到/opt/eclipse目录下，且菜单Apps--&gt;...&nbsp;&nbsp;<a href='http://www.cppblog.com/elva/archive/2009/08/25/94373.html'>阅读全文</a><img src ="http://www.cppblog.com/elva/aggbug/94373.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2009-08-25 16:03 <a href="http://www.cppblog.com/elva/archive/2009/08/25/94373.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> [Pthread] Linux程序调试的基石(二)--Inside GDB </title><link>http://www.cppblog.com/elva/archive/2009/07/25/91148.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Sat, 25 Jul 2009 09:56:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2009/07/25/91148.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/91148.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2009/07/25/91148.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/91148.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/91148.html</trackback:ping><description><![CDATA[3. GDB的实现<br>GDB是GNU发布的一个强大的程序调试工具，用以调试C/C++程序。可以使程序员在程序运行的时候观察程序在内存/寄存器中的使用情况。它的实现也是基于ptrace系统调用来完成的。<br>其
原理是利用ptrace系统调用，在被调试程序和gdb之间建立跟踪关系。然后所有发送给被调试程序的信号(除SIGKILL)都会被gdb截获，gdb
根据截获的信号，查看被调试程序相应的内存地址，并控制被调试的程序继续运行。GDB常用的使用方法有断点设置和单步跟踪，接下来我们来分析一下他们是如
何实现的。<br><br>3.1 建立调试关系<br>用gdb调试程序，可以直接gdb ./test,也可以gdb &lt;pid&gt;(test的进程号)。这对应着使用ptrace建立跟踪关系的两种方式:<br>1)fork: 利用fork+execve执行被测试的程序，子进程在执行execve之前调用ptrace(PTRACE_TRACEME)，建立了与父进程(debugger)的跟踪关系。如我们在分析strace时所示意的程序。<br>2)attach:
debugger可以调用ptrace(PTRACE_ATTACH，pid,...)，建立自己与进程号为pid的进程间的跟踪关系。即利用
PTRACE_ATTACH，使自己变成被调试程序的父进程(用ps可以看到)。用attach建立起来的跟踪关系，可以调用ptrace
(PTRACE_DETACH，pid,...)来解除。注意attach进程时的权限问题，如一个非root权限的进程是不能attach到一个
root进程上的。<br><br>3.2 断点原理<br>断点是大家在调试程序时常用的一个功能,如break linenumber，当执行到linenumber那一行的时候被调试程序会停止，等待debugger的进一步操作。 <br>断点的实现原理，就是在指定的位置插入断点指令，当被调试的程序运行到断点的时候，产生SIGTRAP信号。该信号被gdb捕获并进行断点命中判定，当gdb判断出这次SIGTRAP是断点命中之后就会转入等待用户输入进行下一步处理，否则继续。<br>断点的设置原理: 在程序中设置断点，就是先将该位置的原来的指令保存，然后向该位置写入int 3。当执行到int 3的时候，发生软中断，内核会给子进程发出SIGTRAP信号，当然这个信号会被转发给父进程。然后用保存的指令替换int3,等待恢复运行。<br>断点命中判定:gdb把所有的断点位置都存放在一个链表中，命中判定即把被调试程序当前停止的位置和链表中的断点位置进行比较，看是断点产生的信号，还是无关信号。<br><br>3.3 单步跟踪原理<br>单步跟踪就是指在调试程序的时候，让程序运行一条指令/语句后就停下。GDB中常用的命令有next, step, nexti, stepi。单步跟踪又常分为语句单步(next, step)和指令单步(如nexti, stepi)。<br><br>在linux上，指令单步可以通过ptrace来实现。调用ptrace(PTRACE_SINGLESTEP,pid,...)可以使被调试的进程在每执行完一条指令后就触发一个SIGTRAP信号，让GDB运行。下面来看一个例子:<br>&nbsp;&nbsp;&nbsp; child = fork();<br>&nbsp;&nbsp;&nbsp; if(child == 0) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; execl("./HelloWorld", "HelloWorld", NULL);<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; else {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ptrace(PTRACE_ATTACH,child,NULL,NULL);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while(1){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wait(&amp;val);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(WIFEXITED(val))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; count++;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ptrace(PTRACE_SINGLESTEP,child,NULL,NULL);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; printf("Total Instruction number= %d\n",count);<br>&nbsp;&nbsp;&nbsp; }<br>这
段程序比较简单，子进程调用execve执行HelloWorld,而父进程则先调用ptrace(PTRACE_ATTACH,pid,...)建立与
子进程的跟踪关系。然后调用ptrace(PTRACE_SINGLESTEP, pid,
...)让子进程一步一停，以统计子进程一共执行了多少条指令(你会发现一个简单的HelloWorld实际上也执行了好几万条指令才完成)。当然你也完
全可以在这个时候查看EIP寄存器中存放的指令，或者某个变量的值，当然前提是你得知道这个变量在子进程内存镜像中的位置。<br>指令单步可以依靠硬件
完成，如x86架构处理器支持单步模式(通过设置EFLAGS寄存器的TF标志实现)，每执行一条指令，就会产生一次异常(在Intel
80386以上的处理器上还提供了DRx调试寄存器以用于软件调试)。也可以通过软件完成，即在每条指令后面都插入一条断点指令，这样每执行一条指令都会
产生一次软中断。<br>语句单步基于指令单步实现，即GDB算好每条语句所对应的指令，从什么地方开始到什么地方结束。然后在结束的地方插入断点，或者指令单步一步一步的走到结束点，再进行处理。<br><br>当
然gdb的实现远比今天我们所说的内容要复杂，它能让我们很容易的监测，修改被调试的进程，比如通过行号，函数名，变量名。而要真正实现这些，一是需要在
编译的时候提供足够的信息，如在gcc时加入-g选项，这样gcc会把一些程序信息放到生成的ELF文件中，包括函数符号表，行号，变量信息，宏定义等，
以便日后gdb调试，当然生成的文件也会大一些。二是需要我们对ELF文件格式，进程的内存镜像(布局)以及程序的指令码十分熟悉。这样才能保证在正确的
时机(断点发生？单步？)找到正确的内存地址(代码？数据？)并链接回正确的程序代码(这是哪个变量？程序第几行？)。感兴趣的同学可以找到相应的代码仔
细分析一下。<br><br>小结:<br>ptrace可以实时监测和修改另一个进程的运行，它是如此的强大以至于曾经因为它在unix-like平台
(如Linux,
*BSD)上产生了各种漏洞。但换言之，只要我们能掌握它的使用，就能开发出很多以前在用户态下不可能实现的应用。当然这可能需要我们掌握编译，文件格
式，程序内存布局等相当多的底层知识。<br><br>最后让我们来回顾一下ptrace的使用:<br>1)用PTRACE_ATTACH或者PTRACE_TRACEME 建立进程间的跟踪关系。<br>2)PTRACE_PEEKTEXT, PTRACE_PEEKDATA, PTRACE_PEEKUSR等读取子进程内存/寄存器中保留的值。<br>3)PTRACE_POKETEXT, PTRACE_POKEDATA, PTRACE_POKEUSR等把值写入到被跟踪进程的内存/寄存器中。<br>4)用PTRACE_CONT，PTRACE_SYSCALL, PTRACE_SINGLESTEP控制被跟踪进程以何种方式继续运行。<br>5)PTRACE_DETACH, PTRACE_KILL 脱离进程间的跟踪关系。<br><br>TIPS:<br>&nbsp;&nbsp;&nbsp; 1. 进程状态TASK_TRACED用以表示当前进程因为被父进程跟踪而被系统停止。<br>&nbsp;&nbsp;&nbsp; 2. 如在子进程结束前，父进程结束，则trace关系解除。<br>&nbsp;&nbsp;&nbsp; 3. 利用attach建立起来的跟踪关系，虽然ps看到双方为父子关系，但在"子进程"中调用getppid()仍会返回原来的父进程id。<br>&nbsp;&nbsp;&nbsp; 4. 不能attach到自己不能跟踪的进程，如non-root进程跟踪root进程。<br>&nbsp;&nbsp;&nbsp; 5. 已经被trace的进程，不能再次被attach。<br>&nbsp;&nbsp;&nbsp; 6. 即使是用PTRACE_TRACEME建立起来的跟踪关系，也可以用DETACH的方式予以解除。<br>&nbsp;&nbsp;&nbsp; 7. 因为进入/退出系统调用都会触发一次SIGTRAP，所以通常的做法是在第一次(进入)的时候读取系统调用的参数，在第二次(退出)的时候读取系统调用的返回值。但注意execve是个例外。<br>&nbsp;&nbsp;&nbsp; 8. 程序调试时的断点由int 3设置完成，而单步跟踪则可由ptrace(PTRACE_SINGLESTEP)实现。<br>&nbsp;&nbsp;&nbsp; <br>Pthread 08/01/14<br><br>原文地址：http://blog.csdn.net/Javadino/archive/2008/09/06/2891434.aspx<br><img src ="http://www.cppblog.com/elva/aggbug/91148.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2009-07-25 17:56 <a href="http://www.cppblog.com/elva/archive/2009/07/25/91148.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> [Pthread] Linux上程序调试的基石(一)--ptrace</title><link>http://www.cppblog.com/elva/archive/2009/07/25/91147.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Sat, 25 Jul 2009 09:55:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2009/07/25/91147.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/91147.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2009/07/25/91147.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/91147.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/91147.html</trackback:ping><description><![CDATA[引子:<br>1.在Linux系统中，进程状态除了我们所熟知的TASK_RUNNING，TASK_INTERRUPTIBLE，TASK_STOPPED等，还有一个TASK_TRACED。这表明这个进程处于什么状态？<br>2.strace可以方便的帮助我们记录进程所执行的系统调用，它是如何跟踪到进程执行的？<br>3.gdb是我们调试程序的利器，可以设置断点，单步跟踪程序。它的实现原理又是什么？<br><br>所有这一切的背后都隐藏着Linux所提供的一个强大的系统调用ptrace().<br><br>1.ptrace系统调用<br>ptrace
系统调从名字上看是用于进程跟踪的，它提供了父进程可以观察和控制其子进程执行的能力，并允许父进程检查和替换子进程的内核镜像(包括寄存器)的值。其基
本原理是:
当使用了ptrace跟踪后，所有发送给被跟踪的子进程的信号(除了SIGKILL)，都会被转发给父进程，而子进程则会被阻塞，这时子进程的状态就会被
系统标注为TASK_TRACED。而父进程收到信号后，就可以对停止下来的子进程进行检查和修改，然后让子进程继续运行。&nbsp;&nbsp; &nbsp;<br>&nbsp;&nbsp; &nbsp;其原型为：&nbsp;&nbsp; &nbsp;<br>&nbsp;&nbsp; &nbsp;#include &lt;sys/ptrace.h&gt;<br>&nbsp;&nbsp; &nbsp;long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);<br>&nbsp;&nbsp; &nbsp;ptrace有四个参数: <br>&nbsp;&nbsp; &nbsp;1). enum __ptrace_request request：指示了ptrace要执行的命令。<br>&nbsp;&nbsp; &nbsp;2). pid_t pid: 指示ptrace要跟踪的进程。<br>&nbsp;&nbsp; &nbsp;3). void *addr: 指示要监控的内存地址。<br>&nbsp;&nbsp; &nbsp;4). void *data: 存放读取出的或者要写入的数据。<br>ptrace是如此的强大，以至于有很多大家所常用的工具都基于ptrace来实现，如strace和gdb。接下来，我们借由对strace和gdb的实现，来看看ptrace是如何使用的。<br><br>2. strace的实现<br>strace常常被用来拦截和记录进程所执行的系统调用，以及进程所收到的信号。如有这么一段程序：<br>HelloWorld.c:<br>#include &lt;stdio.h&gt;<br>int main(){<br>&nbsp;&nbsp;&nbsp; printf("Hello World!\n");<br>&nbsp;&nbsp;&nbsp; return 0;<br>}<br>编译后，用strace跟踪： strace ./HelloWorld<br>可以看到形如:<br>execve("./HelloWorld", ["./HelloWorld"], [/* 67 vars */]) = 0<br>brk(0)&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; = 0x804a000<br>mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f18000<br>access("/etc/ld.so.preload", R_OK)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = -1 ENOENT (No such file or directory)<br>open("/home/supperman/WorkSpace/lib/tls/i686/sse2/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)<br>...<br>的一段输出，这就是在执行HelloWorld中，系统所执行的系统调用，以及他们的返回值。<br><br>下面我们用ptrace来研究一下它是怎么实现的。<br>...<br>&nbsp;&nbsp;&nbsp; switch(pid = fork())<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp; case -1:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<br>&nbsp;&nbsp;&nbsp; case 0: //子进程<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ptrace(PTRACE_TRACEME,0,NULL,NULL);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; execl("./HelloWorld", "HelloWorld", NULL);<br>&nbsp;&nbsp;&nbsp; default: //父进程<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wait(&amp;val); //等待并记录execve<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(WIFEXITED(val))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; syscallID=ptrace(PTRACE_PEEKUSER, pid, ORIG_EAX*4, NULL);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf("Process executed system call ID = %ld\n",syscallID);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ptrace(PTRACE_SYSCALL,pid,NULL,NULL);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while(1)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wait(&amp;val); //等待信号<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(WIFEXITED(val)) //判断子进程是否退出<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(flag==0) //第一次(进入系统调用)，获取系统调用的参数<br>&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; syscallID=ptrace(PTRACE_PEEKUSER, pid, ORIG_EAX*4, NULL);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf("Process executed system call ID = %ld ",syscallID);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; flag=1;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else //第二次(退出系统调用)，获取系统调用的返回值<br>&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; returnValue=ptrace(PTRACE_PEEKUSER, pid, EAX*4, NULL);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf("with return value= %ld\n", returnValue);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; flag=0;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ptrace(PTRACE_SYSCALL,pid,NULL,NULL);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>...<br><br>在
上面的程序中，fork出的子进程先调用了ptrace(PTRACE_TRACEME)表示子进程让父进程跟踪自己。然后子进程调用execl加载执行
了HelloWorld。而在父进程中则使用wait系统调用等待子进程的状态改变。子进程因为设置了PTRACE_TRACEME而在执行系统调用被系
统停止(设置为TASK_TRACED)，这时父进程被唤醒，使用ptrace(PTRACE_PEEKUSER,pid,...)分别去读取子进程执行
的系统调用ID(放在ORIG_EAX中)以及系统调用返回时的值(放在EAX中)。然后使用ptrace(PTRACE_SYSCALL,
pid,...)指示子进程运行到下一次执行系统调用的时候(进入或者退出)，直到子进程退出为止。<br><br>程序的执行结果如下:<br>Process executed system call ID = 11<br>Process executed system call ID = 45 with return value= 134520832<br>Process executed system call ID = 192 with return value= -1208934400<br>Process executed system call ID = 33 with return value= -2<br>Process executed system call ID = 5 with return value= -2<br>...<br>其
中，11号系统调用就是execve，45号是brk,192是mmap2,33是access,5是open...经过比对可以发现，和strace的
输出结果一样。当然strace进行了更详尽和完善的处理，我们这里只是揭示其原理，感兴趣的同学可以去研究一下strace的实现。<br><br>PS: <br>&nbsp;&nbsp; &nbsp;1). 在系统调用执行的时候，会执行pushl %eax # 保存系统调用号ORIG_EAX在程序用户栈中。<br>&nbsp;&nbsp; &nbsp;2). 在系统调用返回的时候，会执行movl %eax,EAX(%esp)将系统调用的返回值放入寄存器%eax中。<br>&nbsp;&nbsp; &nbsp;3). WIFEXITED()宏用来判断子进程是否为正常退出的，如果是，它会返回一个非零值。<br>&nbsp;&nbsp; &nbsp;4). 被跟踪的程序在进入或者退出某次系统调用的时候都会触发一个SIGTRAP信号，而被父进程捕获。<br>&nbsp;&nbsp; &nbsp;5). execve()系统调用执行成功的时候并没有返回值，因为它开始执行一段新的程序，并没有"返回"的概念。失败的时候会返回-1。<br>&nbsp;&nbsp; &nbsp;6). 在父进程进行进行操作的时候，用ps查看，可以看到子进程的状态为T,表示子进程处于TASK_TRACED状态。当然为了更具操作性，你可以在父进程中加入sleep()。<br><br>(To Be Continued)<br><br>Pthread&nbsp; 08/01/13<br><br>原文地址：http://blog.csdn.net/Javadino/archive/2008/09/06/2891413.aspx<br><img src ="http://www.cppblog.com/elva/aggbug/91147.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2009-07-25 17:55 <a href="http://www.cppblog.com/elva/archive/2009/07/25/91147.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Ptrace及其命令</title><link>http://www.cppblog.com/elva/archive/2009/07/25/91146.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Sat, 25 Jul 2009 09:52:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2009/07/25/91146.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/91146.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2009/07/25/91146.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/91146.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/91146.html</trackback:ping><description><![CDATA[<p class="MsoNormal" style="text-indent: 21pt;"><span style="font-family: 宋体;">在用户模式中，虽然只有一个函数可用，即</span><span style="font-family: &quot;courier new&quot;;" lang="EN-US">ptrace(int _request, pid_t _pid, caddr_t _addr, int _data)</span><span style="font-family: 宋体;">，但是这个函数能做所有的事情！如果你愿意，也可以花费几个小时来编写自己的小调试器，以解决特定的问题。</span></p>
<p class="MsoNormal" style="text-indent: 21pt;"><span style="font-family: &quot;courier new&quot;;" lang="EN-US">ptrace</span><span style="font-family: 宋体;">函数的</span><span style="font-family: &quot;courier new&quot;;" lang="EN-US">_request</span><span style="font-family: 宋体;">参数是最重要的一个参数，因为它确定你将做什么。</span><span lang="EN-US">BSD</span><span style="font-family: 宋体;">和</span><span lang="EN-US">Linux</span><span style="font-family: 宋体;">的头文件使用不同的定义，这使得将</span><span lang="EN-US">ptrace</span><span style="font-family: 宋体;">应用从一个平台移植到另一个平台变得很复杂。默认地，我们使用</span><span lang="EN-US">BSD</span><span style="font-family: 宋体;">头文件中的定义。</span></p>
<p class="MsoNormal" style="margin: 6pt 0cm 0pt 36.35pt; text-indent: -15.35pt;"><span style="font-family: wingdings;" lang="EN-US">r</span><span style="font-size: 5pt;" lang="EN-US">&nbsp; </span><strong><span style="font-family: &quot;courier new&quot;;" lang="EN-US">PT_TRACE_ME</span></strong><span style="font-family: 宋体;">（</span><span style="font-family: &quot;courier new&quot;;" lang="EN-US">PTRACE_TRACEME</span><span style="font-family: 宋体;">）将当前进程切换到停止状态。它通常总是与</span><span style="font-family: &quot;courier new&quot;;" lang="EN-US">fork/exec</span><span style="font-family: 宋体;">一起使用，虽然也能遇到自我追踪的应用程序。对于每一个进程，</span><span style="font-family: &quot;courier new&quot;; letter-spacing: 0.1pt;" lang="EN-US">PT_TRACE_ME</span><span style="font-family: 宋体; letter-spacing: 0.1pt;">只能被调用一次。追踪一个正被追踪的进程是会失败的（另一个较不重要的结果是进程不能追踪它自己。如果要这样做，应该首先从自身派生一个进程）。大量的反调试技术都是以这一事实为基础的。为了克服这类技术，必须使用绕过</span><span style="font-family: &quot;courier new&quot;; letter-spacing: 0.1pt;" lang="EN-US">ptrace</span><span style="font-family: 宋体; letter-spacing: 0.1pt;">的调试器。一个信号被发送到正被调试的进程，并将该进程切换到停止状态，该进程可以使用从父进程上下文中调用的</span><span style="font-family: &quot;courier new&quot;; letter-spacing: 0.1pt;" lang="EN-US">PT_CONTINUE</span><span style="font-family: 宋体; letter-spacing: 0.1pt;">和</span><span style="font-family: &quot;courier new&quot;;" lang="EN-US">PT_STEP</span><span style="font-family: 宋体;">命令从停止状态退出。</span><span style="font-family: &quot;courier new&quot;;" lang="EN-US">wait</span><span style="font-family: 宋体;">函数会延迟父进程的执行，直到被调试的进程切换为停止状态或者终止为止（终止时，返回值为</span><span style="font-family: &quot;courier new&quot;;" lang="EN-US">1407</span><span style="font-family: 宋体;">）。其他的所有参数<span style="letter-spacing: 0.1pt;">都被忽略。</span></span></p>
<p class="MsoNormal" style="margin-left: 36.35pt; text-indent: -15.35pt;"><span style="font-family: wingdings;" lang="EN-US">r</span><span style="font-size: 5pt;" lang="EN-US">&nbsp; </span><strong><span style="font-family: &quot;courier new&quot;;" lang="EN-US">PT_ATTACH</span></strong><span style="font-family: 宋体;">（</span><span style="font-family: &quot;courier new&quot;;" lang="EN-US">PTRACE_ATTACH</span><span style="font-family: 宋体;">）</span><span style="font-family: 宋体;">将进程标志为</span><span style="font-family: &quot;courier new&quot;;" lang="EN-US">pid</span><span style="font-family: 宋体;">的运行进程切换为停止状态，在这种情形下，调试器进程成为&#8220;父进程&#8221;。其他的所有参数都被忽略。进程必须具有与调试进程相同的用户标志（</span><span lang="EN-US">UID</span><span style="font-family: 宋体;">），并且不能是</span><span style="font-family: &quot;courier new&quot;;" lang="EN-US">setuid/setduid</span><span style="font-family: 宋体;">进程（否则就要用</span><span style="font-family: &quot;courier new&quot;;" lang="EN-US">root</span><span style="font-family: 宋体;">来调试）。</span></p>
<p class="MsoNormal" style="margin-left: 36.35pt; text-indent: -15.35pt;"><span style="font-family: wingdings;" lang="EN-US">r</span><span style="font-size: 5pt;" lang="EN-US">&nbsp; </span><strong><span style="font-family: &quot;courier new&quot;; letter-spacing: 0.2pt;" lang="EN-US">PT_DETACH</span></strong><span style="font-family: 宋体; letter-spacing: 0.2pt;">（</span><span style="font-family: &quot;courier new&quot;; letter-spacing: 0.2pt;" lang="EN-US">PTRACE_DETACH</span><span style="font-family: 宋体; letter-spacing: 0.2pt;">）</span><span style="font-family: 宋体; letter-spacing: 0.2pt;">停止进程标志为</span><span style="font-family: &quot;courier new&quot;; letter-spacing: 0.2pt;" lang="EN-US">pid</span><span style="font-family: 宋体; letter-spacing: 0.2pt;">进程（由</span><span style="font-family: &quot;courier new&quot;; letter-spacing: 0.2pt;" lang="EN-US">PT_ATTACH</span><span style="font-family: 宋体; letter-spacing: 0.2pt;">和</span><span style="font-family: &quot;courier new&quot;; letter-spacing: 0.2pt;" lang="EN-US">PT_TRACE_ME</span><span style="font-family: 宋体; letter-spacing: 0.2pt;">指定）的调试，并继续其常态运行。其他的所有参数都被忽略。</span></p>
<p class="MsoNormal" style="margin-left: 36.35pt; text-indent: -15.35pt;"><span style="font-family: wingdings;" lang="EN-US">r</span><span style="font-size: 5pt;" lang="EN-US">&nbsp; </span><strong><span style="font-family: &quot;courier new&quot;;" lang="EN-US">PT_CONTINUE</span></strong><span style="font-family: 宋体;">（</span><span style="font-family: &quot;courier new&quot;;" lang="EN-US">PTRACE_CONT</span><span style="font-family: 宋体;">）</span><span style="font-family: 宋体;">继续进程标志为</span><span style="font-family: &quot;courier new&quot;;" lang="EN-US">pid</span><span style="font-family: 宋体;">的被调试进程的执行，而不中断与调试器进程的通信。如果</span><span style="font-family: &quot;courier new&quot;;" lang="EN-US">addr </span><span style="font-family: 宋体;">＝＝</span><span style="font-family: &quot;courier new&quot;;" lang="EN-US"> 1</span><span style="font-family: 宋体;">（在</span><span lang="EN-US">Linux</span><span style="font-family: 宋体;">中为</span><span lang="EN-US">0</span><span style="font-family: 宋体;">），从上次停止的地址继续执行；否则，从指定的地址继续执行。参数</span><span lang="EN-US">_data</span><span style="font-family: 宋体;">指定发送到被调试进程的信号数量（零说明没有信号）。</span></p>
<p class="MsoNormal" style="margin-left: 36.35pt; text-indent: -15.35pt;"><span style="font-family: wingdings;" lang="EN-US">r</span><span style="font-size: 5pt;" lang="EN-US">&nbsp; </span><strong><span style="font-family: &quot;courier new&quot;;" lang="EN-US">PT_STEP</span></strong><span style="font-family: 宋体;">（</span><span style="font-family: &quot;courier new&quot;;" lang="EN-US">PTRACE_SINGLESTEP</span><span style="font-family: 宋体;">）</span><span style="font-family: 宋体;">进行进程标志为</span><span lang="EN-US">pid</span><span style="font-family: 宋体;">的进程的单步执行，即执行下一条机器指令并切换为停止状态（在</span><span lang="EN-US">i386</span><span style="font-family: 宋体;">中，这是根据设置追踪标志来实现<span style="letter-spacing: -0.1pt;">的，虽然</span></span><span style="font-family: 宋体; letter-spacing: -0.1pt;">有些</span><span style="font-family: 宋体; letter-spacing: -0.1pt;">&#8220;黑客&#8221;函数库使用硬件断点）。</span><span style="letter-spacing: -0.1pt;" lang="EN-US">BSD</span><span style="font-family: 宋体; letter-spacing: -0.1pt;">要求将参数</span><span style="letter-spacing: -0.1pt;" lang="EN-US">addr</span><span style="font-family: 宋体; letter-spacing: -0.1pt;">置为</span><span style="letter-spacing: -0.1pt;" lang="EN-US">1</span><span style="font-family: 宋体; letter-spacing: -0.1pt;">，而</span><span style="letter-spacing: -0.1pt;" lang="EN-US">Linux</span><span style="font-family: 宋体;">要求将该参数置为</span><span lang="EN-US">0</span><span style="font-family: 宋体;">。其他的所有参数都被忽略。</span></p>
<p class="MsoNormal" style="margin-left: 36.35pt; text-indent: -15.35pt; line-height: 16pt;"><span style="font-family: wingdings;" lang="EN-US">r</span><span style="font-size: 5pt;" lang="EN-US">&nbsp; </span><strong><span style="font-family: &quot;courier new&quot;;" lang="EN-US">PT_READ_I</span></strong><span style="font-family: 宋体;">和</span><strong><span style="font-family: &quot;courier new&quot;;" lang="EN-US">PT_READ_D</span></strong><span style="font-family: 宋体;">（</span><span style="font-family: &quot;courier new&quot;;" lang="EN-US">PTRACE_PEEKTEXT</span><span style="font-family: 宋体;">和</span><span style="font-family: &quot;courier new&quot;;" lang="EN-US">PTRACE_PEEKDATA</span><span style="font-family: 宋体;">）分别从代码区和正</span><span style="font-family: 宋体;">被</span><span style="font-family: 宋体;">调试进程的地址空间区读取机器字。在许多当代的平台中，这两个指令是等价的。</span><span style="font-family: &quot;courier new&quot;;" lang="EN-US">ptrace</span><span style="font-family: 宋体;">函数接收目标地址</span><span style="font-family: &quot;courier new&quot;;" lang="EN-US">addr</span><span style="font-family: 宋体;">，并返回读到的结果。</span></p>
<p class="MsoNormal" style="margin-left: 36.35pt; text-indent: -15.35pt; line-height: 16pt;"><span style="font-family: wingdings;" lang="EN-US">r</span><span style="font-size: 5pt;" lang="EN-US">&nbsp; </span><strong><span style="font-family: &quot;courier new&quot;;" lang="EN-US">PT_WRITE_I</span></strong><span style="font-family: 宋体;">和</span><strong><span style="font-family: &quot;courier new&quot;;" lang="EN-US">PR_READ_D</span></strong><span style="font-family: 宋体;">（</span><span style="font-family: &quot;courier new&quot;;" lang="EN-US">PTRACE_POKETEXT</span><span style="font-family: 宋体;">和</span><span style="font-family: &quot;courier new&quot;;" lang="EN-US">PTRACE_POKEDATA</span><span style="font-family: 宋体;">）</span><span style="font-family: 宋体;">将由</span><span style="font-family: &quot;courier new&quot;;" lang="EN-US">_data</span><span style="font-family: 宋体;">传入的机器字写入</span><span style="font-family: &quot;courier new&quot;;" lang="EN-US">addr</span><span style="font-family: 宋体;">所指定的地址。</span></p>
<p class="MsoNormal" style="margin-left: 36.35pt; text-indent: -15.35pt; line-height: 16pt;"><span style="font-family: wingdings;" lang="EN-US">r</span><span style="font-size: 5pt;" lang="EN-US">&nbsp; </span><strong><span style="font-family: &quot;courier new&quot;;" lang="EN-US">PT_GETREGS</span></strong><strong><span style="font-family: 宋体;">，</span></strong><strong><span style="font-family: &quot;courier new&quot;;" lang="EN-US">PT_GETFPREGS</span></strong><span style="font-family: 宋体;">和</span><strong><span style="font-family: &quot;courier new&quot;;" lang="EN-US">PT_GETDBREGS</span></strong><span style="font-family: 宋体;">（</span><span style="font-family: &quot;courier new&quot;;" lang="EN-US">PTRACE_GETREGS</span><span style="font-family: 宋体;">，</span><span style="font-family: &quot;courier new&quot;;" lang="EN-US">PTRACE_ FPREGS</span><span style="font-family: 宋体;">和</span><span style="font-family: &quot;courier new&quot;;" lang="EN-US">PT_GETFPXREGS</span><span style="font-family: 宋体;">）</span><span style="font-family: 宋体;">将一般用途寄存器、段寄存器和调试寄存器的值读入到地址由</span><span style="font-family: &quot;courier new&quot;;" lang="EN-US">_addr</span><span style="font-family: 宋体;">指针所指定的调试器进程的内存区中。只有</span><span lang="EN-US">i386</span><span style="font-family: 宋体;">平台接收这些与系统相关的命令。寄存器结构的描述放在头文件</span><span lang="EN-US">machine/reg.h</span><span style="font-family: 宋体;">文件中。</span></p>
<p class="MsoNormal" style="margin-left: 36.35pt; text-indent: -15.35pt; line-height: 16pt;"><span style="font-family: wingdings;" lang="EN-US">r</span><span style="font-size: 5pt;" lang="EN-US">&nbsp; </span><strong><span style="font-family: &quot;courier new&quot;;" lang="EN-US">PT_SETREGS</span></strong><strong><span style="font-family: 宋体;">，</span></strong><strong><span style="font-family: &quot;courier new&quot;;" lang="EN-US">PT_SETFPREGS</span></strong><span style="font-family: 宋体;">和</span><strong><span style="font-family: &quot;courier new&quot;;" lang="EN-US">PT_SETDBREGS</span></strong><span style="font-family: 宋体;">（</span><span style="font-family: &quot;courier new&quot;;" lang="EN-US">PTRACE_SETREGS</span><span style="font-family: 宋体;">，</span><span style="font-family: &quot;courier new&quot;;" lang="EN-US">PTRACE_ SETFPREGS</span><span style="font-family: 宋体;">和</span><span style="font-family: &quot;courier new&quot;;" lang="EN-US">PT_SETFPXREGS</span><span style="font-family: 宋体;">）</span><span style="font-family: 宋体;">通过拷贝由</span><span style="font-family: &quot;courier new&quot;;" lang="EN-US">_addr</span><span style="font-family: 宋体;">指针所指定的内存区域的内容来设置被调试</span><span style="font-family: 宋体;">进程</span><span style="font-family: 宋体;">的寄存器的值。</span></p>
<p class="MsoNormal" style="margin-left: 36.35pt; text-indent: -15.35pt; line-height: 16pt;"><span style="font-family: wingdings;" lang="EN-US">r</span><span style="font-size: 5pt;" lang="EN-US">&nbsp; </span><strong><span style="font-family: &quot;courier new&quot;;" lang="EN-US">PT_KILL</span></strong><span style="font-family: 宋体;">（</span><span style="font-family: &quot;courier new&quot;;" lang="EN-US">PTRACE_KILL</span><span style="font-family: 宋体;">）</span><span style="font-family: 宋体;">将</span><span style="font-family: &quot;courier new&quot;;" lang="EN-US">sigkill</span><span style="font-family: 宋体;">发送到被调试进程，以终止其执行。</span></p><img src ="http://www.cppblog.com/elva/aggbug/91146.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2009-07-25 17:52 <a href="http://www.cppblog.com/elva/archive/2009/07/25/91146.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Playing with ptrace, Part II</title><link>http://www.cppblog.com/elva/archive/2009/07/25/91141.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Sat, 25 Jul 2009 09:45:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2009/07/25/91141.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/91141.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2009/07/25/91141.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/91141.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/91141.html</trackback:ping><description><![CDATA[<p>In Part I of this article
[<em>LJ</em>, November 2002], we saw how ptrace can be
used to trace system calls and change system call arguments. In
this article, we investigate advanced techniques like setting
breakpoints and injecting code into running programs. Debuggers use
these methods to set up breakpoints and execute debugging handlers.
As with Part I, all code in this article is i386
architecture-specific.
</p>
<div class="simplesect" lang="en">
<div class="titlepage"><a name="N0xa50890.0xb44e88"></a>
<p>In Part I, we ran the process to be traced as a child after
calling ptrace(PTRACE_TRACEME, ..). If you simply wanted to see how
the process is making system calls and trace the program, this
would be sufficient. If you want to trace or debug a process
already running, then ptrace(PTRACE_ATTACH, ..) should be
used.</p>
<p>When a ptrace(PTRACE_ATTACH, ..) is called with the pid to be
traced, it is roughly equivalent to the process calling
ptrace(PTRACE_TRACEME, ..) and becoming a child of the tracing
process. The traced process is sent a SIGSTOP, so we can examine
and modify the process as usual. After we are done with
modifications or tracing, we can let the traced process continue on
its own by calling ptrace(PTRACE_DETACH, ..).</p>
<p>The following is the code for a small example tracing
program:</p>
<pre class="programlisting">int main()<br>{   int i;<br>    for(i = 0;i &lt; 10; ++i) {<br>        printf("My counter: %d\n", i);<br>        sleep(2);<br>    }<br>    return 0;<br>}<br></pre>
<p>Save the program as dummy2.c. Compile and run it:
</p>
<pre class="programlisting">gcc -o dummy2 dummy2.c<br>./dummy2 &amp;<br></pre>
Now, we can attach to dummy2 by using the code below:
<pre class="programlisting">#include &lt;sys/ptrace.h&gt;<br>#include &lt;sys/types.h&gt;<br>#include &lt;sys/wait.h&gt;<br>#include &lt;unistd.h&gt;<br>#include &lt;linux/user.h&gt;   /* For user_regs_struct<br>                             etc. */<br>int main(int argc, char *argv[])<br>{   pid_t traced_process;<br>    struct user_regs_struct regs;<br>    long ins;<br>    if(argc != 2) {<br>        printf("Usage: %s &lt;pid to be traced&gt;\n",<br>               argv[0], argv[1]);<br>        exit(1);<br>    }<br>    traced_process = atoi(argv[1]);<br>    ptrace(PTRACE_ATTACH, traced_process,<br>           NULL, NULL);<br>    wait(NULL);<br>    ptrace(PTRACE_GETREGS, traced_process,<br>           NULL, &amp;regs);<br>    ins = ptrace(PTRACE_PEEKTEXT, traced_process,<br>                 regs.eip, NULL);<br>    printf("EIP: %lx Instruction executed: %lx\n",<br>           regs.eip, ins);<br>    ptrace(PTRACE_DETACH, traced_process,<br>           NULL, NULL);<br>    return 0;<br>}<br></pre>
The above program simply attaches to a process, waits for it to
stop, examines its eip (instruction pointer) and detaches.
<p>To inject code use ptrace(PTRACE_POKETEXT, ..) and
ptrace(PTRACE_POKEDATA, ..) after the traced process has
stopped.</p>
</div>
<div class="simplesect" lang="en">
<div class="titlepage"><a name="N0xa50890.0xb451f8"></a>Setting Breakpoints</div>
<p>How do debuggers set breakpoints? Generally, they replace the
instruction to be executed with a trap instruction, so that when
the traced program stops, the tracing program, the debugger, can
examine it. It will replace the original instruction once the
tracing program continues the traced process. Here's an
example:</p>
<pre class="programlisting">#include &lt;sys/ptrace.h&gt;<br>#include &lt;sys/types.h&gt;<br>#include &lt;sys/wait.h&gt;<br>#include &lt;unistd.h&gt;<br>#include &lt;linux/user.h&gt;<br>const int long_size = sizeof(long);<br>void getdata(pid_t child, long addr,<br>             char *str, int len)<br>{   char *laddr;<br>    int i, j;<br>    union u {<br>            long val;<br>            char chars[long_size];<br>    }data;<br>    i = 0;<br>    j = len / long_size;<br>    laddr = str;<br>    while(i &lt; j) {<br>        data.val = ptrace(PTRACE_PEEKDATA, child,<br>                          addr + i * 4, NULL);<br>        memcpy(laddr, data.chars, long_size);<br>        ++i;<br>        laddr += long_size;<br>    }<br>    j = len % long_size;<br>    if(j != 0) {<br>        data.val = ptrace(PTRACE_PEEKDATA, child,<br>                          addr + i * 4, NULL);<br>        memcpy(laddr, data.chars, j);<br>    }<br>    str[len] = '\0';<br>}<br>void putdata(pid_t child, long addr,<br>             char *str, int len)<br>{   char *laddr;<br>    int i, j;<br>    union u {<br>            long val;<br>            char chars[long_size];<br>    }data;<br>    i = 0;<br>    j = len / long_size;<br>    laddr = str;<br>    while(i &lt; j) {<br>        memcpy(data.chars, laddr, long_size);<br>        ptrace(PTRACE_POKEDATA, child,<br>               addr + i * 4, data.val);<br>        ++i;<br>        laddr += long_size;<br>    }<br>    j = len % long_size;<br>    if(j != 0) {<br>        memcpy(data.chars, laddr, j);<br>        ptrace(PTRACE_POKEDATA, child,<br>               addr + i * 4, data.val);<br>    }<br>}<br>int main(int argc, char *argv[])<br>{   pid_t traced_process;<br>    struct user_regs_struct regs, newregs;<br>    long ins;<br>    /* int 0x80, int3 */<br>    char code[] = {0xcd,0x80,0xcc,0};<br>    char backup[4];<br>    if(argc != 2) {<br>        printf("Usage: %s &lt;pid to be traced&gt;\n",<br>               argv[0], argv[1]);<br>        exit(1);<br>    }<br>    traced_process = atoi(argv[1]);<br>    ptrace(PTRACE_ATTACH, traced_process,<br>           NULL, NULL);<br>    wait(NULL);<br>    ptrace(PTRACE_GETREGS, traced_process,<br>           NULL, &amp;regs);<br>    /* Copy instructions into a backup variable */<br>    getdata(traced_process, regs.eip, backup, 3);<br>    /* Put the breakpoint */<br>    putdata(traced_process, regs.eip, code, 3);<br>    /* Let the process continue and execute<br>       the int 3 instruction */<br>    ptrace(PTRACE_CONT, traced_process, NULL, NULL);<br>    wait(NULL);<br>    printf("The process stopped, putting back "<br>           "the original instructions\n");<br>    printf("Press &lt;enter&gt; to continue\n");<br>    getchar();<br>    putdata(traced_process, regs.eip, backup, 3);<br>    /* Setting the eip back to the original<br>       instruction to let the process continue */<br>    ptrace(PTRACE_SETREGS, traced_process,<br>           NULL, &amp;regs);<br>    ptrace(PTRACE_DETACH, traced_process,<br>           NULL, NULL);<br>    return 0;<br>}<br></pre>
<p>Here we replace the three bytes with the code for a trap
instruction, and when the process stops, we replace the original
instructions and reset the eip to original location. Figures 1-4
clarify how the instruction stream looks when above program is
executed.
</p>
<div class="table"><a name="N0xa50890.0xb453b0"></a>
<table summary="" border="1">
    <colgroup><col><col></colgroup>
    <tbody>
        <tr>
            <td>
            <p>
            </p>
            <div class="mediaobject"><img src="http://www.linuxjournal.com/files/linuxjournal.com/linuxjournal/articles/062/6210/6210f1.png"></div>
            </td>
            <td>
            <p>
            </p>
            <div class="mediaobject"><img src="http://www.linuxjournal.com/files/linuxjournal.com/linuxjournal/articles/062/6210/6210f2.png"></div>
            </td>
        </tr>
        <tr>
            <td>
            <p>Figure 1. After the Process Is Stopped</p>
            </td>
            <td>
            <p>Figure 2. After the Trap Instruction Bytes Are
            Set</p>
            </td>
        </tr>
        <tr>
            <td>
            <p>
            </p>
            <div class="mediaobject"><img src="http://www.linuxjournal.com/files/linuxjournal.com/linuxjournal/articles/062/6210/6210f3.png"></div>
            </td>
            <td>
            <p>
            </p>
            <div class="mediaobject"><img src="http://www.linuxjournal.com/files/linuxjournal.com/linuxjournal/articles/062/6210/6210f4.png"></div>
            </td>
        </tr>
        <tr>
            <td>
            <p>Figure 3. Trap Is Hit and Control Is Given to the
            Tracing Program</p>
            </td>
            <td>
            <p>Figure 4. After the Original Instructions Are Replaced
            and eip Is Reset to the Original Location</p>
            </td>
        </tr>
    </tbody>
</table>
</div>
<p>Now that we have a clear idea of how breakpoints are set,
let's inject some code bytes into a running program. These code
bytes will print &#8220;hello world&#8221;.</p>
<p>The following program is a simple &#8220;hello world&#8221; program
with modifications to fit our needs. Compile the following program
with:</p>
<pre class="programlisting">gcc -o hello hello.c<br>void main()<br>{<br>__asm__("<br>         jmp forward<br>backward:<br>         popl   %esi      # Get the address of<br>                          # hello world string<br>         movl   $4, %eax  # Do write system call<br>         movl   $2, %ebx<br>         movl   %esi, %ecx<br>         movl   $12, %edx<br>         int    $0x80<br>         int3             # Breakpoint. Here the<br>                          # program will stop and<br>                          # give control back to<br>                          # the parent<br>forward:<br>         call   backward<br>         .string \"Hello World\\n\""<br>       );<br>}<br></pre>
<p>The jumping backward and forward here is required to find the
address of the &#8220;hello world&#8221; string.
</p>
<p>We can get the machine code for the above assembly from GDB.
Fire up GDB and disassemble the program:</p>
<pre class="programlisting">(gdb) disassemble main<br>Dump of assembler code for function main:<br>0x80483e0 &lt;main&gt;:       push   %ebp<br>0x80483e1 &lt;main+1&gt;:     mov    %esp,%ebp<br>0x80483e3 &lt;main+3&gt;:     jmp    0x80483fa &lt;forward&gt;<br>End of assembler dump.<br>(gdb) disassemble forward<br>Dump of assembler code for function forward:<br>0x80483fa &lt;forward&gt;:    call   0x80483e5 &lt;backward&gt;<br>0x80483ff &lt;forward+5&gt;:  dec    %eax<br>0x8048400 &lt;forward+6&gt;:  gs<br>0x8048401 &lt;forward+7&gt;:  insb   (%dx),%es:(%edi)<br>0x8048402 &lt;forward+8&gt;:  insb   (%dx),%es:(%edi)<br>0x8048403 &lt;forward+9&gt;:  outsl  %ds:(%esi),(%dx)<br>0x8048404 &lt;forward+10&gt;: and    %dl,0x6f(%edi)<br>0x8048407 &lt;forward+13&gt;: jb     0x8048475<br>0x8048409 &lt;forward+15&gt;: or     %fs:(%eax),%al<br>0x804840c &lt;forward+18&gt;: mov    %ebp,%esp<br>0x804840e &lt;forward+20&gt;: pop    %ebp<br>0x804840f &lt;forward+21&gt;: ret<br>End of assembler dump.<br>(gdb) disassemble backward<br>Dump of assembler code for function backward:<br>0x80483e5 &lt;backward&gt;:   pop    %esi<br>0x80483e6 &lt;backward+1&gt;: mov    $0x4,%eax<br>0x80483eb &lt;backward+6&gt;: mov    $0x2,%ebx<br>0x80483f0 &lt;backward+11&gt;:        mov    %esi,%ecx<br>0x80483f2 &lt;backward+13&gt;:        mov    $0xc,%edx<br>0x80483f7 &lt;backward+18&gt;:        int    $0x80<br>0x80483f9 &lt;backward+20&gt;:        int3<br>End of assembler dump.<br></pre>
<p>We need to take the machine code bytes from main+3 to
backward+20, which is a total of 41 bytes. The machine code can be
seen with the x command in GDB:
</p>
<pre class="programlisting">(gdb) x/40bx main+3<br>&lt;main+3&gt;: eb 15 5e b8 04 00 00 00<br>&lt;backward+6&gt;: bb 02 00 00 00 89 f1 ba<br>&lt;backward+14&gt;: 0c 00 00 00 cd 80 cc<br>&lt;forward+1&gt;: e6 ff ff ff 48 65 6c 6c<br>&lt;forward+9&gt;: 6f 20 57 6f 72 6c 64 0a<br></pre>
Now we have the instruction bytes to be executed. Why wait? We can
inject them using the same method as in the previous example. The
following is the source code; only the main function is given here:
<pre class="programlisting">int main(int argc, char *argv[])<br>{   pid_t traced_process;<br>    struct user_regs_struct regs, newregs;<br>    long ins;<br>    int len = 41;<br>    char insertcode[] =<br>"\xeb\x15\x5e\xb8\x04\x00"<br>        "\x00\x00\xbb\x02\x00\x00\x00\x89\xf1\xba"<br>        "\x0c\x00\x00\x00\xcd\x80\xcc\xe8\xe6\xff"<br>        "\xff\xff\x48\x65\x6c\x6c\x6f\x20\x57\x6f"<br>        "\x72\x6c\x64\x0a\x00";<br>    char backup[len];<br>    if(argc != 2) {<br>        printf("Usage: %s &lt;pid to be traced&gt;\n",<br>               argv[0], argv[1]);<br>        exit(1);<br>    }<br>    traced_process = atoi(argv[1]);<br>    ptrace(PTRACE_ATTACH, traced_process,<br>           NULL, NULL);<br>    wait(NULL);<br>    ptrace(PTRACE_GETREGS, traced_process,<br>           NULL, &amp;regs);<br>    getdata(traced_process, regs.eip, backup, len);<br>    putdata(traced_process, regs.eip,<br>            insertcode, len);<br>    ptrace(PTRACE_SETREGS, traced_process,<br>           NULL, &amp;regs);<br>    ptrace(PTRACE_CONT, traced_process,<br>           NULL, NULL);<br>    wait(NULL);<br>    printf("The process stopped, Putting back "<br>           "the original instructions\n");<br>    putdata(traced_process, regs.eip, backup, len);<br>    ptrace(PTRACE_SETREGS, traced_process,<br>           NULL, &amp;regs);<br>    printf("Letting it continue with "<br>           "original flow\n");<br>    ptrace(PTRACE_DETACH, traced_process,<br>           NULL, NULL);<br>    return 0;<br>}<br></pre>
</div>
<div class="simplesect" lang="en">
<div class="titlepage"><a name="N0xa50890.0xb46328"></a>Injecting the Code into Free Space</div>
<p>In the previous example we injected the code directly into
the executing instruction stream. However, debuggers can get
confused with this kind of behaviour, so let's find the free space
in the process and inject the code there. We can find free space by
examining the /proc/pid/maps file of the traced process. The
following function will find the starting address of this
map:</p>
<pre class="programlisting">long freespaceaddr(pid_t pid)<br>{<br>    FILE *fp;<br>    char filename[30];<br>    char line[85];<br>    long addr;<br>    char str[20];<br>    sprintf(filename, "/proc/%d/maps", pid);<br>    fp = fopen(filename, "r");<br>    if(fp == NULL)<br>        exit(1);<br>    while(fgets(line, 85, fp) != NULL) {<br>        sscanf(line, "%lx-%*lx %*s %*s %s", &amp;addr,<br>               str, str, str, str);<br>        if(strcmp(str, "00:00") == 0)<br>            break;<br>    }<br>    fclose(fp);<br>    return addr;<br>}<br></pre>
<p>Each line in /proc/pid/maps represents a mapped region of the
process. An entry in /proc/pid/maps looks like this:
</p>
<pre class="programlisting">map start-mapend    protection  offset     device<br>inode      process file<br>08048000-0804d000   r-xp        00000000   03:08<br>66111      /opt/kde2/bin/kdeinit<br></pre>
The following program injects code into free space. It's similar to
the previous injection program except the free space address is
used for keeping our new code. Here is the source code for the main
function:
<pre class="programlisting">int main(int argc, char *argv[])<br>{   pid_t traced_process;<br>    struct user_regs_struct oldregs, regs;<br>    long ins;<br>    int len = 41;<br>    char insertcode[] =<br>"\xeb\x15\x5e\xb8\x04\x00"<br>        "\x00\x00\xbb\x02\x00\x00\x00\x89\xf1\xba"<br>        "\x0c\x00\x00\x00\xcd\x80\xcc\xe8\xe6\xff"<br>        "\xff\xff\x48\x65\x6c\x6c\x6f\x20\x57\x6f"<br>        "\x72\x6c\x64\x0a\x00";<br>    char backup[len];<br>    long addr;<br>    if(argc != 2) {<br>        printf("Usage: %s &lt;pid to be traced&gt;\n",<br>               argv[0], argv[1]);<br>        exit(1);<br>    }<br>    traced_process = atoi(argv[1]);<br>    ptrace(PTRACE_ATTACH, traced_process,<br>           NULL, NULL);<br>    wait(NULL);<br>    ptrace(PTRACE_GETREGS, traced_process,<br>           NULL, &amp;regs);<br>    addr = freespaceaddr(traced_process);<br>    getdata(traced_process, addr, backup, len);<br>    putdata(traced_process, addr, insertcode, len);<br>    memcpy(&amp;oldregs, &amp;regs, sizeof(regs));<br>    regs.eip = addr;<br>    ptrace(PTRACE_SETREGS, traced_process,<br>           NULL, &amp;regs);<br>    ptrace(PTRACE_CONT, traced_process,<br>           NULL, NULL);<br>    wait(NULL);<br>    printf("The process stopped, Putting back "<br>           "the original instructions\n");<br>    putdata(traced_process, addr, backup, len);<br>    ptrace(PTRACE_SETREGS, traced_process,<br>           NULL, &amp;oldregs);<br>    printf("Letting it continue with "<br>           "original flow\n");<br>    ptrace(PTRACE_DETACH, traced_process,<br>           NULL, NULL);<br>    return 0;<br>}<br></pre>
</div>
<div class="simplesect" lang="en">
<div class="titlepage"><a name="N0xa50890.0xdfc590"></a>Behind the Scenes</div>
<p>So what happens within the kernel now? How is ptrace
implemented? This section could be an article on its own; however,
here's a brief description of what happens.</p>
<p>When a process calls ptrace with PTRACE_TRACEME, the kernel
sets up the process flags to reflect that it is being
traced:</p>
<pre class="programlisting">Source: arch/i386/kernel/ptrace.c<br>if (request == PTRACE_TRACEME) {<br>    /* are we already being traced? */<br>    if (current-&gt;ptrace &amp; PT_PTRACED)<br>        goto out;<br>    /* set the ptrace bit in the process flags. */<br>    current-&gt;ptrace |= PT_PTRACED;<br>    ret = 0;<br>    goto out;<br>}<br></pre>
<p>When a system call entry is done, the kernel checks this flag
and calls the trace system call if the process is being traced. The
gory assembly details can be found in arch/i386/kernel/entry.S.
</p>
<p>Now, we are in the sys_trace() function as defined in
arch/i386/kernel/ptrace.c. It stops the child and sends a signal to
the parent notifying that the child is stopped. This wakes up the
waiting parent, and it does the ptrace magic. Once the parent is
done, and it calls ptrace(PTRACE_CONT, ..) or
ptrace(PTRACE_SYSCALL, ..), it wakes up the child by calling the
scheduler function wake_up_process(). Some other architectures can
implement this by sending a SIGCHLD to child.</p>
</div>
<div class="titlepage"><a name="N0xa50890.0xdfc7f8"></a>Conclusion</div>
<p><span class="bold"><strong>ptrace</strong></span> may appear to be
magic to some people, because it can examine and modify a running
program. It is generally used by debuggers and system call tracing
programs, such as ptrace. It opens up interesting possibilities for
doing user-mode extensions as well. There have been a lot of
attempts to extend the operating system on the user level. See
Resources to read about UFO, a user-level extension to filesystems.
<span class="bold"><strong>ptrace</strong></span> also is used to employ
security mechanisms.</p>
<p>All example code from this article and from Part I is
available as a tar archive on the <em>Linux Journal</em> FTP site
[<a href="ftp://ftp.ssc.com/pub/lj/listings/issue104/6210.tgz">ftp.ssc.com/pub/lj/listings/issue104/6210.tgz</a>].</p>
<br>
<p>原文：<br></p>
<p>http://www.linuxjournal.com/article/6210<br></p><img src ="http://www.cppblog.com/elva/aggbug/91141.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2009-07-25 17:45 <a href="http://www.cppblog.com/elva/archive/2009/07/25/91141.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>玩转ptrace(一)</title><link>http://www.cppblog.com/elva/archive/2009/07/25/91140.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Sat, 25 Jul 2009 09:45:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2009/07/25/91140.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/91140.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2009/07/25/91140.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/91140.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/91140.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: by Pradeep Padala Created 2002-11-01 02:00翻译: Magic.D E-mail: adamgic@163.com译者序：在开发Hust Online Judge的过程中，查阅了不少资料，关于调试器技术的资料在网上是很少，即便是UNIX编程巨著《UNIX环境高级编程》中，相关内容也不多，直到我在http://www.linuxjournal.com上找到这篇...&nbsp;&nbsp;<a href='http://www.cppblog.com/elva/archive/2009/07/25/91140.html'>阅读全文</a><img src ="http://www.cppblog.com/elva/aggbug/91140.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2009-07-25 17:45 <a href="http://www.cppblog.com/elva/archive/2009/07/25/91140.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SIGPIPE导致的程序退出</title><link>http://www.cppblog.com/elva/archive/2009/07/21/90761.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Tue, 21 Jul 2009 10:56:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2009/07/21/90761.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/90761.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2009/07/21/90761.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/90761.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/90761.html</trackback:ping><description><![CDATA[<span class=Apple-style-span style="WORD-SPACING: 0px; FONT: 16px simsun; TEXT-TRANSFORM: none; COLOR: rgb(0,0,0); TEXT-INDENT: 0px; WHITE-SPACE: normal; LETTER-SPACING: normal; BORDER-COLLAPSE: separate; orphans: 2; widows: 2; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px"><span class=Apple-style-span style="FONT-SIZE: 12px; LINE-HEIGHT: 18px; FONT-FAMILY: Arial">
<table style="TABLE-LAYOUT: fixed">
    <tbody>
        <tr>
            <td style="FONT-SIZE: 12px; FILTER: none; VISIBILITY: visible! important; WORD-BREAK: break-all; LINE-HEIGHT: 18px; ZOOM: 1! important; FONT-FAMILY: Arial; WORD-WRAP: break-word">
            <div class=cnt id=blog_text style="OVERFLOW-Y: hidden; FONT-SIZE: 14px; FILTER: none; VISIBILITY: visible! important; OVERFLOW-X: hidden; COLOR: rgb(51,51,51); WORD-BREAK: normal; LINE-HEIGHT: 20px; ZOOM: 1! important; FONT-FAMILY: Arial; POSITION: static; WORD-WRAP: break-word">
            <p style="LINE-HEIGHT: normal">当服务器close一个连接时，若client端接着发数据。根据TCP协议的规定，会收到一个RST响应，client再往这个服务器发送数据时，系统会发出一个SIGPIPE信号给进程，告诉进程这个连接已经断开了，不要再写了。<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp; 根据信号的默认处理规则SIGPIPE信号的默认执行动作是terminate(终止、退出),所以client会退出。若不想客户端退出可以把SIGPIPE设为SIG_IGN</p>
            <p style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp; 如:&nbsp;&nbsp;&nbsp; signal(SIGPIPE,SIG_IGN);<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp; 这时SIGPIPE交给了系统处理。</p>
            <p style="LINE-HEIGHT: normal">服务器采用了fork的话，要收集垃圾进程，防止僵尸进程的产生，可以这样处理：<br style="LINE-HEIGHT: normal">signal(SIGCHLD,SIG_IGN);　交给系统init去回收。<br style="LINE-HEIGHT: normal">&nbsp;&nbsp; 这里子进程就不会产生僵尸进程了。</p>
            <p style="LINE-HEIGHT: normal"><br style="LINE-HEIGHT: normal"><a style="LINE-HEIGHT: normal" href="http://www.cublog.cn/u/31357/showart_242605.html"><u><font color=#0000ff>http://www.cublog.cn/u/31357/showart_242605.html</font></u></a></p>
            <p style="LINE-HEIGHT: normal"><br style="LINE-HEIGHT: normal">好久没做过C开发了，最近重操旧业。<span class=Apple-converted-space>&nbsp;</span><br style="LINE-HEIGHT: normal">听说另外一个项目组socket开发遇到问题，发送端和接受端数据大小不一致。建议他们采用writen的重发机制，以避免信号中断错误。采用后还是有问题。PM让我帮忙研究下。<span class=Apple-converted-space>&nbsp;</span><br style="LINE-HEIGHT: normal">UNP n年以前看过，很久没做过底层开发，手边也没有UNP vol1这本书，所以做了个测试程序，研究下实际可能发生的情况了。<span class=Apple-converted-space>&nbsp;</span><br style="LINE-HEIGHT: normal"><br style="LINE-HEIGHT: normal">测试环境：AS3和redhat 9(缺省没有nc)<span class=Apple-converted-space>&nbsp;</span><br style="LINE-HEIGHT: normal"><br style="LINE-HEIGHT: normal">先下载unp源码:<span class=Apple-converted-space>&nbsp;</span><br style="LINE-HEIGHT: normal">wget<span class=Apple-converted-space>&nbsp;</span><a style="LINE-HEIGHT: normal" href="http://www.unpbook.com/unpv13e.tar.gz"><u><font color=#0000ff>http://www.unpbook.com/unpv13e.tar.gz</font></u></a><span class=Apple-converted-space>&nbsp;</span><br style="LINE-HEIGHT: normal">tar xzvf *.tar.gz;<span class=Apple-converted-space>&nbsp;</span><br style="LINE-HEIGHT: normal">configure;make lib.<span class=Apple-converted-space>&nbsp;</span><br style="LINE-HEIGHT: normal">然后参考str_cli.c和tcpcli01.c，写了测试代码client.c<span class=Apple-converted-space>&nbsp;</span><br style="LINE-HEIGHT: normal"><br style="LINE-HEIGHT: normal">#include&nbsp;&nbsp;&nbsp; "unp.h"</p>
            <p style="LINE-HEIGHT: normal">#define MAXBUF 40960<br style="LINE-HEIGHT: normal">void processSignal(int signo)<br style="LINE-HEIGHT: normal">{<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp; printf("Signal is %d\n", signo);<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp; signal(signo, processSignal);<br style="LINE-HEIGHT: normal">}<br style="LINE-HEIGHT: normal">void<br style="LINE-HEIGHT: normal">str_cli(FILE *fp, int sockfd)<br style="LINE-HEIGHT: normal">{<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp; char&nbsp;&nbsp;&nbsp; sendline[MAXBUF], recvline[MAXBUF];</p>
            <p style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp; while (1) {</p>
            <p style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; memset(sendline, 'a', sizeof(sendline));<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf("Begin send %d data\n", MAXBUF);<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Writen(sockfd, sendline, sizeof(sendline));<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sleep(5);</p>
            <p style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp; }<br style="LINE-HEIGHT: normal">}</p>
            <p style="LINE-HEIGHT: normal">int<br style="LINE-HEIGHT: normal">main(int argc, char **argv)<br style="LINE-HEIGHT: normal">{<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp; int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sockfd;<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp; struct sockaddr_in&nbsp;&nbsp;&nbsp; servaddr;</p>
            <p style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp; signal(SIGPIPE, SIG_IGN);<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp; //signal(SIGPIPE, processSignal);</p>
            <p style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp; if (argc != 2)<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; err_quit("usage: tcpcli [port]");</p>
            <p style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp; sockfd = Socket(AF_INET, SOCK_STREAM, 0);</p>
            <p style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp; bzero(&amp;servaddr, sizeof(servaddr));<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp; servaddr.sin_family = AF_INET;<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp; servaddr.sin_port = htons(atoi(argv[1]));<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp; Inet_pton(AF_INET, "127.0.0.1", &amp;servaddr.sin_addr);</p>
            <p style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp; Connect(sockfd, (SA *) &amp;servaddr, sizeof(servaddr));</p>
            <p style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp; str_cli(stdin, sockfd);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* do it all */</p>
            <p style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp; exit(0);<br style="LINE-HEIGHT: normal">}</p>
            <p style="LINE-HEIGHT: normal"></p>
            <p style="LINE-HEIGHT: normal"></p>
            <p style="LINE-HEIGHT: normal">为了方便观察错误输出，lib/writen.c也做了修改，加了些日志：</p>
            <p style="LINE-HEIGHT: normal"></p>
            <p style="LINE-HEIGHT: normal"></p>
            <p style="LINE-HEIGHT: normal">/* include writen */<br style="LINE-HEIGHT: normal">#include&nbsp;&nbsp;&nbsp; "unp.h"</p>
            <p style="LINE-HEIGHT: normal">ssize_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;nbs
            <table class=FCK__ShowTableBorders style="TABLE-LAYOUT: auto; LINE-HEIGHT: normal">
                <tbody style="LINE-HEIGHT: normal">
                    <tr style="LINE-HEIGHT: normal">
                        <td style="FONT-SIZE: 12px; FILTER: none; VISIBILITY: visible! important; WORD-BREAK: break-all; LINE-HEIGHT: normal; ZOOM: 1! important; FONT-FAMILY: Arial; WORD-WRAP: break-word">
                        <p style="LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" size=+0><span style="LINE-HEIGHT: normal">p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: rgb(255,153,0); LINE-HEIGHT: normal">/* Write "n" bytes to a descriptor. */</span><br style="LINE-HEIGHT: normal">writen<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">(</span><span style="COLOR: rgb(0,0,255); LINE-HEIGHT: normal">int</span><span class=Apple-converted-space>&nbsp;</span>fd<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">,</span><span class=Apple-converted-space>&nbsp;</span><span style="COLOR: rgb(0,0,255); LINE-HEIGHT: normal">const</span><span class=Apple-converted-space>&nbsp;</span><span style="COLOR: rgb(0,0,255); LINE-HEIGHT: normal">void</span><span class=Apple-converted-space>&nbsp;</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">*</span>vptr<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">,</span><span class=Apple-converted-space>&nbsp;</span><span style="COLOR: rgb(255,0,0); LINE-HEIGHT: normal">size_t</span><span class=Apple-converted-space>&nbsp;</span>n<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">)</span><br style="LINE-HEIGHT: normal"><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">{</span><br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: rgb(255,0,0); LINE-HEIGHT: normal">size_t</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nleft<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">;</span><br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp; ssize_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nwritten<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">;</span><br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: rgb(0,0,255); LINE-HEIGHT: normal">const</span><span class=Apple-converted-space>&nbsp;</span><span style="COLOR: rgb(0,0,255); LINE-HEIGHT: normal">char</span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">*</span>ptr<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">;</span><br style="LINE-HEIGHT: normal"><br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp; ptr<span class=Apple-converted-space>&nbsp;</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">=</span><span class=Apple-converted-space>&nbsp;</span>vptr<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">;</span><br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp; nleft<span class=Apple-converted-space>&nbsp;</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">=</span><span class=Apple-converted-space>&nbsp;</span>n<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">;</span><br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: rgb(0,0,255); LINE-HEIGHT: normal">while</span><span class=Apple-converted-space>&nbsp;</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">(</span>nleft<span class=Apple-converted-space>&nbsp;</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">&gt;</span><span class=Apple-converted-space>&nbsp;</span>0<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">)</span><span class=Apple-converted-space>&nbsp;</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">{</span><br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: rgb(255,0,0); LINE-HEIGHT: normal">printf</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">(</span><span style="COLOR: rgb(255,0,255); LINE-HEIGHT: normal">"Begin Writen %d\n"</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">,</span><span class=Apple-converted-space>&nbsp;</span>nleft<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">)</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">;</span><br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: rgb(0,0,255); LINE-HEIGHT: normal">if</span><span class=Apple-converted-space>&nbsp;</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">(</span><span class=Apple-converted-space>&nbsp;</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">(</span>nwritten<span class=Apple-converted-space>&nbsp;</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">=</span><span class=Apple-converted-space>&nbsp;</span><span style="COLOR: rgb(255,0,0); LINE-HEIGHT: normal">write</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">(</span>fd<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">,</span><span class=Apple-converted-space>&nbsp;</span>ptr<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">,</span><span class=Apple-converted-space>&nbsp;</span>nleft<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">)</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">)</span><span class=Apple-converted-space>&nbsp;</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">&lt;</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">=</span><span class=Apple-converted-space>&nbsp;</span>0<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">)</span><span class=Apple-converted-space>&nbsp;</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">{</span><br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: rgb(0,0,255); LINE-HEIGHT: normal">if</span><span class=Apple-converted-space>&nbsp;</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">(</span>nwritten<span class=Apple-converted-space>&nbsp;</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">&lt;</span><span class=Apple-converted-space>&nbsp;</span>0<span class=Apple-converted-space>&nbsp;</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">&amp;</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">&amp;</span><span class=Apple-converted-space>&nbsp;</span><span style="COLOR: rgb(255,0,0); LINE-HEIGHT: normal">errno</span><span class=Apple-converted-space>&nbsp;</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">=</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">=</span><span class=Apple-converted-space>&nbsp;</span>EINTR<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">)</span><span class=Apple-converted-space>&nbsp;</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">{</span><br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: rgb(255,0,0); LINE-HEIGHT: normal">printf</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">(</span><span style="COLOR: rgb(255,0,255); LINE-HEIGHT: normal">"intterupt\n"</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">)</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">;</span><br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nwritten<span class=Apple-converted-space>&nbsp;</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">=</span><span class=Apple-converted-space>&nbsp;</span>0<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: rgb(255,153,0); LINE-HEIGHT: normal">/* and call write() again */</span><br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">}</span><br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: rgb(0,0,255); LINE-HEIGHT: normal">else</span><br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: rgb(0,0,255); LINE-HEIGHT: normal">return</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">(</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">-</span>1<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">)</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: rgb(255,153,0); LINE-HEIGHT: normal">/* error */</span><br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">}</span><br style="LINE-HEIGHT: normal"><br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nleft<span class=Apple-converted-space>&nbsp;</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">-</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">=</span><span class=Apple-converted-space>&nbsp;</span>nwritten<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">;</span><br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ptr<span class=Apple-converted-space>&nbsp;</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">+</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">=</span><span class=Apple-converted-space>&nbsp;</span>nwritten<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">;</span><br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: rgb(255,0,0); LINE-HEIGHT: normal">printf</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">(</span><span style="COLOR: rgb(255,0,255); LINE-HEIGHT: normal">"Already write %d, left %d, errno=%d\n"</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">,</span><span class=Apple-converted-space>&nbsp;</span>nwritten<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">,</span><span class=Apple-converted-space>&nbsp;</span>nleft<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">,</span><span class=Apple-converted-space>&nbsp;</span><span style="COLOR: rgb(255,0,0); LINE-HEIGHT: normal">errno</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">)</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">;</span><br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">}</span><br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: rgb(0,0,255); LINE-HEIGHT: normal">return</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">(</span>n<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">)</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">;</span><br style="LINE-HEIGHT: normal"><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">}</span><br style="LINE-HEIGHT: normal"><span style="COLOR: rgb(255,153,0); LINE-HEIGHT: normal">/* end writen */</span><br style="LINE-HEIGHT: normal"><br style="LINE-HEIGHT: normal"><span style="COLOR: rgb(0,0,255); LINE-HEIGHT: normal">void</span><br style="LINE-HEIGHT: normal">Writen<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">(</span><span style="COLOR: rgb(0,0,255); LINE-HEIGHT: normal">int</span><span class=Apple-converted-space>&nbsp;</span>fd<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">,</span><span class=Apple-converted-space>&nbsp;</span><span style="COLOR: rgb(0,0,255); LINE-HEIGHT: normal">void</span><span class=Apple-converted-space>&nbsp;</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">*</span>ptr<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">,</span><span class=Apple-converted-space>&nbsp;</span><span style="COLOR: rgb(255,0,0); LINE-HEIGHT: normal">size_t</span><span class=Apple-converted-space>&nbsp;</span>nbytes<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">)</span><br style="LINE-HEIGHT: normal"><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">{</span><br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: rgb(0,0,255); LINE-HEIGHT: normal">if</span><span class=Apple-converted-space>&nbsp;</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">(</span>writen<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">(</span>fd<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">,</span><span class=Apple-converted-space>&nbsp;</span>ptr<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">,</span><span class=Apple-converted-space>&nbsp;</span>nbytes<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">)</span><span class=Apple-converted-space>&nbsp;</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">!</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">=</span><span class=Apple-converted-space>&nbsp;</span>nbytes<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">)</span><br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; err_sys<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">(</span><span style="COLOR: rgb(255,0,255); LINE-HEIGHT: normal">"writen error"</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">)</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">;</span><br style="LINE-HEIGHT: normal"><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">}</span><br style="LINE-HEIGHT: normal"></span></font></p>
                        </td>
                    </tr>
                </tbody>
            </table>
            </p>
            <p style="LINE-HEIGHT: normal"></p>
            <p style="LINE-HEIGHT: normal">client.c放在tcpclieserv目录下，修改了Makefile，增加了client.c的编译目标</p>
            <p style="LINE-HEIGHT: normal"></p>
            <p style="LINE-HEIGHT: normal">
            <table style="TABLE-LAYOUT: auto; LINE-HEIGHT: normal; BORDER-COLLAPSE: collapse" borderColor=#999999 cellSpacing=0 cellPadding=0 width="95%" bgColor=#f1f1f1 border=1>
                <tbody style="LINE-HEIGHT: normal">
                    <tr style="LINE-HEIGHT: normal">
                        <td style="FONT-SIZE: 12px; FILTER: none; VISIBILITY: visible! important; WORD-BREAK: break-all; LINE-HEIGHT: normal; ZOOM: 1! important; FONT-FAMILY: Arial; WORD-WRAP: break-word">
                        <p style="MARGIN: 5px; LINE-HEIGHT: 18px"><code style="LINE-HEIGHT: normal"><span style="COLOR: rgb(0,0,0); LINE-HEIGHT: normal"><br style="LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" face=新宋体>client<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">:</span><span class=Apple-converted-space>&nbsp;</span>client<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">.</span>c<br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">{</span>CC<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">}</span><span class=Apple-converted-space>&nbsp;</span>$<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">{</span>CFLAGS<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">}</span><span class=Apple-converted-space>&nbsp;</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">-</span>o $@ $<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">&lt;</span><span class=Apple-converted-space>&nbsp;</span>$<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">{</span>LIBS<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">}</span><br style="LINE-HEIGHT: normal"></font></span></code></p>
                        </td>
                    </tr>
                </tbody>
            </table>
            </p>
            <p style="LINE-HEIGHT: normal"></p>
            <p style="LINE-HEIGHT: normal">接着就可以开始测试了。</p>
            <h2 style="LINE-HEIGHT: normal">测试1 忽略SIGPIPE信号，writen之前，对方关闭接受进程</h2>
            <p style="LINE-HEIGHT: normal">本机服务端：</p>
            <p style="LINE-HEIGHT: normal"><br style="LINE-HEIGHT: normal">nc -l -p 30000<span class=Apple-converted-space>&nbsp;</span><br style="LINE-HEIGHT: normal"><br style="LINE-HEIGHT: normal">本机客户端:<span class=Apple-converted-space>&nbsp;</span><br style="LINE-HEIGHT: normal">./client 30000<span class=Apple-converted-space>&nbsp;</span><br style="LINE-HEIGHT: normal">Begin send 40960 data<br style="LINE-HEIGHT: normal">Begin Writen 40960<br style="LINE-HEIGHT: normal">Already write 40960, left 0, errno=0<br style="LINE-HEIGHT: normal">Begin send 40960 data<br style="LINE-HEIGHT: normal">Begin Writen 40960<br style="LINE-HEIGHT: normal">Already write 40960, left 0, errno=0<br style="LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" color=#ff0000>执行到上步停止服务端,client会继续显示:</font><span class=Apple-converted-space>&nbsp;</span><br style="LINE-HEIGHT: normal">Begin send 40960 data<br style="LINE-HEIGHT: normal">Begin Writen 40960<br style="LINE-HEIGHT: normal">writen error: Broken pipe(32)<br style="LINE-HEIGHT: normal"><strong style="LINE-HEIGHT: normal">结论:可见write之前，对方socket中断，发送端write会返回-1,errno号为EPIPE(32)</strong></p>
            <h2 style="LINE-HEIGHT: normal">测试2 catch SIGPIPE信号，writen之前，对方关闭接受进程</h2>
            <p style="LINE-HEIGHT: normal">修改客户端代码，catch sigpipe信号</p>
            <p style="LINE-HEIGHT: normal">
            <table style="TABLE-LAYOUT: auto; LINE-HEIGHT: normal; BORDER-COLLAPSE: collapse" borderColor=#999999 cellSpacing=0 cellPadding=0 width="95%" bgColor=#f1f1f1 border=1>
                <tbody style="LINE-HEIGHT: normal">
                    <tr style="LINE-HEIGHT: normal">
                        <td style="FONT-SIZE: 12px; FILTER: none; VISIBILITY: visible! important; WORD-BREAK: break-all; LINE-HEIGHT: normal; ZOOM: 1! important; FONT-FAMILY: Arial; WORD-WRAP: break-word">
                        <p style="MARGIN: 5px; LINE-HEIGHT: 18px"><code style="LINE-HEIGHT: normal"><span style="COLOR: rgb(0,0,0); LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" face=新宋体><span style="COLOR: rgb(255,153,0); LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" color=#000000>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font>//signal(SIGPIPE, SIG_IGN);<br style="LINE-HEIGHT: normal"></span><br style="LINE-HEIGHT: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: rgb(255,0,0); LINE-HEIGHT: normal">signal</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">(</span>SIGPIPE<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">,</span><span class=Apple-converted-space>&nbsp;</span>processSignal<span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">)</span><span style="COLOR: rgb(0,0,204); LINE-HEIGHT: normal">;</span></font><br style="LINE-HEIGHT: normal"></span></code></p>
                        </td>
                    </tr>
                </tbody>
            </table>
            </p>
            <p style="LINE-HEIGHT: normal">本机服务端：</p>
            <p style="LINE-HEIGHT: normal"><br style="LINE-HEIGHT: normal">nc -l -p 30000<span class=Apple-converted-space>&nbsp;</span><br style="LINE-HEIGHT: normal"><br style="LINE-HEIGHT: normal">本机客户端:<span class=Apple-converted-space>&nbsp;</span><br style="LINE-HEIGHT: normal">make client<span class=Apple-converted-space>&nbsp;</span><br style="LINE-HEIGHT: normal">./client 30000<span class=Apple-converted-space>&nbsp;</span><br style="LINE-HEIGHT: normal"><br style="LINE-HEIGHT: normal">Begin send 40960 data<br style="LINE-HEIGHT: normal">Begin Writen 40960<br style="LINE-HEIGHT: normal">Already write 40960, left 0, errno=0<br style="LINE-HEIGHT: normal">Begin send 40960 data<br style="LINE-HEIGHT: normal">Begin Writen 40960<br style="LINE-HEIGHT: normal">Already write 40960, left 0, errno=0<br style="LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" color=#ff0000>执行到上步停止服务端,client会继续显示:</font><span class=Apple-converted-space>&nbsp;</span><br style="LINE-HEIGHT: normal">Begin send 40960 data<br style="LINE-HEIGHT: normal">Begin Writen 40960<br style="LINE-HEIGHT: normal">Signal is 13<br style="LINE-HEIGHT: normal">writen error: Broken pipe(32)<br style="LINE-HEIGHT: normal"><strong style="LINE-HEIGHT: normal">结论:可见write之前，对方socket中断，发送端write时，会先调用SIGPIPE响应函数，然后write返回-1,errno号为EPIPE(32)</strong><span class=Apple-converted-space>&nbsp;</span><br style="LINE-HEIGHT: normal"></p>
            <h2 style="LINE-HEIGHT: normal">测试3 writen过程中，对方关闭接受进程</h2>
            <p style="LINE-HEIGHT: normal">为了方便操作，加大1次write的数据量，修改MAXBUF为4096000</p>
            <p style="LINE-HEIGHT: normal">本机服务端：</p>
            <p style="LINE-HEIGHT: normal"><br style="LINE-HEIGHT: normal">nc -l -p 30000<span class=Apple-converted-space>&nbsp;</span><br style="LINE-HEIGHT: normal"><br style="LINE-HEIGHT: normal">本机客户端:<span class=Apple-converted-space>&nbsp;</span><br style="LINE-HEIGHT: normal">make client<span class=Apple-converted-space>&nbsp;</span><br style="LINE-HEIGHT: normal">./client 30000<span class=Apple-converted-space>&nbsp;</span><br style="LINE-HEIGHT: normal"><br style="LINE-HEIGHT: normal">Begin send 4096000 data<br style="LINE-HEIGHT: normal">Begin Writen 4096000<br style="LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" color=#ff0000>执行到上步停止服务端,client会继续显示:</font><span class=Apple-converted-space>&nbsp;</span><br style="LINE-HEIGHT: normal">Already write 589821, left 3506179, errno=0<br style="LINE-HEIGHT: normal">Begin Writen 3506179<br style="LINE-HEIGHT: normal">writen error: Connection reset by peer(104)<br style="LINE-HEIGHT: normal"><br style="LINE-HEIGHT: normal"><strong style="LINE-HEIGHT: normal">结论:可见socket write中，对方socket中断，发送端write会先返回已经发送的字节数,再次write时返回-1,errno号为ECONNRESET(104)</strong></p>
            <p style="LINE-HEIGHT: normal">为什么以上测试，都是对方已经中断socket后，发送端再次write，结果会有所不同呢。从后来找到的UNP5.12,5.13能找到答案</p>
            <p style="LINE-HEIGHT: normal">
            <table style="TABLE-LAYOUT: auto; LINE-HEIGHT: normal; BORDER-COLLAPSE: collapse" borderColor=#999999 cellSpacing=0 cellPadding=0 width="95%" bgColor=#f1f1f1 border=1>
                <tbody style="LINE-HEIGHT: normal">
                    <tr style="LINE-HEIGHT: normal">
                        <td style="FONT-SIZE: 12px; FILTER: none; VISIBILITY: visible! important; WORD-BREAK: break-all; LINE-HEIGHT: normal; ZOOM: 1! important; FONT-FAMILY: Arial; WORD-WRAP: break-word">
                        <p style="MARGIN: 5px; LINE-HEIGHT: 18px">The client's call to readline may happen before the server's RST is received by the client, or it may happen after. If the readline happens before the RST is received, as we've shown in our example, the result is an unexpected EOF in the client. But if the RST arrives first, the result is an ECONNRESET ("Connection reset by peer") error return from readline.</p>
                        </td>
                    </tr>
                </tbody>
            </table>
            </p>
            <p style="LINE-HEIGHT: normal">以上解释了测试3的现象，write时，收到RST.</p>
            <p style="LINE-HEIGHT: normal">
            <table style="TABLE-LAYOUT: auto; LINE-HEIGHT: normal; BORDER-COLLAPSE: collapse" borderColor=#999999 cellSpacing=0 cellPadding=0 width="95%" bgColor=#f1f1f1 border=1>
                <tbody style="LINE-HEIGHT: normal">
                    <tr style="LINE-HEIGHT: normal">
                        <td style="FONT-SIZE: 12px; FILTER: none; VISIBILITY: visible! important; WORD-BREAK: break-all; LINE-HEIGHT: normal; ZOOM: 1! important; FONT-FAMILY: Arial; WORD-WRAP: break-word">
                        <p style="MARGIN: 5px; LINE-HEIGHT: 18px">What happens if the client ignores the error return from readline and writes more data to the server? This can happen, for example, if the client needs to perform two writes to the server before reading anything back, with the first write eliciting the RST.</p>
                        <p style="MARGIN: 5px; LINE-HEIGHT: 18px">The rule that applies is: When a process writes to a socket that has received an RST, the SIGPIPE signal is sent to the process. The default action of this signal is to terminate the process, so the process must catch the signal to avoid being involuntarily terminated.</p>
                        <p style="MARGIN: 5px; LINE-HEIGHT: 18px">If the process either catches the signal and returns from the signal handler, or ignores the signal, the write operation returns EPIPE.</p>
                        </td>
                    </tr>
                </tbody>
            </table>
            </p>
            <p style="LINE-HEIGHT: normal">以上解释了测试1，2的现象,write一个已经接受到RST的socket，系统内核会发送SIGPIPE给发送进程，如果进程catch/ignore这个信号，write都返回EPIPE错误.</p>
            <p style="LINE-HEIGHT: normal">因此,UNP建议应用根据需要处理SIGPIPE信号，至少不要用系统缺省的处理方式处理这个信号，系统缺省的处理方式是退出进程，这样你的应用就很难查处处理进程为什么退出。</p>
            <p style="LINE-HEIGHT: normal"><br style="LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" color=#0000ff>http://blog.csdn.net/shcyd/archive/2006/10/28/1354577.aspx</font></p>
            <p style="LINE-HEIGHT: normal">在Unix系统下，如果send在等待协议传送数据时网络断开的话，调用send的进程会接收到一个SIGPIPE信号，进程对该信号的默认处理是进程终止。<br style="LINE-HEIGHT: normal">在Unix系统下，如果recv函数在等待协议接收数据时网络断开了，那么调用recv的进程会接收到一个SIGPIPE信号，进程对该信号的默认处理是进程终止。</p>
            <p style="LINE-HEIGHT: normal">处理方法：<br style="LINE-HEIGHT: normal">在初始化时调用<strong style="LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" color=#333399>signal(SIGPIPE,SIG_IGN)</font></strong>忽略该信号（只需一次）<br style="LINE-HEIGHT: normal">其时send或recv函数将返回-1，errno为EPIPE，可视情况关闭socket或其他处理</p>
            <p style="LINE-HEIGHT: normal">gdb：<br style="LINE-HEIGHT: normal">gdb默认收到sigpipe时中断程序，可调用<strong style="LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" color=#333399>handle SIGPIPE nostop print</font></strong></p>
            <p style="LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" color=#993300>相关</font></p>
            <p style="LINE-HEIGHT: normal"><strong style="LINE-HEIGHT: normal">(1)SIG_DFL信号专用的默认动作:</strong><br style="LINE-HEIGHT: normal">　　(a)如果默认动作是暂停线程，则该线程的执行被暂时挂起。当线程暂停期间，发送给线程的任何附加信号都不交付，直到该线程开始执行，但是SIGKILL除外。<br style="LINE-HEIGHT: normal">　　(b)把挂起信号的信号动作设置成SIG_DFL，且其默认动作是忽略信号 (SIGCHLD)。</p>
            <p style="LINE-HEIGHT: normal"><strong style="LINE-HEIGHT: normal">(2)SIG_IGN忽略信号</strong><br style="LINE-HEIGHT: normal">　　(a)该信号的交付对线程没有影响<br style="LINE-HEIGHT: normal">　　(b)系统不允许把SIGKILL或SIGTOP信号的动作设置为SIG_DFL</p>
            <p style="LINE-HEIGHT: normal"><strong style="LINE-HEIGHT: normal">(3)指向函数的指针--捕获信号</strong><br style="LINE-HEIGHT: normal">　　(a)信号一经交付，接收线程就在指定地址上执行信号捕获程序。在信号捕 获函数返回后，接受线程必须在被中断点恢复执行。<br style="LINE-HEIGHT: normal">　　(b)用C语言函数调用的方法进入信号捕捉程序:<br style="LINE-HEIGHT: normal">　　　　void func (signo)<br style="LINE-HEIGHT: normal">　　　　int signo;<br style="LINE-HEIGHT: normal">　　　　func( )是指定的信号捕捉函数，signo是正被交付信号的编码<br style="LINE-HEIGHT: normal">　　(c)如果SIGFPE,SIGILL或SIGSEGV信号不是由C标准定义的kill( )或raise( )函数所生成，则从信号SIGFPE,SIGILL,SIGSEGV的信号捕获函数正常返回后线程的行为是未定义的。<br style="LINE-HEIGHT: normal">　　(d)系统不允许线程捕获SIGKILL和SIGSTOP信号。<br style="LINE-HEIGHT: normal">　　(e)如果线程为SIGCHLD信号建立信号捕获函数，而该线程有未被等待的以终止的子线程时，没有规定是否要生成SIGCHLD信号来指明那个子线程。</p>
            <p style="LINE-HEIGHT: normal">每一种信号都被OSKit给予了一个符号名，对于32位的i386平台而言，一个字32位，因而信号有32种。下面的表给出了常用的符号名、描述和它们的信号值。</p>
            <p style="LINE-HEIGHT: normal">符号名　　信号值 描述　　　　　　　　　　　　　　　　是否符合POSIX<br style="LINE-HEIGHT: normal">SIGHUP　　1　　　在控制终端上检测到挂断或控制线程死亡　　是<br style="LINE-HEIGHT: normal">SIGINT　　2　　　交互注意信号　　　　　　　　　　　　　　是<br style="LINE-HEIGHT: normal">SIGQUIT　 3　　　交互中止信号　　　　　　　　　　　　　　是<br style="LINE-HEIGHT: normal">SIGILL　　4　　　检测到非法硬件的指令　　　　　　　　　　是<br style="LINE-HEIGHT: normal">SIGTRAP　 5　　　从陷阱中回朔　　　　　　　　　　　　　　否<br style="LINE-HEIGHT: normal">SIGABRT　 6　　　异常终止信号　　　　　　　　　　　　　　是<br style="LINE-HEIGHT: normal">SIGEMT　　7　　　EMT 指令　　　　　　　　　　　　　　　　否<br style="LINE-HEIGHT: normal">SIGFPE　　8　　　不正确的算术操作信号　　　　　　　　　　是<br style="LINE-HEIGHT: normal">SIGKILL　 9　　　终止信号　　　　　　　　　　　　　　　　是<br style="LINE-HEIGHT: normal">SIGBUS　　10　　 总线错误　　　　　　　　　　　　　　　　否<br style="LINE-HEIGHT: normal">SIGSEGV　 11　　 检测到非法的内存调用　　　　　　　　　　是<br style="LINE-HEIGHT: normal">SIGSYS　　12　　 系统call的错误参数　　　　　　　　　　　否<br style="LINE-HEIGHT: normal">SIGPIPE　 13　　 在无读者的管道上写　　　　　　　　　　　是<br style="LINE-HEIGHT: normal">SIGALRM　 14　　 报时信号　　　　　　　　　　　　　　　　是<br style="LINE-HEIGHT: normal">SIGTERM　 15　　 终止信号　　　　　　　　　　　　　　　　是<br style="LINE-HEIGHT: normal">SIGURG　　16　　 IO信道紧急信号　　　　　　　　　　　　　否<br style="LINE-HEIGHT: normal">SIGSTOP　 17　　 暂停信号　　　　　　　　　　　　　　　　是<br style="LINE-HEIGHT: normal">SIGTSTP　 18　　 交互暂停信号　　　　　　　　　　　　　　是<br style="LINE-HEIGHT: normal">SIGCONT　 19　　 如果暂停则继续　　　　　　　　　　　　　是<br style="LINE-HEIGHT: normal">SIGCHLD　 20　　 子线程终止或暂停　　　　　　　　　　　　是<br style="LINE-HEIGHT: normal">SIGTTIN　 21　　 后台线程组一成员试图从控制终端上读出　　是<br style="LINE-HEIGHT: normal">SIGTTOU　 22　　 后台线程组的成员试图写到控制终端上　　　是<br style="LINE-HEIGHT: normal">SIGIO　　 23　　 允许I/O信号 　　　　　　　　　　　　　　否<br style="LINE-HEIGHT: normal">SIGXCPU　 24　　 超出CPU时限　　　　　　　　　　　　　　 否<br style="LINE-HEIGHT: normal">SIGXFSZ　 25　　 超出文件大小限制　　　　　　　　　　　　否<br style="LINE-HEIGHT: normal">SIGVTALRM 26　　 虚时间警报器　　　　　　　　　　　　　　否<br style="LINE-HEIGHT: normal">SIGPROF　 27　　 侧面时间警报器　　　　　　　　　　　　　否<br style="LINE-HEIGHT: normal">SIGWINCH　28　　 窗口大小的更改　　　　　　　　　　　　　否<br style="LINE-HEIGHT: normal">SIGINFO　 29　　 消息请求　　　　　　　　　　　　　　　　否<br style="LINE-HEIGHT: normal"><clk style="LINE-HEIGHT: normal"></clk>SIGUSR1 　30　　 保留作为<nobr style="COLOR: rgb(102,0,255); LINE-HEIGHT: normal; BORDER-BOTTOM: rgb(102,0,255) 1px dotted; BACKGROUND-COLOR: transparent; TEXT-DECORATION: underline">用户</nobr>自定义的信号1　　　　　　　 是<br style="LINE-HEIGHT: normal">SIGUSR2 　31　　 保留作为用户自定义的信号　　　　　　　　是<span class=Apple-converted-space>&nbsp;</span><br style="LINE-HEIGHT: normal"><br style="LINE-HEIGHT: normal"><font style="LINE-HEIGHT: normal" color=#ff6600>注意</font>：Linux信号机制基本上是从Unix系统中继承过来的。早期Unix系统中的信号机制比较简单和原始，后来在实践中暴露出一些问题，因此，把那些建立在早期机制上的信号叫做"不可靠信号"，信号值小于SIGRTMIN(Red hat 7.2中，SIGRTMIN=32，SIGRTMAX=63)的信号都是不可靠信号。这就是"不可靠信号"的来源。它的主要问题是：进程每次处理信号后，就将对信号的响应设置为默认动作。在某些情况下，将导致对信号的错误处理；因此，用户如果不希望这样的操作，那么就要在信号处理函数结尾再一次调用signal()，重新安装该信号。</p>
            <p style="LINE-HEIGHT: normal"><br style="LINE-HEIGHT: normal"></p>
            <p style="LINE-HEIGHT: normal"></p>
            <p style="LINE-HEIGHT: normal">另外，我再做一些补充，产生RST响应以至于系统发出SIGPIPE信号，应该分为两种情况:</p>
            <p style="LINE-HEIGHT: normal">1. 客户端到服务端之间网络断掉，或者服务端断电等，物理连接断掉了，这种情况下客户端不会退出，send函数正常执行，不会感觉到自己出错。因为由于物理网络断开，服务端不会给客户端回应错误消息，没有RST响应，自然也不会产生SIGPIPE信号。但是当服务端再恢复正常的时候，对客户端send来的消息会产生RST响应，客户端就收到SIGPIPE信号了，程序退出，但是这时send函数是能够返回 -1的。可以进行异常处理。</p>
            <p style="LINE-HEIGHT: normal">2.客户端到服务端的网络能通，服务程序挂掉，客户端程序会马上退出，因为服务端能正常返回错误消息，客户端收到，SIGPIPE信号就产生了。不过我不确定此时服务端返回是的RST响应，抓包来看没有RST标志。水平有限，只写到这了。</p>
            <p style="LINE-HEIGHT: normal"><br style="LINE-HEIGHT: normal"></p>
            <p style="LINE-HEIGHT: normal">文章出处：<a style="LINE-HEIGHT: normal" href="http://www.diybl.com/course/6_system/linux/Linuxjs/20081020/150832.html"><u><font color=#0000ff>http://www.diybl.com/course/6_system/linux/Linuxjs/20081020/150832.html</font></u></a></p>
            </div>
            </td>
        </tr>
    </tbody>
</table>
</span></span><br class=Apple-interchange-newline>
<img src ="http://www.cppblog.com/elva/aggbug/90761.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2009-07-21 18:56 <a href="http://www.cppblog.com/elva/archive/2009/07/21/90761.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于SIGPIPE导致的程序退出</title><link>http://www.cppblog.com/elva/archive/2008/09/10/61544.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Wed, 10 Sep 2008 14:49:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2008/09/10/61544.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/61544.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2008/09/10/61544.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/61544.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/61544.html</trackback:ping><description><![CDATA[<p>收集一些网上的资料，以便参考：<br><br><a href="http://blog.chinaunix.net/u2/69143/showart_1087349.html">http://blog.chinaunix.net/u2/69143/showart_1087349.html</a><br><br>&nbsp;&nbsp;&nbsp;&nbsp; 当服务器close一个连接时，若client端接着发数据。根据TCP协议的规定，会收到一个RST响应，client再往这个服务器发送数据时，系统会发出一个SIGPIPE信号给进程，告诉进程这个连接已经断开了，不要再写了。<br>&nbsp;&nbsp;&nbsp; 根据信号的默认处理规则SIGPIPE信号的默认执行动作是terminate(终止、退出),所以client会退出。若不想客户端退出可以把SIGPIPE设为SIG_IGN<br><br>&nbsp;&nbsp;&nbsp; 如:&nbsp;&nbsp;&nbsp; signal(SIGPIPE,SIG_IGN);<br>&nbsp;&nbsp;&nbsp; 这时SIGPIPE交给了系统处理。<br><br>&nbsp; 服务器采用了fork的话，要收集垃圾进程，防止僵尸进程的产生，可以这样处理：<br>&nbsp; signal(SIGCHLD,SIG_IGN);　交给系统init去回收。<br>&nbsp;&nbsp; 这里子进程就不会产生僵尸进程了。<br><br><br>http://www.cublog.cn/u/31357/showart_242605.html</p>
<br>好久没做过C开发了，最近重操旧业。
<div>听说另外一个项目组socket开发遇到问题，发送端和接受端数据大小不一致。建议他们采用writen的重发机制，以避免信号中断错误。采用后还是有问题。PM让我帮忙研究下。</div>
<div>UNP n年以前看过，很久没做过底层开发，手边也没有UNP vol1这本书，所以做了个测试程序，研究下实际可能发生的情况了。</div>
<div>&nbsp;</div>
<div>测试环境：AS3和redhat 9(缺省没有nc)</div>
<div>&nbsp;</div>
<div>先下载unp源码:</div>
<div>wget http://www.unpbook.com/unpv13e.tar.gz</div>
<div>tar xzvf *.tar.gz;</div>
<div>configure;make lib.</div>
<div>然后参考str_cli.c和tcpcli01.c，写了测试代码client.c</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<table style="border-collapse: collapse;" bgcolor="#f1f1f1" border="1" bordercolor="#999999" cellpadding="0" cellspacing="0" width="95%">
    <tbody>
        <tr>
            <td>
            <p style="margin: 5px; line-height: 150%;"><code><span style="color: #000000;"><span style="color: #0000cc;">#</span><span style="color: #ff0000;">include</span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff00ff;">"unp.h"</span><br><br><span style="color: #0000cc;">#</span><span style="color: #ff0000;">define</span> MAXBUF 40960<br><span style="color: #0000ff;">void</span> processSignal<span style="color: #0000cc;">(</span><span style="color: #0000ff;">int</span> signo<span style="color: #0000cc;">)</span><br><span style="color: #0000cc;">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff0000;">printf</span><span style="color: #0000cc;">(</span><span style="color: #ff00ff;">"Signal is %d\n"</span><span style="color: #0000cc;">,</span> signo<span style="color: #0000cc;">)</span><span style="color: #0000cc;">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff0000;">signal</span><span style="color: #0000cc;">(</span>signo<span style="color: #0000cc;">,</span> processSignal<span style="color: #0000cc;">)</span><span style="color: #0000cc;">;</span><br><span style="color: #0000cc;">}</span><br><span style="color: #0000ff;">void</span><br>str_cli<span style="color: #0000cc;">(</span><span style="color: #ff0000;">FILE</span> <span style="color: #0000cc;">*</span>fp<span style="color: #0000cc;">,</span> <span style="color: #0000ff;">int</span> sockfd<span style="color: #0000cc;">)</span><br><span style="color: #0000cc;">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">char</span>&nbsp;&nbsp;&nbsp;&nbsp;sendline<span style="color: #0000cc;">[</span>MAXBUF<span style="color: #0000cc;">]</span><span style="color: #0000cc;">,</span> recvline<span style="color: #0000cc;">[</span>MAXBUF<span style="color: #0000cc;">]</span><span style="color: #0000cc;">;</span><br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">while</span> <span style="color: #0000cc;">(</span>1<span style="color: #0000cc;">)</span> <span style="color: #0000cc;">{</span><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff0000;">memset</span><span style="color: #0000cc;">(</span>sendline<span style="color: #0000cc;">,</span> <span style="color: #ff00ff;">'a'</span><span style="color: #0000cc;">,</span> <span style="color: #0000ff;">sizeof</span><span style="color: #0000cc;">(</span>sendline<span style="color: #0000cc;">)</span><span style="color: #0000cc;">)</span><span style="color: #0000cc;">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff0000;">printf</span><span style="color: #0000cc;">(</span><span style="color: #ff00ff;">"Begin send %d data\n"</span><span style="color: #0000cc;">,</span> MAXBUF<span style="color: #0000cc;">)</span><span style="color: #0000cc;">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Writen<span style="color: #0000cc;">(</span>sockfd<span style="color: #0000cc;">,</span> sendline<span style="color: #0000cc;">,</span> <span style="color: #0000ff;">sizeof</span><span style="color: #0000cc;">(</span>sendline<span style="color: #0000cc;">)</span><span style="color: #0000cc;">)</span><span style="color: #0000cc;">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff0000;">sleep</span><span style="color: #0000cc;">(5</span><span style="color: #0000cc;">)</span><span style="color: #0000cc;">;</span><br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000cc;">}</span><br><span style="color: #0000cc;">}</span><br><br><span style="color: #0000ff;">int</span><br>main<span style="color: #0000cc;">(</span><span style="color: #0000ff;">int</span> argc<span style="color: #0000cc;">,</span> <span style="color: #0000ff;">char</span> <span style="color: #0000cc;">*</span><span style="color: #0000cc;">*</span>argv<span style="color: #0000cc;">)</span><br><span style="color: #0000cc;">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">int</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sockfd<span style="color: #0000cc;">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">struct</span> <span style="color: #ff0000;">sockaddr_in</span>&nbsp;&nbsp;&nbsp;&nbsp;servaddr<span style="color: #0000cc;">;</span><br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff0000;">signal</span><span style="color: #0000cc;">(</span>SIGPIPE<span style="color: #0000cc;">,</span> <span style="color: #ff0000;">SIG_IGN</span><span style="color: #0000cc;">)</span><span style="color: #0000cc;">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff9900;">//signal(SIGPIPE, processSignal);<br></span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span> <span style="color: #0000cc;">(</span>argc <span style="color: #0000cc;">!</span><span style="color: #0000cc;">=</span> 2<span style="color: #0000cc;">)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;err_quit<span style="color: #0000cc;">(</span><span style="color: #ff00ff;">"usage: tcpcli [port]"</span><span style="color: #0000cc;">)</span><span style="color: #0000cc;">;</span><br><br>&nbsp;&nbsp;&nbsp;&nbsp;sockfd <span style="color: #0000cc;">=</span> <span style="color: #ff0000;">Socket</span><span style="color: #0000cc;">(</span><span style="color: #ff0000;">AF_INET</span><span style="color: #0000cc;">,</span> <span style="color: #ff0000;">SOCK_STREAM</span><span style="color: #0000cc;">,</span> 0<span style="color: #0000cc;">)</span><span style="color: #0000cc;">;</span><br><br>&nbsp;&nbsp;&nbsp;&nbsp;bzero<span style="color: #0000cc;">(</span><span style="color: #0000cc;">&amp;</span>servaddr<span style="color: #0000cc;">,</span> <span style="color: #0000ff;">sizeof</span><span style="color: #0000cc;">(</span>servaddr<span style="color: #0000cc;">)</span><span style="color: #0000cc;">)</span><span style="color: #0000cc;">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;servaddr<span style="color: #0000cc;">.</span>sin_family <span style="color: #0000cc;">=</span> <span style="color: #ff0000;">AF_INET</span><span style="color: #0000cc;">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;servaddr<span style="color: #0000cc;">.</span>sin_port <span style="color: #0000cc;">=</span> <span style="color: #ff0000;">htons</span><span style="color: #0000cc;">(</span><span style="color: #ff0000;">atoi</span><span style="color: #0000cc;">(</span>argv<span style="color: #0000cc;">[</span>1<span style="color: #0000cc;">]</span><span style="color: #0000cc;">)</span><span style="color: #0000cc;">)</span><span style="color: #0000cc;">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;Inet_pton<span style="color: #0000cc;">(</span><span style="color: #ff0000;">AF_INET</span><span style="color: #0000cc;">,</span> <span style="color: #ff00ff;">"127.0.0.1"</span><span style="color: #0000cc;">,</span> <span style="color: #0000cc;">&amp;</span>servaddr<span style="color: #0000cc;">.</span>sin_addr<span style="color: #0000cc;">)</span><span style="color: #0000cc;">;</span><br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff0000;">Connect</span><span style="color: #0000cc;">(</span>sockfd<span style="color: #0000cc;">,</span> <span style="color: #0000cc;">(</span>SA <span style="color: #0000cc;">*</span><span style="color: #0000cc;">)</span> <span style="color: #0000cc;">&amp;</span>servaddr<span style="color: #0000cc;">,</span> <span style="color: #0000ff;">sizeof</span><span style="color: #0000cc;">(</span>servaddr<span style="color: #0000cc;">)</span><span style="color: #0000cc;">)</span><span style="color: #0000cc;">;</span><br><br>&nbsp;&nbsp;&nbsp;&nbsp;str_cli<span style="color: #0000cc;">(</span><span style="color: #ff0000;">stdin</span><span style="color: #0000cc;">,</span> sockfd<span style="color: #0000cc;">)</span><span style="color: #0000cc;">;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff9900;">/* do it all */</span><br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff0000;">exit</span><span style="color: #0000cc;">(</span>0<span style="color: #0000cc;">)</span><span style="color: #0000cc;">;</span><br><span style="color: #0000cc;">}</span><br></span></code></p>
            </td>
        </tr>
    </tbody>
</table>
<p>&nbsp;</p>
<p>为了方便观察错误输出，lib/writen.c也做了修改，加了些日志：</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<table style="border-collapse: collapse;" bgcolor="#f1f1f1" border="1" bordercolor="#999999" cellpadding="0" cellspacing="0" width="95%">
    <tbody>
        <tr>
            <td>
            <p style="margin: 5px; line-height: 150%;"><code><span style="color: #000000;"><span style="color: #ff9900;">/* include writen */</span><br><span style="color: #0000cc;">#</span><span style="color: #ff0000;">include</span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff00ff;">"unp.h"</span><br><br>ssize_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff9900;">/* Write "n" bytes to a descriptor. */</span><br>writen<span style="color: #0000cc;">(</span><span style="color: #0000ff;">int</span> fd<span style="color: #0000cc;">,</span> <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span> <span style="color: #0000cc;">*</span>vptr<span style="color: #0000cc;">,</span> <span style="color: #ff0000;">size_t</span> n<span style="color: #0000cc;">)</span><br><span style="color: #0000cc;">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff0000;">size_t</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nleft<span style="color: #0000cc;">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;ssize_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nwritten<span style="color: #0000cc;">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000cc;">*</span>ptr<span style="color: #0000cc;">;</span><br><br>&nbsp;&nbsp;&nbsp;&nbsp;ptr <span style="color: #0000cc;">=</span> vptr<span style="color: #0000cc;">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;nleft <span style="color: #0000cc;">=</span> n<span style="color: #0000cc;">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">while</span> <span style="color: #0000cc;">(</span>nleft <span style="color: #0000cc;">&gt;</span> 0<span style="color: #0000cc;">)</span> <span style="color: #0000cc;">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff0000;">printf</span><span style="color: #0000cc;">(</span><span style="color: #ff00ff;">"Begin Writen %d\n"</span><span style="color: #0000cc;">,</span> nleft<span style="color: #0000cc;">)</span><span style="color: #0000cc;">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span> <span style="color: #0000cc;">(</span> <span style="color: #0000cc;">(</span>nwritten <span style="color: #0000cc;">=</span> <span style="color: #ff0000;">write</span><span style="color: #0000cc;">(</span>fd<span style="color: #0000cc;">,</span> ptr<span style="color: #0000cc;">,</span> nleft<span style="color: #0000cc;">)</span><span style="color: #0000cc;">)</span> <span style="color: #0000cc;">&lt;</span><span style="color: #0000cc;">=</span> 0<span style="color: #0000cc;">)</span> <span style="color: #0000cc;">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span> <span style="color: #0000cc;">(</span>nwritten <span style="color: #0000cc;">&lt;</span> 0 <span style="color: #0000cc;">&amp;</span><span style="color: #0000cc;">&amp;</span> <span style="color: #ff0000;">errno</span> <span style="color: #0000cc;">=</span><span style="color: #0000cc;">=</span> EINTR<span style="color: #0000cc;">)</span> <span style="color: #0000cc;">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff0000;">printf</span><span style="color: #0000cc;">(</span><span style="color: #ff00ff;">"intterupt\n"</span><span style="color: #0000cc;">)</span><span style="color: #0000cc;">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nwritten <span style="color: #0000cc;">=</span> 0<span style="color: #0000cc;">;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff9900;">/* and call write() again */</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000cc;">}</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">else</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">return</span><span style="color: #0000cc;">(</span><span style="color: #0000cc;">-</span>1<span style="color: #0000cc;">)</span><span style="color: #0000cc;">;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff9900;">/* error */</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000cc;">}</span><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nleft <span style="color: #0000cc;">-</span><span style="color: #0000cc;">=</span> nwritten<span style="color: #0000cc;">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ptr <span style="color: #0000cc;">+</span><span style="color: #0000cc;">=</span> nwritten<span style="color: #0000cc;">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff0000;">printf</span><span style="color: #0000cc;">(</span><span style="color: #ff00ff;">"Already write %d, left %d, errno=%d\n"</span><span style="color: #0000cc;">,</span> nwritten<span style="color: #0000cc;">,</span> nleft<span style="color: #0000cc;">,</span> <span style="color: #ff0000;">errno</span><span style="color: #0000cc;">)</span><span style="color: #0000cc;">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000cc;">}</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">return</span><span style="color: #0000cc;">(</span>n<span style="color: #0000cc;">)</span><span style="color: #0000cc;">;</span><br><span style="color: #0000cc;">}</span><br><span style="color: #ff9900;">/* end writen */</span><br><br><span style="color: #0000ff;">void</span><br>Writen<span style="color: #0000cc;">(</span><span style="color: #0000ff;">int</span> fd<span style="color: #0000cc;">,</span> <span style="color: #0000ff;">void</span> <span style="color: #0000cc;">*</span>ptr<span style="color: #0000cc;">,</span> <span style="color: #ff0000;">size_t</span> nbytes<span style="color: #0000cc;">)</span><br><span style="color: #0000cc;">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span> <span style="color: #0000cc;">(</span>writen<span style="color: #0000cc;">(</span>fd<span style="color: #0000cc;">,</span> ptr<span style="color: #0000cc;">,</span> nbytes<span style="color: #0000cc;">)</span> <span style="color: #0000cc;">!</span><span style="color: #0000cc;">=</span> nbytes<span style="color: #0000cc;">)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;err_sys<span style="color: #0000cc;">(</span><span style="color: #ff00ff;">"writen error"</span><span style="color: #0000cc;">)</span><span style="color: #0000cc;">;</span><br><span style="color: #0000cc;">}</span><br></span></code></p>
            </td>
        </tr>
    </tbody>
</table>
<p>&nbsp;</p>
<p>client.c放在tcpclieserv目录下，修改了Makefile，增加了client.c的编译目标</p>
<p>&nbsp;</p>
<table style="border-collapse: collapse;" bgcolor="#f1f1f1" border="1" bordercolor="#999999" cellpadding="0" cellspacing="0" width="95%">
    <tbody>
        <tr>
            <td>
            <p style="margin: 5px; line-height: 150%;"><code><span style="color: #000000;"><br>client<span style="color: #0000cc;">:</span> client<span style="color: #0000cc;">.</span>c<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$<span style="color: #0000cc;">{</span>CC<span style="color: #0000cc;">}</span> $<span style="color: #0000cc;">{</span>CFLAGS<span style="color: #0000cc;">}</span> <span style="color: #0000cc;">-</span>o $@ $<span style="color: #0000cc;">&lt;</span> $<span style="color: #0000cc;">{</span>LIBS<span style="color: #0000cc;">}</span><br></span></code></p>
            </td>
        </tr>
    </tbody>
</table>
<p>&nbsp;</p>
<p>接着就可以开始测试了。</p>
<h2>测试1 忽略SIGPIPE信号，writen之前，对方关闭接受进程</h2>
<p>本机服务端：</p>
<div>nc -l -p 30000</div>
<div>&nbsp;</div>
<div>本机客户端:</div>
<div>./client 30000</div>
<div>Begin send 40960 data<br>Begin Writen 40960<br>Already write 40960, left 0, errno=0<br>Begin send 40960 data<br>Begin Writen 40960<br>Already write 40960, left 0, errno=0<br><font color="#ff0000">执行到上步停止服务端,client会继续显示:</font></div>
<div>Begin send 40960 data<br>Begin Writen 40960<br>writen error: Broken pipe(32)<br><strong>结论:可见write之前，对方socket中断，发送端write会返回-1,errno号为EPIPE(32)</strong></div>
<div>
<h2>测试2 catch SIGPIPE信号，writen之前，对方关闭接受进程</h2>
<p>修改客户端代码，catch sigpipe信号</p>
<p>
<table style="border-collapse: collapse;" bgcolor="#f1f1f1" border="1" bordercolor="#999999" cellpadding="0" cellspacing="0" width="95%">
    <tbody>
        <tr>
            <td>
            <p style="margin: 5px; line-height: 150%;"><code><span style="color: #000000;"><font face="新宋体"><span style="color: #ff9900;"><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font>//signal(SIGPIPE, SIG_IGN);<br></span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff0000;">signal</span><span style="color: #0000cc;">(</span>SIGPIPE<span style="color: #0000cc;">,</span> processSignal<span style="color: #0000cc;">)</span><span style="color: #0000cc;">;</span></font><br></span></code></p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>本机服务端：</p>
<div>nc -l -p 30000</div>
<div>&nbsp;</div>
<div>本机客户端:</div>
<div>make client</div>
<div>./client 30000</div>
</div>
<div>
<div>Begin send 40960 data<br>Begin Writen 40960<br>Already write 40960, left 0, errno=0<br>Begin send 40960 data<br>Begin Writen 40960<br>Already write 40960, left 0, errno=0<br><font color="#ff0000">执行到上步停止服务端,client会继续显示:</font></div>
<div>Begin send 40960 data<br>Begin Writen 40960<br>Signal is 13<br>writen error: Broken pipe(32)<br><strong>结论:可见write之前，对方socket中断，发送端write时，会先调用SIGPIPE响应函数，然后write返回-1,errno号为EPIPE(32)</strong></div>
<div><strong></strong>&nbsp;</div>
<div>
<h2>测试3 writen过程中，对方关闭接受进程</h2>
<p>为了方便操作，加大1次write的数据量，修改MAXBUF为4096000</p>
<p>本机服务端：</p>
<div>nc -l -p 30000</div>
<div>&nbsp;</div>
<div>本机客户端:</div>
<div>make client</div>
<div>./client 30000</div>
<div>
<div>Begin send 4096000 data<br>Begin Writen 4096000<br><font color="#ff0000">执行到上步停止服务端,client会继续显示:</font></div>
<div>Already write 589821, left 3506179, errno=0<br>Begin Writen 3506179<br>writen error: Connection reset by peer(104)<br><br><strong>结论:可见socket write中，对方socket中断，发送端write会先返回已经发送的字节数,再次write时返回-1,errno号为ECONNRESET(104)</strong></div>
</div>
<p>为什么以上测试，都是对方已经中断socket后，发送端再次write，结果会有所不同呢。从后来找到的UNP5.12,5.13能找到答案</p>
</div>
</div>
<table style="border-collapse: collapse;" bgcolor="#f1f1f1" border="1" bordercolor="#999999" cellpadding="0" cellspacing="0" width="95%">
    <tbody>
        <tr>
            <td>
            <p style="margin: 5px; line-height: 150%;">The client's call to readline may happen before the server's RST is received by the client, or it may happen after. If the readline happens before the RST is received, as we've shown in our example, the result is an unexpected EOF in the client. But if the RST arrives first, the result is an ECONNRESET ("Connection reset by peer") error return from readline. </p>
            </td>
        </tr>
    </tbody>
</table>
<p>以上解释了测试3的现象，write时，收到RST.</p>
<table style="border-collapse: collapse;" bgcolor="#f1f1f1" border="1" bordercolor="#999999" cellpadding="0" cellspacing="0" width="95%">
    <tbody>
        <tr>
            <td>
            <p style="margin: 5px; line-height: 150%;">What happens if the client ignores the error return from readline and writes more data to the server? This can happen, for example, if the client needs to perform two writes to the server before reading anything back, with the first write eliciting the RST.</p>
            <p style="margin: 5px; line-height: 150%;">The rule that applies is: When a process writes to a socket that has received an RST, the SIGPIPE signal is sent to the process. The default action of this signal is to terminate the process, so the process must catch the signal to avoid being involuntarily terminated.</p>
            <p style="margin: 5px; line-height: 150%;">If the process either catches the signal and returns from the signal handler, or ignores the signal, the write operation returns EPIPE. </p>
            </td>
        </tr>
    </tbody>
</table>
<p>以上解释了测试1，2的现象,write一个已经接受到RST的socket，系统内核会发送SIGPIPE给发送进程，如果进程catch/ignore这个信号，write都返回EPIPE错误.</p>
<p>因此,UNP建议应用根据需要处理SIGPIPE信号，至少不要用系统缺省的处理方式处理这个信号，系统缺省的处理方式是退出进程，这样你的应用就很难查处处理进程为什么退出。</p>
<br><a href="http://blog.csdn.net/shcyd/archive/2006/10/28/1354577.aspx">http://blog.csdn.net/shcyd/archive/2006/10/28/1354577.aspx</a><br><br>
<p>在Unix系统下，如果send在等待协议传送数据时网络断开的话，调用send的进程会接收到一个SIGPIPE信号，进程对该信号的默认处理是进程终止。<br>在Unix系统下，如果recv函数在等待协议接收数据时网络断开了，那么调用recv的进程会接收到一个SIGPIPE信号，进程对该信号的默认处理是进程终止。</p>
<p>处理方法：<br>在初始化时调用<strong><font color="#333399">signal(SIGPIPE,SIG_IGN)</font></strong>忽略该信号（只需一次）<br>其时send或recv函数将返回-1，errno为EPIPE，可视情况关闭socket或其他处理</p>
<p>gdb：<br>gdb默认收到sigpipe时中断程序，可调用<strong><font color="#333399">handle SIGPIPE nostop print</font></strong></p>
<p><font color="#993300">相关</font><br></p>
<p><strong>(1)SIG_DFL信号专用的默认动作:</strong><br>　　(a)如果默认动作是暂停线程，则该线程的执行被暂时挂起。当线程暂停期间，发送给线程的任何附加信号都不交付，直到该线程开始执行，但是SIGKILL除外。<br>　　(b)把挂起信号的信号动作设置成SIG_DFL，且其默认动作是忽略信号 (SIGCHLD)。 </p>
<p><strong>(2)SIG_IGN忽略信号</strong><br>　　(a)该信号的交付对线程没有影响<br>　　(b)系统不允许把SIGKILL或SIGTOP信号的动作设置为SIG_DFL </p>
<p><strong>(3)指向函数的指针--捕获信号</strong><br>　　(a)信号一经交付，接收线程就在指定地址上执行信号捕获程序。在信号捕 获函数返回后，接受线程必须在被中断点恢复执行。<br>　　(b)用C语言函数调用的方法进入信号捕捉程序:<br>　　　　void func (signo)<br>　　　　int signo;<br>　　　　func( )是指定的信号捕捉函数，signo是正被交付信号的编码<br>　　(c)如果SIGFPE,SIGILL或SIGSEGV信号不是由C标准定义的kill( )或raise( )函数所生成，则从信号SIGFPE,SIGILL,SIGSEGV的信号捕获函数正常返回后线程的行为是未定义的。<br>　　(d)系统不允许线程捕获SIGKILL和SIGSTOP信号。<br>　　(e)如果线程为SIGCHLD信号建立信号捕获函数，而该线程有未被等待的以终止的子线程时，没有规定是否要生成SIGCHLD信号来指明那个子线程。<br><br></p>
<p>每一种信号都被OSKit给予了一个符号名，对于32位的i386平台而言，一个字32位，因而信号有32种。下面的表给出了常用的符号名、描述和它们的信号值。 </p>
<p>符号名　　信号值 描述　　　　　　　　　　　　　　　　是否符合POSIX<br>SIGHUP　　1　　　在控制终端上检测到挂断或控制线程死亡　　是<br>SIGINT　　2　　　交互注意信号　　　　　　　　　　　　　　是<br>SIGQUIT　 3　　　交互中止信号　　　　　　　　　　　　　　是<br>SIGILL　　4　　　检测到非法硬件的指令　　　　　　　　　　是<br>SIGTRAP　 5　　　从陷阱中回朔　　　　　　　　　　　　　　否<br>SIGABRT　 6　　　异常终止信号　　　　　　　　　　　　　　是<br>SIGEMT　　7　　　EMT 指令　　　　　　　　　　　　　　　　否<br>SIGFPE　　8　　　不正确的算术操作信号　　　　　　　　　　是<br>SIGKILL　 9　　　终止信号　　　　　　　　　　　　　　　　是<br>SIGBUS　　10　　 总线错误　　　　　　　　　　　　　　　　否<br>SIGSEGV　 11　　 检测到非法的内存调用　　　　　　　　　　是<br>SIGSYS　　12　　 系统call的错误参数　　　　　　　　　　　否<br>SIGPIPE　 13　　 在无读者的管道上写　　　　　　　　　　　是<br>SIGALRM　 14　　 报时信号　　　　　　　　　　　　　　　　是<br>SIGTERM　 15　　 终止信号　　　　　　　　　　　　　　　　是<br>SIGURG　　16　　 IO信道紧急信号　　　　　　　　　　　　　否<br>SIGSTOP　 17　　 暂停信号　　　　　　　　　　　　　　　　是<br>SIGTSTP　 18　　 交互暂停信号　　　　　　　　　　　　　　是<br>SIGCONT　 19　　 如果暂停则继续　　　　　　　　　　　　　是<br>SIGCHLD　 20　　 子线程终止或暂停　　　　　　　　　　　　是<br>SIGTTIN　 21　　 后台线程组一成员试图从控制终端上读出　　是<br>SIGTTOU　 22　　 后台线程组的成员试图写到控制终端上　　　是<br>SIGIO　　 23　　 允许I/O信号 　　　　　　　　　　　　　　否<br>SIGXCPU　 24　　 超出CPU时限　　　　　　　　　　　　　　 否<br>SIGXFSZ　 25　　 超出文件大小限制　　　　　　　　　　　　否<br>SIGVTALRM 26　　 虚时间警报器　　　　　　　　　　　　　　否<br>SIGPROF　 27　　 侧面时间警报器　　　　　　　　　　　　　否<br>SIGWINCH　28　　 窗口大小的更改　　　　　　　　　　　　　否<br>SIGINFO　 29　　 消息请求　　　　　　　　　　　　　　　　否<br>SIGUSR1 　30　　 保留作为用户自定义的信号1　　　　　　　 是<br>SIGUSR2 　31　　 保留作为用户自定义的信号　　　　　　　　是&nbsp;<br><br><font color="#ff6600">注意</font>：Linux信号机制基本上是从Unix系统中继承过来的。早期Unix系统中的信号机制比较简单和原始，后来在实践中暴露出一些问题，因此，把那些建立在早期机制上的信号叫做"不可靠信号"，信号值小于SIGRTMIN(Red hat 7.2中，SIGRTMIN=32，SIGRTMAX=63)的信号都是不可靠信号。这就是"不可靠信号"的来源。它的主要问题是：进程每次处理信号后，就将对信号的响应设置为默认动作。在某些情况下，将导致对信号的错误处理；因此，用户如果不希望这样的操作，那么就要在信号处理函数结尾再一次调用signal()，重新安装该信号。</p>
<br>
<p><br></p>
<p>另外，我再做一些补充，产生RST响应以至于系统发出SIGPIPE信号，应该分为两种情况:</p>
<p>1. 客户端到服务端之间网络断掉，或者服务端断电等，物理连接断掉了，这种情况下客户端不会退出，send函数正常执行，不会感觉到自己出错。因为由于物理网络断开，服务端不会给客户端回应错误消息，没有RST响应，自然也不会产生SIGPIPE信号。但是当服务端再恢复正常的时候，对客户端send来的消息会产生RST响应，客户端就收到SIGPIPE信号了，程序退出，但是这时send函数是能够返回 -1的。可以进行异常处理。</p>
<p>2.客户端到服务端的网络能通，服务程序挂掉，客户端程序会马上退出，因为服务端能正常返回错误消息，客户端收到，SIGPIPE信号就产生了。不过我不确定此时服务端返回是的RST响应，抓包来看没有RST标志。水平有限，只写到这了。<br></p><img src ="http://www.cppblog.com/elva/aggbug/61544.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2008-09-10 22:49 <a href="http://www.cppblog.com/elva/archive/2008/09/10/61544.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>perl 把xml文件转换成csv文件 </title><link>http://www.cppblog.com/elva/archive/2008/08/11/58549.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Mon, 11 Aug 2008 11:34:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2008/08/11/58549.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/58549.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2008/08/11/58549.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/58549.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/58549.html</trackback:ping><description><![CDATA[<p>#!/usr/local/bin/perl</p>
<p># use module<br>use XML::Simple;<br>use Data::Dumper;</p>
<p># create object<br>$xml = new XML::Simple;</p>
<p># read XML file<br>$data = $xml-&gt;XMLin("DebugInfo.xml", ForceArray =&gt; 1);</p>
<p># print output<br>#print Dumper($data);<br>#print Dumper($data-&gt;{'employee'}[0]); <br>#print Dumper($data-&gt;{'employee'}[1]); </p>
<p>$data1=$data-&gt;{'DebugInfo'};</p>
<p>#print @{$data1};<br>open FILE,"&gt;&gt;debug.log";<br>foreach $item (@{$data1}){<br>print FILE "${$item}{UID}[0],";<br>print FILE "${$item}{ChannelID}[0],";<br>print FILE "${$item}{IPAddress}[0],";<br>if (${$item}{BufferMapString}[0] =~/^HASH/) <br>{print FILE ",n";}<br>else{print FILE "${$item}{BufferMapString}[0]n"};<br>}<br>close FILE;</p>
<img src ="http://www.cppblog.com/elva/aggbug/58549.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2008-08-11 19:34 <a href="http://www.cppblog.com/elva/archive/2008/08/11/58549.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux对稀疏（Sparse）文件的支持</title><link>http://www.cppblog.com/elva/archive/2008/06/26/54662.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Thu, 26 Jun 2008 05:47:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2008/06/26/54662.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/54662.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2008/06/26/54662.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/54662.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/54662.html</trackback:ping><description><![CDATA[<p><strong></p>
<p>稀疏（Sparse）文件的创建</strong></p>
<ol>
    <li>在EXT2/EXT3文件系统上可以使用dd创建稀疏文件：<br><br>
    <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">$&nbsp;dd&nbsp;if=/dev/zero&nbsp;of=fs.img&nbsp;bs=1M&nbsp;seek=1024&nbsp;count=0<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>0+0&nbsp;records&nbsp;in<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>0+0&nbsp;records&nbsp;out<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>$&nbsp;ls&nbsp;-lh&nbsp;fs.img<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>-rw-rw-r--&nbsp;&nbsp;1&nbsp;zhigang&nbsp;zhigang&nbsp;1.0G&nbsp;Feb&nbsp;&nbsp;5&nbsp;19:50&nbsp;fs.img<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>$&nbsp;du&nbsp;-sh&nbsp;fs.img<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fs.img<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
    <br></li>
    <li>使用C语言来创建一个稀疏文件的方法如下：<br><br>
    <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">$&nbsp;cat&nbsp;sparse.c<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">sys</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">types.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">sys</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">stat.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>#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><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>#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><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;main(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;argc,&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">argv[])<br><img id=Codehighlighter1_133_256_Open_Image onclick="this.style.display='none'; Codehighlighter1_133_256_Open_Text.style.display='none'; Codehighlighter1_133_256_Closed_Image.style.display='inline'; Codehighlighter1_133_256_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_133_256_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_133_256_Closed_Text.style.display='none'; Codehighlighter1_133_256_Open_Image.style.display='inline'; Codehighlighter1_133_256_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_133_256_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_133_256_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;fd&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;open(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">sparse.file</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,&nbsp;O_RDWR</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">O_CREAT);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;lseek(fd,&nbsp;</span><span style="COLOR: #000000">1024</span><span style="COLOR: #000000">,&nbsp;SEEK_CUR);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;write(fd,&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">\0</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>$&nbsp;gcc&nbsp;</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">o&nbsp;sparse&nbsp;sparse.c<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>$&nbsp;.</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">sparse<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>$&nbsp;ls&nbsp;</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">l&nbsp;sparse.file<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">r</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">x</span><span style="COLOR: #000000">--</span><span style="COLOR: #000000">x</span><span style="COLOR: #000000">---</span><span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&nbsp;zhigang&nbsp;zhigang&nbsp;</span><span style="COLOR: #000000">1025</span><span style="COLOR: #000000">&nbsp;Feb&nbsp;&nbsp;</span><span style="COLOR: #000000">5</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">23</span><span style="COLOR: #000000">:</span><span style="COLOR: #000000">12</span><span style="COLOR: #000000">&nbsp;sparse.file<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>]$&nbsp;du&nbsp;sparse.file<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">4</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sparse.file<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
    <br></li>
    <li>&nbsp;使用python来创建一个稀疏文件的方法如下： <br><br>
    <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">$&nbsp;cat&nbsp;sparse.py<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #008000">#</span><span style="COLOR: #008000">!/usr/bin/env&nbsp;python</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>f&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;open(</span><span style="COLOR: #800000">'</span><span style="COLOR: #800000">fs.img</span><span style="COLOR: #800000">'</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #800000">'</span><span style="COLOR: #800000">w</span><span style="COLOR: #800000">'</span><span style="COLOR: #000000">)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>f.seek(</span><span style="COLOR: #000000">1023</span><span style="COLOR: #000000">)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>f.write(</span><span style="COLOR: #800000">'</span><span style="COLOR: #800000">\n</span><span style="COLOR: #800000">'</span><span style="COLOR: #000000">)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>$&nbsp;python&nbsp;sparse.py<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>$&nbsp;ls&nbsp;</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">l&nbsp;fs.img<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">rw</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">rw</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">r</span><span style="COLOR: #000000">--</span><span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&nbsp;zhigang&nbsp;zhigang&nbsp;</span><span style="COLOR: #000000">1024</span><span style="COLOR: #000000">&nbsp;Feb&nbsp;&nbsp;</span><span style="COLOR: #000000">5</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">20</span><span style="COLOR: #000000">:</span><span style="COLOR: #000000">15</span><span style="COLOR: #000000">&nbsp;fs.img<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>$&nbsp;du&nbsp;fs.img<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">4</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fs.img<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
    <p><strong><br>文件稀疏化（sparsify）</strong></p>
    <p>下面的方法都可以将一个文件稀疏化。<br><br>1. cp:<br></p>
    <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">$&nbsp;cp&nbsp;</span><span style="COLOR: #000000">--</span><span style="COLOR: #000000">sparse</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">always&nbsp;file&nbsp;file.sparse</span></div>
    <p><br>cp缺省使用--sparse=auto，会自动探测源文件中是否有空洞，以决定目标文件是否为稀疏文件；使用--sparse=never会禁止创建稀疏文件。<br><br>2. cpio: <br></p>
    <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">$&nbsp;find&nbsp;file&nbsp;</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">cpio&nbsp;</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">pdmuv&nbsp;</span><span style="COLOR: #000000">--</span><span style="COLOR: #000000">sparse&nbsp;</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">tmp</span></div>
    <p><br>如果不加--sparse参数，稀疏文件中的空洞将被填满。 <br><br>3. tar: <br></p>
    <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">$&nbsp;tar&nbsp;cSf&nbsp;</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">&nbsp;file&nbsp;</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">&nbsp;(cd&nbsp;</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">tmp</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">tt;&nbsp;tar&nbsp;xpSf&nbsp;</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">)<img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
    <p><br>如果不加 -S --sparse参数，稀疏文件中的空洞将被填满。 <br><br></p>
    <p><strong>文件稀疏化（sparsify）效率比较</strong></p>
    <p>下面我们创建一个500M的稀疏文件，比较一下几种文件稀疏化方法的效率。 <br><br></p>
    <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">$&nbsp;dd&nbsp;if=/dev/zero&nbsp;of=file&nbsp;count=100&nbsp;bs=1M&nbsp;seek=400<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>100+0&nbsp;records&nbsp;in<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>100+0&nbsp;records&nbsp;out<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>$&nbsp;time&nbsp;cp&nbsp;--sparse=always&nbsp;file&nbsp;file.sparse<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>real&nbsp;&nbsp;&nbsp;&nbsp;0m0.626s<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>user&nbsp;&nbsp;&nbsp;&nbsp;0m0.205s<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>sys&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0m0.390s<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>$&nbsp;time&nbsp;tar&nbsp;cSf&nbsp;-&nbsp;file&nbsp;|&nbsp;(cd&nbsp;/tmp;&nbsp;tar&nbsp;xpSf&nbsp;-)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>real&nbsp;&nbsp;&nbsp;&nbsp;0m2.732s<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>user&nbsp;&nbsp;&nbsp;&nbsp;0m1.706s<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>sys&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0m0.915s<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>$&nbsp;time&nbsp;find&nbsp;file&nbsp;|cpio&nbsp;-pdmuv&nbsp;--sparse&nbsp;/tmp<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>/tmp/file<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>1024000&nbsp;blocks<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>real&nbsp;&nbsp;&nbsp;&nbsp;0m2.763s<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>user&nbsp;&nbsp;&nbsp;&nbsp;0m1.793s<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>sys&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0m0.946s<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
    <p><br>由此可见，上面几种文件稀疏化的方法中，cp的效率最高；tar和cpio由于使用管道，效率下降。 </p>
    <p><strong>使EXT2/EXT3文件系统稀疏化（sparsify）</strong></p>
    <p>如何是一个文件系统的映像文件稀疏化？Ron Yorston为大家提供了<a href="http://intgat.tigress.co.uk/rmy/uml/sparsify.html">几种方法</a>，我觉得下面的方法最简单： <br><br>1. 使用Ron Yorston的<a href="http://intgat.tigress.co.uk/rmy/uml/zerofree.c">zerofree</a>将文件系统中未使用的块清零。<br></p>
    <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">$&nbsp;gcc&nbsp;-o&nbsp;zerofree&nbsp;zerofree.c&nbsp;-lext2fs<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>$&nbsp;./zerofree&nbsp;fs.img</span></div>
    <p><br>2.使用cp命令使映像文件稀疏化： <br></p>
    <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">$&nbsp;cp&nbsp;--sparse=always&nbsp;fs.img&nbsp;fs_sparse.img</span></div>
    <p><br>&nbsp;</p>
    <p><strong>EXT2/EXT3文件系统的sparse_super参数</strong></p>
    <p>这个参数与EXT2/EXT3是否支持Sparse文件无关；当打开该参数时，文件系统将使用更少的超级块（Super block）备份，以节省空间。</p>
    <p>如下的命令可以查看该参数：<br></p>
    <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">#&nbsp;echo&nbsp;stats&nbsp;|&nbsp;debugfs&nbsp;/dev/hda2&nbsp;|&nbsp;grep&nbsp;-i&nbsp;features<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>Filesystem&nbsp;features:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;has_journal&nbsp;ext_attr&nbsp;resize_inode&nbsp;dir_index&nbsp;filetype&nbsp;needs_recovery&nbsp;sparse_super&nbsp;large_file</span></div>
    <p><br>或者：<br></p>
    <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">#&nbsp;tune2fs&nbsp;-l&nbsp;/dev/hda2&nbsp;|grep&nbsp;"Filesystem&nbsp;features"<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>Filesystem&nbsp;features:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;has_journal&nbsp;ext_attr&nbsp;resize_inode&nbsp;dir_index&nbsp;filetype&nbsp;needs_recovery&nbsp;sparse_super&nbsp;large_file</span></div>
    <p><br>可以通过使用： <br></p>
    <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">#&nbsp;tune2fs&nbsp;-O&nbsp;sparse_super</span></div>
    <p><br>或者：<br></p>
    <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">#&nbsp;tune2fs&nbsp;-s&nbsp;[0|1]</span></div>
    <p><br>来设置该参数。 </p>
    <p><strong>参考资料<br></p>
    <ol>
        <li>Keeping filesystem images sparse:</li>
    </ol>
    <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<a href="http://intgat.tigress.co.uk/rmy/uml/sparsify.html">http://intgat.tigress.co.uk/rmy/uml/sparsify.html</a>. </p>
    <!-- google_ad_section_end --></strong></li>
</ol>
<img src ="http://www.cppblog.com/elva/aggbug/54662.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2008-06-26 13:47 <a href="http://www.cppblog.com/elva/archive/2008/06/26/54662.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>GDB调试精粹及使用实例</title><link>http://www.cppblog.com/elva/archive/2008/06/18/53848.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Wed, 18 Jun 2008 05:30:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2008/06/18/53848.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/53848.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2008/06/18/53848.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/53848.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/53848.html</trackback:ping><description><![CDATA[&nbsp;一：列文件清单 <br>1． List <br>(gdb) list line1,line2 <br>二：执行程序 <br>要想运行准备调试的程序，可使用run命令，在它后面可以跟随发给该程序的任何参数，包括标准输入和标准输出说明符()和外壳通配符（*、？、[、]）在内。 <br>如果你使用不带参数的run命令，gdb就再次使用你给予前一条run命令的参数，这是很有用的。 <br>利用set args 命令就可以修改发送给程序的参数，而使用show args 命令就可以查看其缺省参数的列表。 <br>（gdb）set args &#8211;b &#8211;x <br>(gdb) show args <br>backtrace命令为堆栈提供向后跟踪功能。 <br>Backtrace 命令产生一张列表，包含着从最近的过程开始的所以有效过程和调用这些过程的参数。 <br>三：显示数据 <br>利用print 命令可以检查各个变量的值。 <br>(gdb) print p (p为变量名) <br>whatis 命令可以显示某个变量的类型 <br>(gdb) whatis p <br>type = int * <br>print 是gdb的一个功能很强的命令，利用它可以显示被调试的语言中任何有效的表达式。表达式除了包含你程序中的变量外，还可以包含以下内容： <br>l 对程序中函数的调用 <br>(gdb) print find_entry(1,0) <br>l 数据结构和其他复杂对象 <br>(gdb) print *table_start <br>$8={e=reference=&#8217;\000&#8217;,location=0x0,next=0x0} <br>l 值的历史成分 <br>(gdb)print $1 ($1为历史记录变量,在以后可以直接引用 $1 的值) <br>l 人为数组 <br>人为数组提供了一种去显示存储器块（数组节或动态分配的存储区）内容的方法。早期的调试程序没有很好的方法将任意的指针换成一个数组。就像对待参数一样，让我们查看内存中在变量h后面的10个整数，一个动态数组的语法如下所示： <br>base@length <br>因此，要想显示在h后面的10个元素，可以使用h@10： <br>(gdb)print h@10 <br>$13=(-1,345,23,-234,0,0,0,98,345,10) <br>四：<br><a href="http://www.sogou.com/sogoupedia?query=%E6%96%AD%E7%82%B9" target=_blank><font color=#00229c><u>断点</u></font></a><br>(breakpoint) <br>break命令（可以简写为b）可以用来在调试的程序中设置断点，该命令有如下四种形式： <br>l break line-number 使程序恰好在执行给定行之前停止。 <br>l break function-name 使程序恰好在进入指定的函数之前停止。 <br>l break line-or-function if condition 如果condition（条件）是真，程序到达指定行或函数时停止。 <br>l break routine-name 在指定例程的入口处设置断点 <br>如果该程序是由很多原文件构成的，你可以在各个原文件中设置断点，而不是在当前的原文件中设置断点，其方法如下： <br>(gdb) break filename:line-number <br>(gdb) break filename:function-name <br>要想设置一个条件断点，可以利用break if命令，如下所示： <br>(gdb) break line-or-function if expr <br>例： <br>(gdb) break 46 if testsize==100 <br>从断点继续运行：countinue 命令 <br>五．断点的管理 <br>1． 显示当前gdb的断点信息： <br>(gdb) info break <br>他会以如下的形式显示所有的断点信息： <br>Num Type Disp Enb Address What <br>1 breakpoint keep y 0x000028bc in init_random at qsort2.c:155 <br>2 breakpoint keep y 0x0000291c in init_organ at qsort2.c:168 <br>(gdb) <br>2.删除指定的某个断点： <br>(gdb) delete breakpoint 1 <br>该命令将会删除编号为1的断点，如果不带编号参数，将删除所有的断点 <br>(gdb) delete breakpoint <br>3.禁止使用某个断点 <br>(gdb) disable breakpoint 1 <br>该命令将禁止断点 1,同时断点信息的 (Enb)域将变为 n <br>4．允许使用某个断点 <br>(gdb) enable breakpoint 1 <br>该命令将允许断点 1,同时断点信息的 (Enb)域将变为 y <br>5．清除原文件中某一代码行上的所有断点 <br>(gdb)clean number <br>注：number 为原文件的某个代码行的行号 <br>六．变量的检查和赋值 <br>l whatis:识别数组或变量的类型 <br>l ptype:比whatis的功能更强，他可以提供一个结构的定义 <br>l set variable:将值赋予变量 <br>l print 除了显示一个变量的值外，还可以用来赋值 <br>七．单步执行 <br>l next <br>不进入的单步执行 <br>l step <br>进入的单步执行 <br>如果已经进入了某函数，而想退出该函数返回到它的调用函数中，可使用命令finish <br>八．函数的调用 <br>l call name 调用和执行一个函数 <br>(gdb) call gen_and_sork( 1234,1,0 ) <br>(gdb) call printf(&#8220;abcd&#8221;) <br>$1=4 <br>l finish 结束执行当前函数，显示其返回值（如果有的话） <br>九．机器语言工具 <br>有一组专用的gdb变量可以用来检查和修改计算机的通用寄存器，gdb提供了目前每一台计算机中实际使用的4个寄存器的标准名字： <br>l $pc ： 程序计数器 <br>l $fp ： 帧指针（当前堆栈帧） <br>l $sp ： 栈指针 <br>l $ps ： 处理器状态 <br>十．信号 <br>gdb<br>通常可以捕捉到发送给它的大多数信号，通过捕捉信号，它就可决定对于正在运行的进程要做些什么工作。例如，按CTRL-C将中断信号发送给gdb，通常就<br>会终止gdb。但是你或许不想中断gdb，真正的目的是要中断gdb正在运行的程序，因此，gdb要抓住该信号并停止它正在运行的程序，这样就可以执行某<br>些调试操作。 <br>Handle命令可控制信号的处理，他有两个参数，一个是信号名，另一个是接受到信号时该作什么。几种可能的参数是： <br>l nostop 接收到信号时，不要将它发送给程序，也不要停止程序。 <br>l stop 接受到信号时停止程序的执行，从而允许程序调试；显示一条表示已接受到信号的消息（禁止使用消息除外） <br>l print 接受到信号时显示一条消息 <br>l noprint 接受到信号时不要显示消息（而且隐含着不停止程序运行） <br>l pass 将信号发送给程序，从而允许你的程序去处理它、停止运行或采取别的动作。 <br>l nopass 停止程序运行，但不要将信号发送给程序。 <br>例如，假定你截获SIGPIPE信号，以防止正在调试的程序接受到该信号，而且只要该信号一到达，就要求该程序停止，并通知你。要完成这一任务，可利用如下命令： <br>(gdb) handle SIGPIPE stop print <br>请注意，UNIX的信号名总是采用大写字母！你可以用信号编号替代信号名 <br>如<br>果你的程序要执行任何信号处理操作，就需要能够测试其信号处理程序，为此，就需要一种能将信号发送给程序的简便方法，这就是signal命令的任务。该<br>命令的参数是一个数字或者一个名字，如SIGINT。假定你的程序已将一个专用的SIGINT（键盘输入，或CTRL-C；信号2）信号处理程序设置成采<br>取某个清理动作，要想测试该信号处理程序，你可以设置一个断点并使用如下命令： <br>（gdb） signal 2 <br>continuing with signal SIGINT(2) <br>该程序继续执行，但是立即传输该信号，而且处理程序开始运行. <br>十一. 原文件的搜索 <br>search text:该命令可显示在当前文件中包含text串的下一行。 <br>Reverse-search text:该命令可以显示包含text 的前一行。 <br>十二.UNIX接口 <br>shell 命令可启动UNIX外壳，CTRL-D退出外壳，返回到 gdb. <br>十三.命令的历史 <br>为了允许使用历史命令，可使用 set history expansion on 命令 <br>(gdb) set history expansion on <br>小结：常用的gdb命令 <br>backtrace 显示程序中的当前位置和表示如何到达当前位置的栈跟踪（同义词：where） <br>breakpoint 在程序中设置一个断点 <br>cd 改变当前工作目录 <br>clear 删除刚才停止处的断点 <br>commands 命中断点时，列出将要执行的命令 <br>continue 从断点开始继续执行 <br>delete 删除一个断点或监测点；也可与其他命令一起使用 <br>display 程序停止时显示变量和表达时 <br>down 下移栈帧，使得另一个函数成为当前函数 <br>frame 选择下一条continue命令的帧 <br>info 显示与该程序有关的各种信息 <br>jump 在源程序中的另一点开始运行 <br>kill 异常终止在gdb 控制下运行的程序 <br>list 列出相应于正在执行的程序的原文件内容 <br>next 执行下一个源程序行，从而执行其整体中的一个函数 <br>print 显示变量或表达式的值 <br>pwd 显示当前工作目录 <br>pype 显示一个数据结构（如一个结构或C++类）的内容 <br>quit 退出gdb <br>reverse-search 在源文件中反向搜索正规表达式 <br>run 执行该程序 <br>search 在源文件中搜索正规表达式 <br>set variable 给变量赋值 <br>signal 将一个信号发送到正在运行的进程 <br>step 执行下一个源程序行，必要时进入下一个函数 <br>undisplay display命令的反命令，不要显示表达式 <br>until 结束当前循环 <br>up 上移栈帧，使另一函数成为当前函数 <br>watch 在程序中设置一个监测点（即数据断点） <br>whatis 显示变量或函数类型 <br>**************************************************** <br>　GNU的调试器称为gdb，该程序是一个交互式工具，工作在字符模式。在 X Window 系统中，有一个gdb的前端图形工具，称为xxgdb。gdb 是功能强大的调试程序，可完成如下的调试任务： <br>　　* 设置断点； <br>　　* 监视程序变量的值； <br>　　* 程序的单步执行； <br>　　* 修改变量的值。 <br>　　在可以使用 gdb 调试程序之前，必须使用 -g 选项编译源文件。可在 makefile 中如下定义 CFLAGS 变量： <br>　　 CFLAGS = -g <br>　　 运行 gdb 调试程序时通常使用如下的命令： <br>　　 gdb progname <br>　　在 gdb 提示符处键入help，将列出命令的分类，主要的分类有： <br>　　* aliases：命令别名 <br>　　* breakpoints：断点定义； <br>　　* data：数据查看； <br>　　* files：指定并查看文件； <br>　　* internals：维护命令； <br>　　* running：程序执行； <br>　　* stack：调用栈查看； <br>　　* statu：状态查看； <br>　　* tracepoints：跟踪程序执行。 <br>　　键入 help 后跟命令的分类名，可获得该类命令的详细清单。 <br>gdb 的常用命令 <br>命令 解释 <br>　　break NUM 在指定的行上设置断点。 <br>　　bt 显示所有的调用栈帧。该命令可用来显示函数的调用顺序。 <br>　　clear 删除设置在特定源文件、特定行上的断点。其用法为clear FILENAME:NUM <br>　　continue 继续执行正在调试的程序。该命令用在程序由于处理信号或断点而 导致停止运行时。 <br>　　display EXPR 每次程序停止后显示表达式的值。表达式由程序定义的变量组成。 <br>　　file FILE 装载指定的可执行文件进行调试。 <br>　　help NAME 显示指定命令的帮助信息。 <br>　　info break 显示当前断点清单，包括到达断点处的次数等。 <br>　　info files 显示被调试文件的详细信息。 <br>　　info func 显示所有的函数名称。 <br>　　info local 显示当函数中的局部变量信息。 <br>　　info prog 显示被调试程序的执行状态。 <br>　　info var 显示所有的全局和静态变量名称。 <br>　　kill 终止正被调试的程序。 <br>　　list 显示源代码段。 <br>　　make 在不退出 gdb 的情况下运行 make 工具。 <br>　　next 在不单步执行进入其他函数的情况下，向前执行一行源代码。 <br>　　print EXPR 显示表达式 EXPR 的值。 <br>******gdb 使用范例************************ <br>----------------- <br>清单 一个有错误的 C 源程序 bugging.c <br>代码: <br>----------------- <br>1　＃i nclude <br>2 <br>3　static char buff [256]; <br>4　static char* string; <br>5　int main () <br>6　{ <br>7　　　printf ("Please input a string: "); <br>8　　　gets (string);　　 <br>9　　 printf ("\nYour string is: %s\n", string); <br>10 } <br>----------------- <br>　 上面这个程序非常简单，其目的是接受用户的输入，然后将用户的输入打印出来。该程序使用了一个未经过初始化的字符串地址 string，因此，编译并运行之后，将出现 Segment Fault 错误： <br>$ gcc -o bugging -g bugging.c <br>$ ./bugging <br>Please input a string: asfd <br>Segmentation fault (core dumped) <br>为了查找该程序中出现的问题，我们利用 gdb，并按如下的步骤进行： <br>1．运行 gdb bugging 命令，装入 bugging 可执行文件； <br>2．执行装入的 bugging 命令 run； <br>3．使用 where 命令查看程序出错的地方； <br>4．利用 list 命令查看调用 gets 函数附近的代码； <br>5．唯一能够导致 gets 函数出错的因素就是变量 string。用print命令查看 string 的值； <br>6．在 gdb 中，我们可以直接修改变量的值，只要将 string 取一个合法的指针值就可以了，为此，我们在第8行处设置断点 break 8； <br>7．程序重新运行到第 8行处停止，这时，我们可以用 set variable 命令修改 string 的取值； <br>8．然后继续运行，将看到正确的程序运行结果。<br><br><br><strong>本文来自ChinaUnix博客，如果查看原文请点：</strong><a href="http://blog.chinaunix.net/u1/40912/showart_318499.html" target=_blank><u><font color=#0000ff>http://blog.chinaunix.net/u1/40912/showart_318499.html</font></u></a> 
<img src ="http://www.cppblog.com/elva/aggbug/53848.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2008-06-18 13:30 <a href="http://www.cppblog.com/elva/archive/2008/06/18/53848.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>包末安装完全时，出错信息解决办法</title><link>http://www.cppblog.com/elva/archive/2008/04/02/46069.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Wed, 02 Apr 2008 09:35:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2008/04/02/46069.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/46069.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2008/04/02/46069.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/46069.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/46069.html</trackback:ping><description><![CDATA[ubunto linux 下包未安装完全导致的错误，例如java<br><br><br>You might want to run `apt-get -f install' to correct these:<br>
The following packages have unmet dependencies:<br>
sun-java6-jre: Depends: sun-java6-bin (= 6-00-2ubuntu2) but it is not going to be installed or<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;  ia32-sun-java6-bin (= 6-00-2ubuntu2) but it is not installable<br>
E: Unmet dependencies. Try 'apt-get -f install' with no packages (or specify a solution).<br>
<br>
解决方法：<br>
sudo apt-get install -f<br><br><br>apt-get使用参考：<br><br>
<p>apt-cache search # ——(package 搜索包)<br>
apt-cache show #——(package 获取包的相关信息，如说明、大小、版本等)<br>
sudo apt-get install # ——(package 安装包)<br>
sudo apt-get install # —&#8211;(package - - reinstall 重新安装包)<br>
sudo apt-get -f install # —&#8211;(强制安装?#&#8221;-f = &#8211;fix-missing&#8221;当是修复安装吧&#8230;)<br>
sudo apt-get remove #—&#8211;(package 删除包)<br>
sudo apt-get remove - - purge # ——(package 删除包，包括删除配置文件等)<br>
sudo apt-get autoremove &#8211;purge # —-(package 删除包及其依赖的软件包+配置文件等（只对6.10有效，强烈推荐）)<br>
sudo apt-get update #——更新源<br>
sudo apt-get upgrade #——更新已安装的包<br>
sudo apt-get dist-upgrade # ———升级系统<br>
sudo apt-get dselect-upgrade #——使用 dselect 升级<br>
apt-cache depends #——-(package 了解使用依赖)<br>
apt-cache rdepends # ——(package 了解某个具体的依赖?#当是查看该包被哪些包依赖吧&#8230;)<br>
sudo apt-get build-dep # ——(package 安装相关的编译环境)<br>
apt-get source #——(package 下载该包的源代码)<br>
sudo apt-get clean &amp;&amp; sudo apt-get autoclean # ——&#8211;清理下载文件的存档 &amp;&amp; 只清理过时的包<br>
sudo apt-get check #——-检查是否有损坏的依赖</p>
<script type="text/javascript"><!--  google_ad_client =" "pub-1539499085830808";"  //468x15, 创建于 07-11-22  google_ad_slot =" "8747841444";"  google_ad_width =" 468;"  google_ad_height =" 15;"  //--></script>
<br> <img src ="http://www.cppblog.com/elva/aggbug/46069.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2008-04-02 17:35 <a href="http://www.cppblog.com/elva/archive/2008/04/02/46069.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux-C-Socket编程 </title><link>http://www.cppblog.com/elva/archive/2007/05/24/24733.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Wed, 23 May 2007 17:53:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2007/05/24/24733.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/24733.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2007/05/24/24733.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/24733.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/24733.html</trackback:ping><description><![CDATA[本文内容提到的套接字都是Berkely socket.<br><br>实用套接字的四个步骤:<br>1 分配空间和初始化<br>2 连接<br>3 传送数据<br>4 关闭<br><br>具体算法:<br><br>服务器端:<br>#include &lt;sys/socket.h&gt;<br>#include &lt;netinet/in.h&gt;<br><br>int socket_descriptor;<br>socket_descriptor = socket(AF_INET, SOCK_STREAM, 0);<br><br>int port = 8000;<br>struct sockaddr_in sin;<br>sin.sin_family = AF_INET;<br>sin.sin_addr.s_addr = INADDR_ANY;<br>pin.sin_port = htons(port);<br><br>bind(socket_descriptor,(struct socketaddr *)&amp;sin, sizeof(sin) );<br><br>listen(socket_descriptor, 1024);<br><br>struct sockaddr_in pin;<br>int address_size;<br>int temp_socket_descriptor;<br><br>while(1) {<br>&nbsp; temp_socket_descriptor = accept(socket_descriptor,(struct socketaddr *)&amp;pin,&nbsp; sizeof(address_size));<br>&nbsp; ......<br>&nbsp; close(temp_socket_descriptor);<br>}<br><br><br>客户端:<br>#include &lt;sys/socket.h&gt;<br>#include &lt;netinet/in.h&gt;<br>#include &lt;netdb.h&gt;&nbsp;&nbsp;&nbsp;&nbsp; //直接影响sockaddr_in.sin_addr的填写<br><br>char * host_name = "127.0.0.1";<br>struct hostent * server_host_name;<br>server_host_name = gethostbyname(host_name);<br><br>int port = 8000;<br>struct sockaddr_in pin;<br>pin.sin_family = AF_INET;<br>pin.sin_addr.s_addr = htol(INADDR_ANY);<br>pin.sin_addr.s_addr = ((struct in_addr *)(server_host_name-&gt;h_addr))-&gt;s_addr; 或者 pin.sin_addr = *(struct in_addr *) server_host_name-&gt;h_addr;<br>pin.sin_port = htons(port);<br><br>int socket_descriptor;<br>socket_descriptor = socket(AF_INET, SOCK_STREAM, 0);<br>connect(socket_descriptor, (void *)&amp;pin, sizeof(pin));<br>.......<br>close(socket_descriptor);<br>
<img src ="http://www.cppblog.com/elva/aggbug/24733.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2007-05-24 01:53 <a href="http://www.cppblog.com/elva/archive/2007/05/24/24733.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>openssh配置说明 </title><link>http://www.cppblog.com/elva/archive/2007/05/24/24734.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Wed, 23 May 2007 17:53:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2007/05/24/24734.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/24734.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2007/05/24/24734.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/24734.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/24734.html</trackback:ping><description><![CDATA[<p>主题：openssh配置说明</p>
<p>相关文件：<br>&nbsp;&nbsp;openssh-clients-2.9p2-7.rpm<br>&nbsp;&nbsp;openssh-2.9p-7.rpm<br>&nbsp;&nbsp;openssh-server-2.9p2-7</p>
<p>内容：<br>SSH的英文全称是Secure SHell。通过使用SSH，你可以把所有传输的数据进行加密，这样"中间人"这种攻击方式就不可能实现了，而且也能够防止DNS和IP欺骗。还有一个额外的好处就是传输的数据是经过压缩的，所以可以加快传输的速度。SSH有很多功能，它既可以代替telnet，又可以为ftp、pop、甚至ppp提供一个安全的"通道"。</p>
<p>1.什么是SSH？<br>传统的网络服务程序，如：ftp、pop和telnet在本质上都是不安全的，因为它们在网络上用明文传送口令和数据，别有用心的人非常容易就可以截获这些口令和数据。而且，这些服务程序的安全验证方式也是有其弱点的，就是很容易受到"中间人"（man-in-the-middle）这种方式的攻击。所谓"中间人"的攻击方式，就是"中间人"冒充真正的服务器接收你的传给服务器的数据，然后再冒充你把数据传给真正的服务器。服务器和你之间的数据传送被"中间人"一转手做了手脚之后，就会出现很严重的问题。<br>SSH的英文全称是Secure SHell。通过使用SSH，你可以把所有传输的数据进行加密，这样"中间人"这种攻击方式就不可能实现了，而且也能够防止DNS和IP欺骗。还有一个额外的好处就是传输的数据是经过压缩的，所以可以加快传输的速度。SSH有很多功能，它既可以代替telnet，又可以为ftp、pop、甚至ppp提供一个安全的"通道"。<br>最初SSH是由芬兰的一家公司开发的。但是因为受版权和加密算法的限制，现在很多人都转而使用OpenSSH。OpenSSH是SSH的替代软件，而且是免费的，可以预计将来会有越来越多的人使用它而不是SSH。<br>SSH是由客户端和服务端的软件组成的，有两个不兼容的版本分别是：1.x和2.x。用SSH 2.x的客户程序是不能连接到SSH 1.x的服务程序上去的。OpenSSH 2.x同时支持SSH 1.x和2.x。</p>
<p>2.SSH的安全验证是如何工作的<br>从客户端来看，SSH提供两种级别的安全验证。<br>第一种级别（基于口令的安全验证）只要你知道自己帐号和口令，就可以登录到远程主机。所有传输的数据都会被加密，但是不能保证你正在连接的服务器就是你想连接的服务器。可能会有别的服务器在冒充真正的服务器，也就是受到"中间人"这种方式的攻击。<br>第二种级别（基于密匙的安全验证）需要依靠密匙，也就是你必须为自己创建一对密匙，并把公用密匙放在需要访问的服务器上。如果你要连接到SSH服务器上，客户端软件就会向服务器发出请求，请求用你的密匙进行安全验证。服务器收到请求之后，先在你在该服务器的家目录下寻找你的公用密匙，然后把它和你发送过来的公用密匙进行比较。如果两个密匙一致，服务器就用公用密匙加密"质询"（challenge）并把它发送给客户端软件。客户端软件收到"质询"之后就可以用你的私人密匙解密再把它发送给服务器。<br>用这种方式，你必须知道自己密匙的口令。但是，与第一种级别相比，第二种级别不需要在网络上传送口令。<br>第二种级别不仅加密所有传送的数据，而且"中间人"这种攻击方式也是不可能的（因为他没有你的私人密匙）。但是整个登录的过程可能需要10秒。</p>
<p>3.安装并测试OpenSSH<br>因为受到美国法律的限制，在很多Linux的发行版中都没有包括OpenSSH。但是，可以从网络上下载并安装OpenSSH<br>安装完OpenSSH之后，用下面命令测试一下：<br>ssh -l [your accountname on the remote host] [address of the remote host]</p>
<p>如果OpenSSH工作正常，你会看到下面的提示信息：<br>The authenticity of host [hostname] can't be established.<br>Key fingerprint is 1024 5f:a0:0b:65:d3:82:df:ab:44:62:6d:98:9c:fe:e9:52.<br>Are you sure you want to continue connecting (yes/no)?<br>OpenSSH告诉你它不知道这台主机，但是你不用担心这个问题，因为你是第一次登录这台主机。键入"yes"。这将把这台主机的"识别标记"加到"~/.ssh/know_hosts"文件中。第二次访问这台主机的时候就不会再显示这条提示信息了。<br>然后，SSH提示你输入远程主机上你的帐号的口令。输入完口令之后，就建立了SSH连接，这之后就可以象使用telnet那样使用SSH了。</p>
<p>4.SSH的密匙<br>4.1 生成你自己的密匙对<br>生成并分发你自己的密匙有两个好处：<br>可以防止"中间人"这种攻击方式 <br>可以只用一个口令就登录到所有你想登录的服务器上 <br>用下面的命令可以生成密匙：<br>ssh-keygen如果远程主机使用的是SSH 2.x就要用这个命令：</p>
<p>ssh-keygen -d在同一台主机上同时有SSH1和SSH2的密匙是没有问题的，因为密匙是存成不同的文件的。</p>
<p>ssh-keygen命令运行之后会显示下面的信息：<br>Generating RSA keys: ............................ooooooO......ooooooO<br>Key generation complete.<br>Enter file in which to save the key (/home/[user]/.ssh/identity):<br>[按下ENTER就行了]<br>Created directory '/home/[user]/.ssh'.<br>Enter passphrase (empty for no passphrase):<br>[输入的口令不会显示在屏幕上]<br>Enter same passphrase again:<br>[重新输入一遍口令，如果忘记了口令就只能重新生成一次密匙了]<br>Your identification has been saved in /home/[user]/.ssh/identity.<br>[这是你的私人密匙]<br>Your public key has been saved in /home/[user]/.ssh/identity.pub.<br>The key fingerprint is: 2a:dc:71:2f:27:84:a2:e4:a1:1e:a9:63:e2:fa:a5:89 [user]@[local machine]<br>"ssh-keygen -d"做的是几乎同样的事，但是把一对密匙存为（默认情况下）"/home/[user]/.ssh/id_dsa"（私人密匙）和"/home/[user]/.ssh/id_dsa.pub"（公用密匙）。</p>
<p>现在你有一对密匙了：公用密匙要分发到所有你想用ssh登录的远程主机上去；私人密匙要好好地保管防止别人知道你的私人密匙。用"ls -l ~/.ssh/identity"或"ls -l ~/.ssh/id_dsa"所显示的文件的访问权限必须是"-rw-------"。<br>如果你怀疑自己的密匙已经被别人知道了，不要迟疑马上生成一对新的密匙。当然，你还要重新分发一次公用密匙。</p>
<p>4.2 分发公用密匙<br>在每一个你需要用SSH连接的远程服务器上，你要在自己的家目录下创建一个".ssh"的子目录，把你的公用密匙"identity.pub" 拷贝到这个目录下并把它重命名为"authorized_keys"。然后执行：<br>chmod 644 .ssh/authorized_keys<br>这一步是必不可少的。如果除了你之外别人对"authorized_keys"文件也有写的权限，SSH就不会工作。<br>如果你想从不同的计算机登录到远程主机，"authorized_keys"文件也可以有多个公用密匙。在这种情况下，必须在新的计算机上重新生成一对密匙，然后把生成的"identify.pub"文件拷贝并粘贴到远程主机的"authorized_keys"文件里。当然在新的计算机上你必须有一个帐号，而且密匙是用口令保护的。有一点很重要，就是当你取消了这个帐号之后，别忘了把这一对密匙删掉。</p>
<p>5.配置SSH<br>5.1 配置客户端的软件<br>OpenSSH有三种配置方式：命令行参数、用户配置文件和系统级的配置文件（"/etc/ssh/ssh_config"）。命令行参数优先于配置文件，用户配置文件优先于系统配置文件。所有的命令行的参数都能在配置文件中设置。因为在安装的时候没有默认的用户配置文件，所以要把"/etc/ssh/ssh_config"拷贝并重新命名为"~/.ssh/config"。<br>标准的配置文件大概是这样的：<br>[lots of explanations and possible options listed]<br># Be paranoid by default<br>Host *<br>ForwardAgent no<br>ForwardX11 no<br>FallBackToRsh no<br>还有很多选项的设置可以用"man ssh"查看"CONFIGURATION FILES"这一章。<br>配置文件是按顺序读取的。先设置的选项先生效。<br>假定你在<a href="http://www.foobar.com/">www.foobar.com</a>上有一个名为"bilbo"的帐号。而且你要把"ssh-agent"和"ssh-add"结合起来使用并且使用数据压缩来加快传输速度。因为主机名太长了，你懒得输入这么长的名字，用"fbc"作为"<a href="http://www.foobar.com/">www.foobar.com</a>"的简称。你的配置文件可以是这样的：<br>Host *fbc<br>HostName <a href="http://www.foobar.com/">www.foobar.com</a><br>User bilbo<br>ForwardAgent yes<br>Compression yes<br># Be paranoid by default<br>Host *<br>ForwardAgent no<br>ForwardX11 no<br>FallBackToRsh no<br>你输入"ssh fbc"之后，SSH会自动地从配置文件中找到主机的全名，用你的用户名登录并且用"ssh-agent"管理的密匙进行安全验证。这样很方便吧！<br>用SSH连接到其它远程计算机用的还是"paranoid（偏执）"默认设置。如果有些选项没有在配置文件或命令行中设置，那么还是使用默认的"paranoid"设置。<br>在我们上面举的那个例子中，对于到<a href="http://www.foobar.com/">www.foobar.com</a>的SSH连接："ForwardAgent"和"Compression"被设置为"Yes"；其它的设置选项（如果没有用命令行参数）"ForwardX11"和"FallBackToRsh"都被设置成"No"。<br>其它还有一些需要仔细看一看的设置选项是：<br>CheckHostIP yes&nbsp;&nbsp; 这个选项用来进行IP地址的检查以防止DNS欺骗。</p>
<p>CompressionLevel&nbsp; 压缩的级别从"1"（最快）到"9"（压缩率最高）。默认值为"6"。</p>
<p>ForwardX11 yes&nbsp; 为了在本地运行远程的X程序必须设置这个选项。</p>
<p>LogLevel DEBUG&nbsp; 当SSH出现问题的时候，这选项就很有用了。默认值为"INFO"。</p>
<p>5.2 配置服务端的软件<br>SSH服务器的配置使用的是"/etc/ssh/sshd_config"配置文件，这些选项的设置在配置文件中已经有了一些说明而且用"man sshd"也可以查看帮助。请注意OpenSSH对于SSH 1.x和2.x没有不同的配置文件。<br>在默认的设置选项中需要注意的有：<br>PermitRootLogin yes&nbsp;&nbsp; 最好把这个选项设置成"PermitRootLogin without-password"，这样"root"用户就不能从没有密匙的计算机上登录。把这个选项设置成"no"将禁止"root"用户登录，只能用"su"命令从普通用户转成"root"。<br>X11Forwarding no&nbsp;&nbsp; 把这个选项设置成"yes"允许用户运行远程主机上的X程序。就算禁止这个选项也不能提高服务器的安全因为用户可以安装他们自己的转发器（forwarder），请参看"man sshd"。<br>PasswordAuthentication yes&nbsp; 把这个选项设置为"no"只允许用户用基于密匙的方式登录。这当然会给那些经常需要从不同主机登录的用户带来麻烦，但是这能够在很大程度上提高系统的安全性。基于口令的登录方式有很大的弱点。<br># Subsystem /usr/local/sbin/sftpd&nbsp;&nbsp; 把最前面的＃号去掉并且把路径名设置成"/usr/bin/sftpserv"，用户就能使用"sftp"（安全的FTP）了（sftpserv在sftp软件包中）。因为很多用户对FTP比较熟悉而且"scp"用起来也有一些麻烦，所以"sftp"还是很有用的。而且2.0.7版本以后的图形化的ftp工具"gftp"也支持"sftp"。</p>
<p>6.拷贝文件<br>6.1 用"scp"拷贝文件<br>SSH提供了一些命令和shell用来登录远程服务器。在默认情况下它不允许你拷贝文件，但是还是提供了一个"scp"命令。<br>假定你想把本地计算机当前目录下的一个名为"dumb"的文件拷贝到远程服务器<a href="http://www.foobar.com/">www.foobar.com</a>上你的家目录下。而且你在远程服务器上的帐号名为"bilbo"。<br>可以用这个命令：scp dumb <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#98;&#105;&#108;&#98;&#111;&#64;&#119;&#119;&#119;&#46;&#102;&#111;&#111;&#98;&#97;&#114;&#46;&#99;&#111;&#109;">bilbo@www.foobar.com</a>:.<br>把文件拷贝回来用这个命令：scp <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#98;&#105;&#108;&#98;&#111;&#64;&#119;&#119;&#119;&#46;&#102;&#111;&#111;&#98;&#97;&#114;&#46;&#99;&#111;&#109;&#58;&#100;&#117;&#109;&#98;">bilbo@www.foobar.com:dumb</a> .<br>"scp"调用SSH进行登录，然后拷贝文件，最后调用SSH关闭这个连接。<br>如果在你的"~/.ssh/config"文件中已经为<a href="http://www.foobar.com/">www.foobar.com</a>做了这样的配置：<br>Host *fbc<br>HostName <a href="http://www.foobar.com/">www.foobar.com</a><br>User bilbo<br>ForwardAgent yes<br>那么你就可以用"fbc"来代替"<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#98;&#105;&#108;&#98;&#111;&#64;&#119;&#119;&#119;&#46;&#102;&#111;&#111;&#98;&#97;&#114;&#46;&#99;&#111;&#109;">bilbo@www.foobar.com</a>"，命令就简化为"scp dumb fbc:."。<br>"scp"假定你在远程主机上的家目录为你的工作目录。如果你使用相对目录就要相对于家目录。<br>用"scp"命令的"-r"参数允许递归地拷贝目录。"scp"也可以在两个不同的远程主机之间拷贝文件。<br>有时候你可能会试图作这样的事：用SSH登录到<a href="http://www.foobar.com/">www.foobar.com</a>上之后，输入命令"scp [local machine]:dumb ."想用它把本地的"dumb"文件拷贝到你当前登录的远程服务器上。这时候你会看到下面的出错信息：<br>ssh: secure connection to [local machine] refused<br>之所以会出现这样的出错信息是因为你运行的是远程的"scp"命令，它试图登录到在你本地计算机上运行的SSH服务程序&#8230;&#8230;所以最好在本地运行"scp"除非你的本地计算机也运行SSH服务程序。</p>
<p>6.2 用"sftp"拷贝文件<br>如果你习惯使用ftp的方式拷贝文件，可以试着用"sftp"。"sftp"建立用SSH加密的安全的FTP连接通道，允许使用标准的ftp命令。还有一个好处就是"sftp"允许你通过"exec"命令运行远程的程序。从2.0.7版以后，图形化的ftp客户软件"gftp"就支持"sftp"。<br>如果远程的服务器没有安装sftp服务器软件"sftpserv"，可以把"sftpserv"的可执行文件拷贝到你的远程的家目录中（或者在远程计算机的$PATH环境变量中设置的路径）。"sftp"会自动激活这个服务软件，你没有必要在远程服务器上有什么特殊的权限。</p>
<p>6.3 用"rsync"拷贝文件<br>"rsync"是用来拷贝、更新和移动远程和本地文件的一个有用的工具，很容易就可以用"-e ssh"参数和SSH结合起来使用。"rsync"的一个优点就是，不会拷贝全部的文件，只会拷贝本地目录和远程目录中有区别的文件。而且它还使用很高效的压缩算法，这样拷贝的速度就很快。</p>
<p>6.4 用"加密通道"的ftp拷贝文件<br>如果你坚持要用传统的FTP客户软件。SSH可以为几乎所有的协议提供"安全通道"。FTP是一个有一点奇怪的协议（例如需要两个端口）而且不同的服务程序和服务程序之间、客户程序和客户程序之间还有一些差别。<br>实现"加密通道"的方法是使用"端口转发"。你可以把一个没有用到的本地端口（通常大于1000）设置成转发到一个远程服务器上，然后只要连接本地计算机上的这个端口就行了。有一点复杂是吗？<br>其实一个基本的想法就是，转发一个端口，让SSH在后台运行，用下面的命令：<br>ssh [user@remote host] -f -L 1234:[remote host]:21 tail -f /etc/motd<br>接着运行FTP客户，把它设置到指定的端口：<br>lftp -u [username] -p 1234 localhost<br>当然，用这种方法很麻烦而且很容易出错。所以最好使用前三种方法。</p>
<p>7.用SSH设置"加密通道"<br>7.1 "加密通道"的基础知识<br>SSH的"加密通道"是通过"端口转发"来实现的。你可以在本地端口（没有用到的）和在远程服务器上运行的某个服务的端口之间建立"加密通道"。然后只要连接到本地端口。所有对本地端口的请求都被SSH加密并且转发到远程服务器的端口。当然只有远程服务器上运行SSH服务器软件的时候"加密通道"才能工作。可以用下面命令检查一些远程服务器是否运行SSH服务：<br>telnet [full name of remote host] 22</p>
<p>如果收到这样的出错信息：telnet: Unable to connect to remote host: Connection refused</p>
<p>就说明远程服务器上没有运行SSH服务软件。</p>
<p>端口转发使用这样的命令语法：<br>ssh -f [username@remote host] -L [local port]:[full name of remote host]:[remote port] [some command]<br>你不仅可以转发多个端口而且可以在"~/.ssh/config"文件中用"LocalForward"设置经常使用的一些转发端口。</p>
<p>7.2 为POP加上"加密通道"<br>你可以用POP协议从服务器上取email。为POP加上"加密通道"可以防止POP的密码被网络监听器（sniffer）监听到。还有一个好处就是SSH的压缩方式可以让邮件传输得更快。<br>假定你在pop.foobar.com上有一个POP帐号，你的用户名是"bilbo"你的POP口令是"topsecret"。用来建立SSH"加密通道"的命令是：<br>ssh -f -C <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#98;&#105;&#108;&#98;&#111;&#64;&#112;&#111;&#112;&#46;&#102;&#111;&#111;&#98;&#97;&#114;&#46;&#99;&#111;&#109;">bilbo@pop.foobar.com</a> -L 1234:pop.foobar.com:110 sleep 5<br>（如果要测试，可以把"sleep"的值加到500）。运行这个命令之后会提示你输入POP口令：<br><a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#98;&#105;&#108;&#98;&#111;&#64;&#112;&#111;&#112;&#46;&#102;&#111;&#111;&#98;&#97;&#114;&#46;&#99;&#111;&#109;&#39;&#115;">bilbo@pop.foobar.com's</a> password:<br>输入口令之后就可以用"telnet"连接到本地的转发端口了。<br>telnet localhost 1234<br>你会收到远程mail服务器的"READY"消息。<br>当然，这个方法要求你手工输入所有的POP命令，这是很不方便的。可以用Fetchmail（参考how to configure Fetchmail）。Secure POP via SSH mini-HOWTO、man fetchmail和在"/usr/doc/fetchmail-[&#8230;]"目录下的Fetchmail的FAQ都提供了一些具体的例子。<br>请注意IMAP协议使用的是不同的端口：IMAP v2的端口号为143而IMAP v3的端口号为220。</p>
<p>7.3 为X加上"加密通道"<br>如果你打算在本地计算机上运行远程SSH服务器上的X程序，那么登录到远程的计算机上，创建一个名为"~/.ssh/environment"的文件并加上这一行：<br>XAUTHORITY=/home/[remote user name]/.Xauthority</p>
<p>（如果在远程主机上你的家目录下不存在".Xauthority"这个文件，那么当用SSH登录的时候就会自动创建）。<br>比如启动一个X程序（xterm）可以这个命令：<br>ssh -f -X -l [remote user name] [remote machine] xterm<br>这将在远程运行xterm这个程序。其它的X程序也是用相同的方法。</p>
<p>7.4 为linuxconf加上"加密通道"<br>Linuxconf(<a href="http://www.solucorp.qc.ca/linuxconf/">http://www.solucorp.qc.ca/linuxconf/</a>)是Linux的配置工具，它支持远程管理。Linuxconf的FAQ重说明了如何通过SSH使用linuxconf：<br>其命令为：remadmin --exec [link_command] linuxconf --guiproto<br>如果你想在两台计算机之间用加密的方式传送信息，那么最好用ssh。命令是：<br>remadmin --exec ssh -l [account] linuxconf --guiproto<br>这是非常有效的而且运行用图形界面管理计算机。<br>这种方法需要在客户端安装linuxconf。其它的方法还有直接登录到服务器上用"X11Forwarding"或字符界面运行linuxconf。</p>
<p>7.5 为Webmin加上"加密通道"<br>Webmin(<a href="http://www.webmin.com/webmin/">http://www.webmin.com/webmin/</a>)是一个新的基于浏览器的配置工具。它运行在1000端口。你可以用SSH的"端口转发"对它进行加密：<br>ssh -f -l [remote user name] [remote host] -L 1234:[remote host]:10000 tail -f /etc/motd<br>把浏览器指向<a href="http://localhost:1234/">http://localhost:1234</a> </p>
<br>
<img src ="http://www.cppblog.com/elva/aggbug/24734.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2007-05-24 01:53 <a href="http://www.cppblog.com/elva/archive/2007/05/24/24734.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>