﻿<?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++博客-ACFirst-随笔分类-Linux</title><link>http://www.cppblog.com/zzfmars/category/14650.html</link><description>明天是另一天，你能看到明天的太阳吗？</description><language>zh-cn</language><lastBuildDate>Fri, 27 May 2011 22:16:38 GMT</lastBuildDate><pubDate>Fri, 27 May 2011 22:16:38 GMT</pubDate><ttl>60</ttl><item><title>pthread_create用法 </title><link>http://www.cppblog.com/zzfmars/archive/2011/05/21/146877.html</link><dc:creator>Kevin_Zhang</dc:creator><author>Kevin_Zhang</author><pubDate>Sat, 21 May 2011 10:59:00 GMT</pubDate><guid>http://www.cppblog.com/zzfmars/archive/2011/05/21/146877.html</guid><wfw:comment>http://www.cppblog.com/zzfmars/comments/146877.html</wfw:comment><comments>http://www.cppblog.com/zzfmars/archive/2011/05/21/146877.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zzfmars/comments/commentRss/146877.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zzfmars/services/trackbacks/146877.html</trackback:ping><description><![CDATA[<div class="shareUser">转载自 <a style="color: #1463c4" href="http://hi.baidu.com/xiapingwen" target="blank">xiapingwen</a></div>
<div class="shareLastEditor">最终编辑 <a style="color: #1463c4" href="http://hi.baidu.com/xiapingwen" target="blank">xiapingwen</a></div>
<div style="margin-bottom: 5px; border-top: #bddaf2 1px solid"></div>
<div id="blog_text" class="cnt">linux下用C开发多线程程序，Linux系统下的多线程遵循POSIX线程接口，称为pthread。<br />
<p>
<table class="allBorders" border="1" rules="none" cellspacing="0" cellpadding="5">
<tbody>
<tr>
<td class="docTableCell" valign="top" align="left"><pre>#include &lt;pthread.h&gt;<br /><br />int pthread_create(pthread_t *restrict <span class="docEmphItalicAlt">tidp</span>,<br />                   const pthread_attr_t *restrict <span class="docEmphItalicAlt">attr</span>,<br />                   void *(*<span class="docEmphItalicAlt">start_rtn</span>)(void), <br />                   void *restrict <span class="docEmphItalicAlt">arg</span>);</pre></td></tr>
<tr>
<td class="docTableCell" valign="top" align="right">
<p class="docText">Returns: 0 if OK, error number on failure</p></td></tr></tbody></table></p>
<p>C99 中新增加了 restrict 修饰的指针： 由 restrict 修饰的指针是最初唯一对指针所指向的对象进行存取的方法，仅当第二个指针基于第一个时，才能对对象进行存取。对对象的存取都限定于基于由 restrict 修饰的指针表达式中。 由 restrict 修饰的指针主要用于函数形参，或指向由 malloc() 分配的内存空间。restrict 数据类型不改变程序的语义。 编译器能通过作出 restrict 修饰的指针是存取对象的唯一方法的假设，更好地优化某些类型的例程。</p>
<p>第一个参数为指向线程标识符的指针。<br />第二个参数用来设置线程属性。<br />第三个参数是线程运行函数的起始地址。<br />最后一个参数是运行函数的参数。<br /><br />下面这个程序中，我们的函数<code><span style="color: rgb(0,0,0)"><font face="NSimsun">thr_fn</font></span></code>不需要参数，所以最后一个参数设为空指针。第二个参数我们也设为空指针，这样将生成默认属性的线程。当创建线程成功时，函数返回0，若不为0则说明创建线程失败，常见的错误返回代码为EAGAIN和EINVAL。前者表示系统限制创建新的线程，例如线程数目过多了；后者表示第二个参数代表的线程属性值非法。创建线程成功后，新创建的线程则运行参数三和参数四确定的函数，原来的线程则继续运行下一行代码。 
<table style="border-collapse: collapse" border="1" cellspacing="0" bordercolor="#e99999" cellpadding="0" width="95%" bgcolor="#f1f1f1">
<tbody>
<tr>
<td>
<p style="line-height: 150%; margin: 5px"><code><span style="color: rgb(0,0,0)"><font face="NSimsun"><span style="color: rgb(0,0,204)">#</span><span style="color: rgb(255,0,0)">include</span><span style="color: rgb(0,0,204)">&lt;</span>stdio<span style="color: rgb(0,0,204)">.</span>h<span style="color: rgb(0,0,204)">&gt;</span><br /><span style="color: rgb(0,0,204)">#</span><span style="color: rgb(255,0,0)">include</span><span style="color: rgb(0,0,204)">&lt;</span>pthread<span style="color: rgb(0,0,204)">.</span>h</font><span style="color: rgb(0,0,204)"><font face="NSimsun">&gt;<br /></font></span></span></code><code><span style="color: rgb(0,0,0)"><font face="NSimsun"><span style="color: rgb(0,0,204)">#</span><span style="color: rgb(255,0,0)">include</span><span style="color: rgb(0,0,204)">&lt;</span>string<span style="color: rgb(0,0,204)">.</span>h</font><font face="NSimsun"><span style="color: rgb(0,0,204)">&gt;<br />#</span><span style="color: rgb(255,0,0)">include</span><span style="color: rgb(0,0,204)">&lt;</span>sys/types<span style="color: rgb(0,0,204)">.</span>h</font><font face="NSimsun"><span style="color: rgb(0,0,204)">&gt;<br />#</span><span style="color: rgb(255,0,0)">include</span><span style="color: rgb(0,0,204)">&lt;</span>unistd<span style="color: rgb(0,0,204)">.</span>h<span style="color: rgb(0,0,204)">&gt;</span></font></span></code><br /><code><span style="color: rgb(0,0,0)"><br /><font face="新宋体"><span style="color: rgb(255,0,0)">pthread_t</span> ntid<span style="color: rgb(0,0,204)">;</span><br /><br /><span style="color: rgb(0,0,255)">void</span> printids<span style="color: rgb(0,0,204)">(</span><span style="color: rgb(0,0,255)">const</span> <span style="color: rgb(0,0,255)">char</span> <span style="color: rgb(0,0,204)">*</span>s<span style="color: rgb(0,0,204)">)</span><span style="color: rgb(0,0,204)">{</span><br /><span style="color: rgb(255,0,0)">pid_t</span> pid<span style="color: rgb(0,0,204)">;</span><br /></font></span></code><code><span style="color: rgb(0,0,0)"><font face="新宋体"><span style="color: rgb(255,0,0)">pthread_t</span> tid<span style="color: rgb(0,0,204)">;</span><br /><br /></font></span></code><code><span style="color: rgb(0,0,0)"><font face="新宋体">pid <span style="color: rgb(0,0,204)">=</span> getpid<span style="color: rgb(0,0,204)">(</span><span style="color: rgb(0,0,204)">)</span><span style="color: rgb(0,0,204)">;</span><br /></font></span></code><code><span style="color: rgb(0,0,0)"><font face="新宋体">tid <span style="color: rgb(0,0,204)">=</span> pthread_self<span style="color: rgb(0,0,204)">(</span><span style="color: rgb(0,0,204)">)</span><span style="color: rgb(0,0,204)">;</span><br /></font></span></code><code><span style="color: rgb(0,0,0)"><font face="新宋体"><span style="color: rgb(255,0,0)">printf</span><span style="color: rgb(0,0,204)">(</span><span style="color: rgb(255,0,255)">"%s pid %u tid %u (0x%x)\n"</span><span style="color: rgb(0,0,204)">,</span>s<span style="color: rgb(0,0,204)">,</span><span style="color: rgb(0,0,204)">(</span><span style="color: rgb(0,0,255)">unsigned</span> <span style="color: rgb(0,0,255)">int</span><span style="color: rgb(0,0,204)">)</span>pid<span style="color: rgb(0,0,204)">,</span><span style="color: rgb(0,0,204)">(</span><span style="color: rgb(0,0,255)">unsigned</span> <span style="color: rgb(0,0,255)">int</span><span style="color: rgb(0,0,204)">)</span>tid<span style="color: rgb(0,0,204)">,</span><span style="color: rgb(0,0,204)">(</span><span style="color: rgb(0,0,255)">unsigned</span> </font><span style="color: rgb(0,0,255)"><br /><font face="新宋体">int</font></span><font face="新宋体"><span style="color: rgb(0,0,204)">)</span>tid<span style="color: rgb(0,0,204)">)</span><span style="color: rgb(0,0,204)">;</span><br /><span style="color: rgb(0,0,204)">}</span><br /><br /><span style="color: rgb(0,0,255)">void</span> <span style="color: rgb(0,0,204)">*</span>thr_fn<span style="color: rgb(0,0,204)">(</span><span style="color: rgb(0,0,255)">void</span> <span style="color: rgb(0,0,204)">*</span><span style="color: rgb(255,0,0)">arg</span><span style="color: rgb(0,0,204)">)</span><span style="color: rgb(0,0,204)">{</span><br /></font></span></code><code><span style="color: rgb(0,0,0)"><font face="新宋体">printids<span style="color: rgb(0,0,204)">(</span><span style="color: rgb(255,0,255)">"new thread:"</span><span style="color: rgb(0,0,204)">)</span><span style="color: rgb(0,0,204)">;</span><br /></font></span></code><code><span style="color: rgb(0,0,0)"><font face="新宋体"><span style="color: rgb(0,0,255)">return</span> <span style="color: rgb(0,0,204)">(</span><span style="color: rgb(0,0,204)">(</span><span style="color: rgb(0,0,255)">void</span> <span style="color: rgb(0,0,204)">*</span><span style="color: rgb(0,0,204)">)</span>0<span style="color: rgb(0,0,204)">)</span><span style="color: rgb(0,0,204)">;</span><br /><span style="color: rgb(0,0,204)">}</span><br /><br /><span style="color: rgb(0,0,255)">int</span> main<span style="color: rgb(0,0,204)">(</span><span style="color: rgb(0,0,204)">)</span><span style="color: rgb(0,0,204)">{</span><br /></font></span></code><code><span style="color: rgb(0,0,0)"><font face="新宋体"><span style="color: rgb(0,0,255)">int</span> err<span style="color: rgb(0,0,204)">;</span><br /><br /></font></span></code><font face="新宋体"><code><span style="color: rgb(0,0,0)">err <span style="color: rgb(0,0,204)">=</span> <span style="color: rgb(255,0,0)">pthread_create</span><span style="color: rgb(0,0,204)">(</span><span style="color: rgb(0,0,204)">&amp;</span>ntid<span style="color: rgb(0,0,204)">,</span><span style="color: rgb(255,0,0)">NULL</span><span style="color: rgb(0,0,204)">,</span>thr_fn<span style="color: rgb(0,0,204)">,</span><span style="color: rgb(255,0,0)">NULL</span><span style="color: rgb(0,0,204)">)</span><span style="color: rgb(0,0,204)">;</span><br /></span></code><code><span style="color: rgb(0,0,0)"><span style="color: rgb(0,0,255)">if</span><span style="color: rgb(0,0,204)">(</span>err <span style="color: rgb(0,0,204)">!</span><span style="color: rgb(0,0,204)">=</span> 0<span style="color: rgb(0,0,204)">)</span></span></code></font><code><span style="color: rgb(0,0,0)"><font face="新宋体"><span style="color: rgb(0,0,204)">{</span><br /></font></span></code><code><span style="color: rgb(0,0,0)"><font face="新宋体"><span style="color: rgb(255,0,0)">printf</span><span style="color: rgb(0,0,204)">(</span><span style="color: rgb(255,0,255)">"can't create thread: %s\n"</span><span style="color: rgb(0,0,204)">,</span>strerror(err<span style="color: rgb(0,0,204)">))</span><span style="color: rgb(0,0,204)">;</span><br /></font></span></code><code><span style="color: rgb(0,0,0)"><font face="新宋体"><span style="color: rgb(0,0,255)">return</span> 1<span style="color: rgb(0,0,204)">;</span><br /></font></span></code><code><span style="color: rgb(0,0,0)"><font face="新宋体"><span style="color: rgb(0,0,204)">}</span><br /><br /></font></span></code><code><span style="color: rgb(0,0,0)"><font face="新宋体">printids<span style="color: rgb(0,0,204)">(</span><span style="color: rgb(255,0,255)">"main thread:"</span><span style="color: rgb(0,0,204)">)</span><span style="color: rgb(0,0,204)">;</span><br /></font></span></code><code><span style="color: rgb(0,0,0)"><font face="新宋体"><span style="color: rgb(255,0,0)">sleep</span><span style="color: rgb(0,0,204)">(</span>1<span style="color: rgb(0,0,204)">)</span><span style="color: rgb(0,0,204)">;</span><br /></font></span></code><code><span style="color: rgb(0,0,0)"><font face="新宋体"><span style="color: rgb(0,0,255)">return</span> 0<span style="color: rgb(0,0,204)">;</span><br /><span style="color: rgb(0,0,204)">}</span><br /></font></span></code></p></td></tr></tbody></table>把APUE2上的一个程序修改一下，然后编译。<br />结果报错:<code><span style="color: rgb(0,0,0)"><br /><font face="NSimsun">pthread.c:(.text+0x85)：对&#8216;pthread_create&#8217;未定义的引用</font></span></code><br /><br />由于pthread库不是Linux系统默认的库，连接时需要使用库libpthread.a,所以在使用pthread_create创建线程时，在编译中要加-lpthread参数:<br /><code><span style="color: rgb(0,0,0)"><font face="NSimsun">gcc -o pthread -lpthread pthread.c</font></span></code></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<blockquote>这是一个关于Posix线程编程的专栏。作者在阐明概念的基础上，将向您详细讲述Posix线程库API。本文是第一篇将向您讲述线程的创建与取消。</blockquote>
<p>&nbsp;</p>
<p><a name="1"><span class="atitle2"><font color="#000000">一、线程创建</font></span></a></p>
<p>&nbsp;</p>
<p><span class="atitle3">1．1 线程与进程</span><br />相对进程而言，线程是一个更加接近于执行体的概念，它可以与同进程中的其他线程共享数据，但拥有自己的栈空间，拥有独立的执行序列。在串行程序基础上引入线程和进程是为了提高程序的并发度，从而提高程序运行效率和响应时间。</p>
<p>&nbsp;</p>
<p>线程和进程在使用上各有优缺点：线程执行开销小，但不利于资源的管理和保护；而进程正相反。同时，线程适合于在SMP机器上运行，而进程则可以跨机器迁移。</p>
<p>&nbsp;</p>
<p><span class="atitle3">1．2 创建线程</span><br />POSIX通过pthread_create()函数创建线程，API定义如下：</p>
<p><br />
<table border="1" cellspacing="0" cellpadding="5" bgcolor="#cccccc">
<tbody>
<tr>
<td><pre><code>int&nbsp;&nbsp;    pthread_create(pthread_t&nbsp;&nbsp;    *&nbsp;&nbsp;    thread, pthread_attr_t * attr, 
<br />void * (*start_routine)(void *), void * arg)
<br /></code></pre></td></tr></tbody></table>与fork()调用创建一个进程的方法不同，pthread_create()创建的线程并不具备与主线程（即调用pthread_create()的线程）同样的执行序列，而是使其运行start_routine(arg)函数。thread返回创建的线程ID，而attr是创建线程时设置的线程属性（见下）。pthread_create()的返回值表示线程创建是否成功。尽管arg是void *类型的变量，但它同样可以作为任意类型的参数传给start_routine()函数；同时，start_routine()可以返回一个void *类型的返回值，而这个返回值也可以是其他类型，并由pthread_join()获取。</p>
<p><span class="atitle3">1．3 线程创建属性</span><br />pthread_create()中的attr参数是一个结构指针，结构中的元素分别对应着新线程的运行属性，主要包括以下几项：</p>
<p>&nbsp;</p>
<p>__detachstate，表示新线程是否与进程中其他线程脱离同步，如果置位则新线程不能用pthread_join()来同步，且在退出时自行释放所占用的资源。缺省为PTHREAD_CREATE_JOINABLE状态。这个属性也可以在线程创建并运行以后用pthread_detach()来设置，而一旦设置为PTHREAD_CREATE_DETACH状态（不论是创建时设置还是运行时设置）则不能再恢复到 PTHREAD_CREATE_JOINABLE状态。</p>
<p>&nbsp;</p>
<p>__schedpolicy，表示新线程的调度策略，主要包括SCHED_OTHER（正常、非实时）、SCHED_RR（实时、轮转法）和 SCHED_FIFO（实时、先入先出）三种，缺省为SCHED_OTHER，后两种调度策略仅对超级用户有效。运行时可以用过 pthread_setschedparam()来改变。</p>
<p>&nbsp;</p>
<p>__schedparam，一个struct sched_param结构，目前仅有一个sched_priority整型变量表示线程的运行优先级。这个参数仅当调度策略为实时（即SCHED_RR 或SCHED_FIFO）时才有效，并可以在运行时通过pthread_setschedparam()函数来改变，缺省为0。</p>
<p>&nbsp;</p>
<p>__inheritsched，有两种值可供选择：PTHREAD_EXPLICIT_SCHED和PTHREAD_INHERIT_SCHED，前者表示新线程使用显式指定调度策略和调度参数（即attr中的值），而后者表示继承调用者线程的值。缺省为PTHREAD_EXPLICIT_SCHED。</p>
<p>&nbsp;</p>
<p>__scope，表示线程间竞争CPU的范围，也就是说线程优先级的有效范围。POSIX的标准中定义了两个值： PTHREAD_SCOPE_SYSTEM和PTHREAD_SCOPE_PROCESS，前者表示与系统中所有线程一起竞争CPU时间，后者表示仅与同进程中的线程竞争CPU。目前LinuxThreads仅实现了PTHREAD_SCOPE_SYSTEM一值。</p>
<p>&nbsp;</p>
<p>pthread_attr_t结构中还有一些值，但不使用pthread_create()来设置。</p>
<p>&nbsp;</p>
<p>为了设置这些属性，POSIX定义了一系列属性设置函数，包括pthread_attr_init()、pthread_attr_destroy()和与各个属性相关的pthread_attr_get---/pthread_attr_set---函数。</p>
<p>&nbsp;</p>
<p><span class="atitle3">1．4 线程创建的Linux实现</span><br />我们知道，Linux的线程实现是在核外进行的，核内提供的是创建进程的接口do_fork()。内核提供了两个系统调用__clone()和fork ()，最终都用不同的参数调用do_fork()核内API。当然，要想实现线程，没有核心对多进程（其实是轻量级进程）共享数据段的支持是不行的，因此，do_fork()提供了很多参数，包括CLONE_VM（共享内存空间）、CLONE_FS（共享文件系统信息）、CLONE_FILES（共享文件描述符表）、CLONE_SIGHAND（共享信号句柄表）和CLONE_PID（共享进程ID，仅对核内进程，即0号进程有效）。当使用fork系统调用时，内核调用do_fork()不使用任何共享属性，进程拥有独立的运行环境，而使用pthread_create()来创建线程时,则最终设置了所有这些属性来调用__clone()，而这些参数又全部传给核内的do_fork()，从而创建的"进程"拥有共享的运行环境，只有栈是独立的，由 __clone()传入。</p>
<p>&nbsp;</p>
<p>Linux线程在核内是以轻量级进程的形式存在的，拥有独立的进程表项，而所有的创建、同步、删除等操作都在核外pthread库中进行。pthread 库使用一个管理线程（__pthread_manager()，每个进程独立且唯一）来管理线程的创建和终止，为线程分配线程ID，发送线程相关的信号（比如Cancel），而主线程（pthread_create()）的调用者则通过管道将请求信息传给管理线程。</p>
<p>&nbsp;</p>
<p><a name="2"><span class="atitle2"><font color="#000000">二、线程取消</font></span></a></p>
<p>&nbsp;</p>
<p><span class="atitle3">2．1 线程取消的定义</span><br />一般情况下，线程在其主体函数退出的时候会自动终止，但同时也可以因为接收到另一个线程发来的终止（取消）请求而强制终止。</p>
<p>&nbsp;</p>
<p><span class="atitle3">2．2 线程取消的语义</span><br />线程取消的方法是向目标线程发Cancel信号，但如何处理Cancel信号则由目标线程自己决定，或者忽略、或者立即终止、或者继续运行至Cancelation-point（取消点），由不同的Cancelation状态决定。</p>
<p>&nbsp;</p>
<p>线程接收到CANCEL信号的缺省处理（即pthread_create()创建线程的缺省状态）是继续运行至取消点，也就是说设置一个CANCELED状态，线程继续运行，只有运行至Cancelation-point的时候才会退出。</p>
<p>&nbsp;</p>
<p><span class="atitle3">2．3 取消点</span><br />根据POSIX标准，pthread_join()、pthread_testcancel()、pthread_cond_wait()、 pthread_cond_timedwait()、sem_wait()、sigwait()等函数以及read()、write()等会引起阻塞的系统调用都是Cancelation-point，而其他pthread函数都不会引起Cancelation动作。但是pthread_cancel的手册页声称，由于LinuxThread库与C库结合得不好，因而目前C库函数都不是Cancelation-point；但CANCEL信号会使线程从阻塞的系统调用中退出，并置EINTR错误码，因此可以在需要作为Cancelation-point的系统调用前后调用 pthread_testcancel()，从而达到POSIX标准所要求的目标，即如下代码段：</p>
<p><br />
<table border="1" cellspacing="0" cellpadding="5" width="100%" bgcolor="#cccccc">
<tbody>
<tr>
<td><pre><code>pthread_testcancel();
<br />&nbsp;&nbsp;&nbsp;&nbsp;    retcode = read(fd, buffer, length);
<br />&nbsp;&nbsp;&nbsp;&nbsp;    pthread_testcancel();</code></pre></td></tr></tbody></table></p>
<p><span class="atitle3">2．4 程序设计方面的考虑</span><br />如果线程处于无限循环中，且循环体内没有执行至取消点的必然路径，则线程无法由外部其他线程的取消请求而终止。因此在这样的循环体的必经路径上应该加入pthread_testcancel()调用。</p>
<p>&nbsp;</p>
<p><span class="atitle3">2．5 与线程取消相关的pthread函数</span><br />int pthread_cancel(pthread_t thread)<br />发送终止信号给thread线程，如果成功则返回0，否则为非0值。发送成功并不意味着thread会终止。</p>
<p>&nbsp;</p>
<p>int pthread_setcancelstate(int state, int *oldstate)<br />设置本线程对Cancel信号的反应，state有两种值：PTHREAD_CANCEL_ENABLE（缺省）和 PTHREAD_CANCEL_DISABLE，分别表示收到信号后设为CANCLED状态和忽略CANCEL信号继续运行；old_state如果不为 NULL则存入原来的Cancel状态以便恢复。</p>
<p>&nbsp;</p>
<p>int pthread_setcanceltype(int type, int *oldtype)<br />设置本线程取消动作的执行时机，type由两种取值：PTHREAD_CANCEL_DEFFERED和 PTHREAD_CANCEL_ASYCHRONOUS，仅当Cancel状态为Enable时有效，分别表示收到信号后继续运行至下一个取消点再退出和立即执行取消动作（退出）；oldtype如果不为NULL则存入运来的取消动作类型值。</p>
<p>&nbsp;</p>
<p>void pthread_testcancel(void)<br />检查本线程是否处于Canceld状态，如果是，则进行取消动作，否则直接返回。</p></div> <img src ="http://www.cppblog.com/zzfmars/aggbug/146877.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zzfmars/" target="_blank">Kevin_Zhang</a> 2011-05-21 18:59 <a href="http://www.cppblog.com/zzfmars/archive/2011/05/21/146877.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux的系统信号（signal）类型与机制 </title><link>http://www.cppblog.com/zzfmars/archive/2010/11/25/134663.html</link><dc:creator>Kevin_Zhang</dc:creator><author>Kevin_Zhang</author><pubDate>Thu, 25 Nov 2010 11:23:00 GMT</pubDate><guid>http://www.cppblog.com/zzfmars/archive/2010/11/25/134663.html</guid><wfw:comment>http://www.cppblog.com/zzfmars/comments/134663.html</wfw:comment><comments>http://www.cppblog.com/zzfmars/archive/2010/11/25/134663.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zzfmars/comments/commentRss/134663.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zzfmars/services/trackbacks/134663.html</trackback:ping><description><![CDATA[<div id=app-share-content>
<div class=intro>信号是Linux编程中非常重要的部分，本文将详细介绍信号机制的基本概念、Linux对信号机制的大致实现方 法、如何使用信号，以及有关信号的几个系统调用。</div>
信号是Linux编程中非常重要的部分，本文将详细介绍信号机制的基本概念、Linux对信号机制的大致实现方法、如何使用信号，以及有关信号的几个系统 调用。<br>信号机制是进程之间相互传递消息的一种方法，信号全称为软中断信号，也有人称作软中断。从它的命名可以看出，它的实质和使用很象中断。所以，信号可以 说是进程控制的一部分。<br>1.信号的基本概念<br>本节先介绍信号的一些基本概念，然后给出一些基本的信号类型和信号对应的事件。基本概念对于理解和使用信号，对于理解信号机制都特别重要。下面就来看 看什么是信号。<br>1.1 基本概念<br>软中断信号（signal，又简称为信号）用来通知进程发生了异步事件。进程之间可以互相通过系统调用kill发送软中断信号。内核也可以因为 内部事件而给进程发送信号，通知进程发生了某个事件。注意，信号只是用来通知某进程发生了什么事件，并不给该进程传递任何数据。<br>收到信号的进程对各种信号有不同的处理方法。处理方法可以分为三类：第一种是类似中断的处理程序，对于需要处理的信号，进程可以指定处理函数， 由该函数来处理。第二种方法是，忽略某个信号，对该信号不做任何处理，就象未发生过一样。第三种方法是，对该信号的处理保留系统的默认值，这种缺省操作， 对大部分的信号的缺省操作是使得进程终止。进程通过系统调用signal来指定进程对某个信号的处理行为。<br>在进程表的表项中有一个软中断信号域，该域中每一位对应一个信号，当有信号发送给进程时，对应位置位。由此可以看出，进程对不同的信号可以同时保留， 但对于同一个信号，进程并不知道在处理之前来过多少个。<br>1.2 信号的类型<br>发出信号的原因很多，这里按发出信号的原因简单分类，以了解各种信号：<br>与进程终止相关的信号。当进程退出，或者子进程终止时，发出这类信号。<br>与进程例外事件相关的信号。如进程越界，或企图写一个只读的内存区域（如程序正文区），或执行一个特权指令及其他各种硬件错误。<br>与在系统调用期间遇到不可恢复条件相关的信号。如执行系统调用exec时，原有资源已经释放，而目前系统资源又已经耗尽。<br>与执行系统调用时遇到非预测错误条件相关的信号。如执行一个并不存在的系统调用。<br>在用户态下的进程发出的信号。如进程调用系统调用kill向其他进程发送信号。<br>与终端交互相关的信号。如用户关闭一个终端，或按下break键等情况。<br>跟踪进程执行的信号。<br>Linux支持的信号列表如下。很多信号是与机器的体系结构相关的。<br>首先列出的是POSIX.1中列出的信号：<br>信号　　　值　　处理动作　发出信号的原因<br>----------------------------------------------------------------------<br>SIGHUP 1　　　 　A　　终端挂起或者控制进程终止<br>SIGINT 2　　　 　A　　键盘中断（如break键被按下）<br>SIGQUIT 3　　 　 C　　键盘的退出键被按下<br>SIGILL 4　　 　　C　　非法指令<br>SIGABRT 6　　　　 C　　由abort(3)发出的退出指令<br>SIGFPE 8　　　　 C　　浮点异常<br>SIGKILL 9　　 　 AEF　 Kill信号<br>SIGSEGV 11　　 　 C　　无效的内存引用<br>SIGPIPE 13　　 　 A　　管道破裂: 写一个没有读端口的管道<br>SIGALRM 14　　　 A　　由alarm(2)发出的信号<br>SIGTERM 15　　　 A　　终止信号<br>SIGUSR1 30,10,16 A　　用户自定义信号1<br>SIGUSR2 31,12,17 A　　用户自定义信号2<br>SIGCHLD 20,17,18 B　　子进程结束信号<br>SIGCONT 19,18,25 　　　进程继续（曾被停止的进程）<br>SIGSTOP 17,19,23 DEF　终止进程<br>SIGTSTP 18,20,24 D　　控制终端（tty）上按下停止键<br>SIGTTIN 21,21,26 D　　后台进程企图从控制终端读<br>SIGTTOU 22,22,27 D　　后台进程企图从控制终端写<br>下面的信号没在POSIX.1中列出，而在SUSv2列出<br>信号　　　 值　 　处理动作　发出信号的原因<br>--------------------------------------------------------------------<br>SIGBUS 10,7,10 C 总线错误(错误的内存访问)<br>SIGPOLL A Sys V定义的Pollable事件，与SIGIO同义<br>SIGPROF 27,27,29 A Profiling定时器到<br>SIGSYS 12,-,12 C 无效的系统调用 (SVID)<br>SIGTRAP 5 C 跟踪/断点捕获<br>SIGURG 16,23,21 B Socket出现紧急条件(4.2 BSD)<br>SIGVTALRM 26,26,28 A 实际时间报警时钟信号(4.2 BSD)<br>SIGXCPU 24,24,30 C 超出设定的CPU时间限制(4.2 BSD)<br>SIGXFSZ 25,25,31 C 超出设定的文件大小限制(4.2 BSD)<br>（对于SIGSYS，SIGXCPU，SIGXFSZ，以及某些机器体系结构下的SIGBUS，Linux缺省的动作是A (terminate)，SUSv2 是C (terminate and dump core)）。<br><br>下面是其它的一些信号:<br>信号　　　 值　 　处理动作　发出信号的原因<br>----------------------------------------------------------------------<br>SIGIOT 6 C IO捕获指令，与SIGABRT同义<br>SIGEMT 7,-,7<br>SIGSTKFLT -,16,- A 协处理器堆栈错误<br>SIGIO 23,29,22 A 某I/O操作现在可以进行了(4.2 BSD)<br>SIGCLD -,-,18 A 与SIGCHLD同义<br>SIGPWR 29,30,19 A 电源故障(System V)<br>SIGINFO 29,-,- A 与SIGPWR同义<br>SIGLOST -,-,- A 文件锁丢失<br>SIGWINCH 28,28,20 B 窗口大小改变(4.3 BSD, Sun)<br>SIGUNUSED -,31,- A 未使用的信号(will be SIGSYS)<br>（在这里，- 表示信号没有实现；有三个值给出的含义为，第一个值通常在Alpha和Sparc上有效，中间的值对应i386和ppc以及sh，最后一个值对应 mips。信号29在Alpha上为SIGINFO / SIGPWR ，在Sparc上为SIGLOST。）<br>处理动作一项中的字母含义如下:<br>A 缺省的动作是终止进程<br>B 缺省的动作是忽略此信号<br>C 缺省的动作是终止进程并进行内核映像转储（dump core）<br>D 缺省的动作是停止进程<br>E 信号不能被捕获<br>F 信号不能被忽略<br>上面介绍的信号是常见系统所支持的。以表格的形式介绍了各种信号的名称、作用及其在默认情况下的处理动作。各种默认处理动作的含义是：终止程序 是指进程退出；忽略该信号是将该信号丢弃，不做处理；停止程序是指程序挂起，进入停止状况以后还能重新进行下去，一般是在调试的过程中（例如ptrace 系统调用）；内核映像转储是指将进程数据在内存的映像和进程在内核结构中存储的部分内容以一定格式转储到文件系统，并且进程退出执行，这样做的好处是为程 序员提供了方便，使得他们可以得到进程当时执行时的数据值，允许他们确定转储的原因，并且可以调试他们的程序。<br>注意: 信号SIGKILL和SIGSTOP既不能被捕捉，也不能被忽略。信号SIGIOT与SIGABRT是一个信号。可以看出，同一个信号在不同的系统中值可 能不一样，所以建议最好使用为信号定义的名字，而不要直接使用信号的值。<br>2.信 号 机 制<br>上一节中介绍了信号的基本概念，在这一节中，我们将介绍内核如何实现信号机制。即内核如何向一个进程发送信号、进程如何接收一个信号、进程怎样 控制自己对信号的反应、内核在什么时机处理和怎样处理进程收到的信号。还要介绍一下setjmp和longjmp在信号中起到的作用。<br>2.1 内核对信号的基本处理方法<br>内核给一个进程发送软中断信号的方法，是在进程所在的进程表项的信号域设置对应于该信号的位。这里要补充的是，如果信号发送给一个正在睡眠的进 程，那么要看该进程进入睡眠的优先级，如果进程睡眠在可被中断的优先级上，则唤醒进程；否则仅设置进程表中信号域相应的位，而不唤醒进程。这一点比较重 要，因为进程检查是否收到信号的时机是：一个进程在即将从内核态返回到用户态时；或者，在一个进程要进入或离开一个适当的低调度优先级睡眠状态时。<br>内核处理一个进程收到的信号的时机是在一个进程从内核态返回用户态时。所以，当一个进程在内核态下运行时，软中断信号并不立即起作用，要等到将返回用 户态时才处理。进程只有处理完信号才会返回用户态，进程在用户态下不会有未处理完的信号。<br>内核处理一个进程收到的软中断信号是在该进程的上下文中，因此，进程必须处于运行状态。前面介绍概念的时候讲过，处理信号有三种类型：进程接收 到信号后退出；进程忽略该信号；进程收到信号后执行用户设定用系统调用signal的函数。当进程接收到一个它忽略的信号时，进程丢弃该信号，就象没有收 到该信号似的继续运行。如果进程收到一个要捕捉的信号，那么进程从内核态返回用户态时执行用户定义的函数。而且执行用户定义的函数的方法很巧妙，内核是在 用户栈上创建一个新的层，该层中将返回地址的值设置成用户定义的处理函数的地址，这样进程从内核返回弹出栈顶时就返回到用户定义的函数处，从函数返回再弹 出栈顶时，才返回原先进入内核的地方。这样做的原因是用户定义的处理函数不能且不允许在内核态下执行（如果用户定义的函数在内核态下运行的话，用户就可以 获得任何权限）。<br>在信号的处理方法中有几点特别要引起注意。<br>在一些系统中，当一个进程处理完中断信号返回用户态之前，内核清除用户区中设定的对该信号的处理例程的地址，即下一次进程对该信号的处理方法又改 为默认值，除非在下一次信号到来之前再次使用signal系统调用。这可能会使得进程在调用signal之前又得到该信号而导致退出。在BSD中，内核不 再清除该地址。但不清除该地址可能使得进程因为过多过快的得到某个信号而导致堆栈溢出。为了避免出现上述情况。在BSD系统中，内核模拟了对硬件中断的处 理方法，即在处理某个中断时，阻止接收新的该类中断。<br><br>如果要捕捉的信号发生于进程正在一个系统调用中时，并且该进程睡眠在可中断的优先级上，这时该信号引起进程作一次longjmp， 跳出睡眠状态，返回用户态并执行信号处理例程。当从信号处理例程返回时，进程就象从系统调用返回一样，但返回了一个错误代码，指出该次系统调用曾经被中 断。这要注意的是，BSD系统中内核可以自动地重新开始系统调用。<br>若进程睡眠在可中断的优先级上，则当它收到一个要忽略的信号时，该进程被唤醒，但不做longjmp，一般是继续睡眠。但用户感觉不到进程曾经被唤醒，而 是象没有发生过该信号一样。<br>内核对子进程终止（SIGCLD）信号的处理方法与其他信号有所区别。当进程检查出收到了一个子进程终止的信号时，缺省情况下，该进程 就象没有收到该信号似的，如果父进程执行了系统调用wait，进程将从系统调用wait中醒来并返回wait调用，执行一系列wait调用的后续操作（找 出僵死的子进程，释放子进程的进程表项），然后从wait中返回。SIGCLD信号的作用是唤醒一个睡眠在可被中断优先级上的进程。如果该进程捕捉了这个 信号，就象普通信号处理一样转到处理例程。如果进程忽略该信号，那么系统调用wait的动作就有所不同，因为SIGCLD的作用仅仅是唤醒一个睡眠在可被 中断优先级上的进程，那么执行wait调用的父进程被唤醒继续执行wait调用的后续操作，然后等待其他的子进程。<br>如果一个进程调用signal系统调用，并设置了SIGCLD的处理方法，并且该进程有子进程处于僵死状态，则内核将向该进程发一个SIGCLD信 号。<br>2.2 setjmp和longjmp的作用<br>前面在介绍信号处理机制时，多次提到了setjmp和longjmp，但没有仔细说明它们的作用和实现方法。这里就此作一个简单的介绍。<br>在介绍信号的时候，我们看到多个地方要求进程在检查收到信号后，从原来的系统调用中直接返回，而不是等到该调用完成。这种进程突然改变其上下文 的情况，就是使用setjmp和longjmp的结果。setjmp将保存的上下文存入用户区，并继续在旧的上下文中执行。这就是说，进程执行一个系统调 用，当因为资源或其他原因要去睡眠时，内核为进程作了一次setjmp，如果在睡眠中被信号唤醒，进程不能再进入睡眠时，内核为进程调用longjmp， 该操作是内核为进程将原先setjmp调用保存在进程用户区的上下文恢复成现在的上下文，这样就使得进程可以恢复等待资源前的状态，而且内核为 setjmp返回1，使得进程知道该次系统调用失败。这就是它们的作用。<br>3.有关信号的系统调用<br>前面两节已经介绍了有关信号的大部分知识。这一节我们来了解一下这些系统调用。其中，系统调用signal是进程用来设定某个信号的处理方法， 系统调用kill是用来发送信号给指定进程的。这两个调用可以形成信号的基本操作。后两个调用pause和alarm是通过信号实现的进程暂停和定时器， 调用alarm是通过信号通知进程定时器到时。所以在这里，我们还要介绍这两个调用。<br>3.1 signal 系统调用<br>系统调用signal用来设定某个信号的处理方法。该调用声明的格式如下：<br>void (*signal(int signum, void (*handler)(int)))(int);<br>在使用该调用的进程中加入以下头文件：<br>#include&nbsp;<br>上述声明格式比较复杂，如果不清楚如何使用，也可以通过下面这种类型定义的格式来使用（POSIX的定义）：<br>typedef void (*sighandler_t)(int);<br>sighandler_t signal(int signum, sighandler_t handler);<br>但这种格式在不同的系统中有不同的类型定义，所以要使用这种格式，最好还是参考一下联机手册。<br>在调用中，参数signum指出要设置处理方法的信号。第二个参数handler是一个处理函数，或者是<br>SIG_IGN：忽略参数signum所指的信号。<br>SIG_DFL：恢复参数signum所指信号的处理方法为默认值。<br>传递给信号处理例程的整数参数是信号值，这样可以使得一个信号处理例程处理多个信号。系统调用signal返回值是指定信号signum前一次的处理 例程或者错误时返回错误代码SIG_ERR。下面来看一个简单的例子：<br>#include&nbsp;<br>#include&nbsp;<br>#include&nbsp;<br>void sigroutine(int dunno)<br>{ /* 信号处理例程，其中dunno将会得到信号的值 */<br>switch (dunno) {<br>case 1:<br>printf("Get a signal -- SIGHUP ");<br>break;<br>case 2:<br>printf("Get a signal -- SIGINT ");<br>break;<br>case 3:<br>printf("Get a signal -- SIGQUIT ");<br>break;<br>}<br>return;<br>}<br>int main() {<br>printf("process id is %d ",getpid());<br>signal(SIGHUP, sigroutine); //* 下面设置三个信号的处理方法<br>signal(SIGINT, sigroutine);<br>signal(SIGQUIT, sigroutine);<br>for (;;) ;<br>}<br>其中信号SIGINT由按下Ctrl-C发出，信号SIGQUIT由按下Ctrl-(back slash)发出。该程序执行的结果如下：<br>localhost:~$ ./sig_test<br>process id is 463<br>Get a signal -SIGINT //按下Ctrl-C得到的结果<br>Get a signal -SIGQUIT //按下Ctrl-得到的结果<br>//按下Ctrl-z将进程置于后台<br>[1]+ Stopped ./sig_test<br>localhost:~$ bg<br>[1]+ ./sig_test &amp;<br>localhost:~$ kill -HUP 463 //向进程发送SIGHUP信号<br>localhost:~$ Get a signal &#8211; SIGHUP<br>kill -9 463 //向进程发送SIGKILL信号，终止进程<br>localhost:~$<br>3.2 kill 系统调用<br>系统调用kill用来向进程发送一个信号。该调用声明的格式如下：<br>int kill(pid_t pid, int sig);<br>在使用该调用的进程中加入以下头文件：<br>#include&nbsp;<br>#include&nbsp;<br>该系统调用可以用来向任何进程或进程组发送任何信号。如果参数pid是正数，那么该调用将信号sig发送到进程号为pid的进程。如果pid等 于0，那么信号sig将发送给当前进程所属进程组里的所有进程。如果参数pid等于-1，信号sig将发送给除了进程1和自身以外的所有进程。如果参数 pid小于-1，信号sig将发送给属于进程组-pid的所有进程。如果参数sig为0，将不发送信号。该调用执行成功时，返回值为0；错误时，返回 -1，并设置相应的错误代码errno。下面是一些可能返回的错误代码：<br>EINVAL：指定的信号sig无效。<br>ESRCH：参数pid指定的进程或进程组不存在。注意，在进程表项中存在的进程，可能是一个还没有被wait收回，但已经终止执行的僵死进程。<br>EPERM：进程没有权力将这个信号发送到指定接收信号的进程。因为，一个进程被允许将信号发送到进程pid时，必须拥有root权 力，或者是发出调用的进程的UID或EUID与指定接收的进程的UID或保存用户ID（savedset-user-ID）相同。如果参数pid小于 -1，即该信号发送给一个组，则该错误表示组中有成员进程不能接收该信号。<br>3.3 pause系统调用<br>系统调用pause的作用是等待一个信号。该调用的声明格式如下：<br>int pause(void);<br>在使用该调用的进程中加入以下头文件：<br>#include&nbsp;<br>该调用使得发出调用的进程进入睡眠，直到接收到一个信号为止。该调用总是返回-1，并设置错误代码为EINTR（接收到一个信号）。下面是一个简单的 范例：<br>#include&nbsp;<br>#include&nbsp;<br>#include&nbsp;<br>void sigroutine(int unused)<br>{<br>printf("Catch a signal SIGINT ");<br>}<br>int main() {<br>signal(SIGINT, sigroutine);<br>pause();<br>printf("receive a signal ");<br>}<br>在这个例子中，程序开始执行，就象进入了死循环一样，这是因为进程正在等待信号，当我们按下Ctrl-C时，信号被捕捉，并且使得pause退出等待 状态。<br>3.4 alarm和 setitimer系统调用<br>系统调用alarm的功能是设置一个定时器，当定时器计时到达时，将发出一个信号给进程。该调用的声明格式如下：<br>unsigned int alarm(unsigned int seconds);<br>在使用该调用的进程中加入以下头文件：<br>#include&nbsp;<br>系统调用alarm安排内核为调用进程在指定的 seconds秒后发出一个SIGALRM的信号。如果指定的参数seconds为0，则不再发送SIGALRM信号。后一次设定将取消前一次的设定。该 调用返回值为上次定时调用到发送之间剩余的时间，或者因为没有前一次定时调用而返回0。注意，在使用时，alarm只设定为发送一次信号，如果要多次发 送，就要多次使用alarm调用。<br>对于alarm，这里不再举例。现在的系统中很多程序不再使用alarm调用，而是使用setitimer调用来设置定时器，用getitimer来 得到定时器的状态，这两个调用的声明格式如下：<br>int getitimer(int which, struct itimerval *value);<br>int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue);<br>在使用这两个调用的进程中加入以下头文件：<br>#include&nbsp;<br>该系统调用给进程提供了三个定时器，它们各自有其独有的计时域，当其中任何一个到达，就发送一个相应的信号给进程，并使得计时器重新开始。三个计时器 由参数which指定，如下所示：<br>TIMER_REAL：按实际时间计时，计时到达将给进程发送SIGALRM信号。<br><br>ITIMER_VIRTUAL：仅当进程执行时才进行计时。计时到达将发送SIGVTALRM信号给进程。<br>ITIMER_PROF：当进程执行时和系统为该进程执行动作时都计时。与ITIMER_VIR-TUAL是一对，该定时器经常用来统计进程在用户态和内 核态花费的时间。计时到达将发送SIGPROF信号给进程。<br>定时器中的参数value用来指明定时器的时间，其结构如下：<br>struct itimerval {<br>struct timeval it_interval; /* 下一次的取值 */<br>struct timeval it_value; /* 本次的设定值 */<br>};<br>该结构中timeval结构定义如下：<br>struct timeval {<br>long tv_sec; /* 秒 */<br>long tv_usec; /* 微秒，1秒 = 1000000 微秒*/<br>};<br>在setitimer调用中，参数ovalue如果不为空，则其中保留的是上次调用设定的值。定时器将it_value递减到0时，产生一个信 号，并将it_value的值设定为it_interval的值，然后重新开始计时，如此往复。当it_value设定为0时，计时器停止，或者当它计时 到期，而it_interval为0时停止。调用成功时，返回0；错误时，返回-1，并设置相应的错误代码errno：<br>EFAULT：参数value或ovalue是无效的指针。<br>EINVAL：参数which不是ITIMER_REAL、ITIMER_VIRT或ITIMER_PROF中的一个。<br>下面是关于setitimer调用的一个简单示范，在该例子中，每隔一秒发出一个SIGALRM，每隔0.5秒发出一个SIGVTALRM信号：<br>#include&nbsp;<br>#include&nbsp;<br>#include&nbsp;<br>#include&nbsp;<br><br>int sec;<br>void sigroutine(int signo) {<br>switch (signo) {<br>case SIGALRM:<br>printf("Catch a signal -- SIGALRM ");<br>break;<br>case SIGVTALRM:<br>printf("Catch a signal -- SIGVTALRM ");<br>break;<br>}<br>return;<br>}<br>int main() {<br>struct itimerval value,ovalue,value2;<br>sec = 5;<br>printf("process id is %d ",getpid());<br>signal(SIGALRM, sigroutine);<br>signal(SIGVTALRM, sigroutine);<br>value.it_value.tv_sec = 1;<br>value.it_value.tv_usec = 0;<br>value.it_interval.tv_sec = 1;<br>value.it_interval.tv_usec = 0;<br>setitimer(ITIMER_REAL, &amp;value, &amp;ovalue);<br>value2.it_value.tv_sec = 0;<br>value2.it_value.tv_usec = 500000;<br>value2.it_interval.tv_sec = 0;<br>value2.it_interval.tv_usec = 500000;<br>setitimer(ITIMER_VIRTUAL, &amp;value2, &amp;ovalue);<br>for (;;) ;<br>}<br>该例子的屏幕拷贝如下：<br>localhost:~$ ./timer_test<br>process id is 579<br>Catch a signal &#8211; SIGVTALRM<br>Catch a signal &#8211; SIGALRM<br>Catch a signal &#8211; SIGVTALRM<br>Catch a signal &#8211; SIGVTALRM<br>Catch a signal &#8211; SIGALRM<br>Catch a signal &#8211;GVTALRM </div>
<img src ="http://www.cppblog.com/zzfmars/aggbug/134663.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zzfmars/" target="_blank">Kevin_Zhang</a> 2010-11-25 19:23 <a href="http://www.cppblog.com/zzfmars/archive/2010/11/25/134663.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用/proc/stat计算cpu的占用率</title><link>http://www.cppblog.com/zzfmars/archive/2010/11/10/133175.html</link><dc:creator>Kevin_Zhang</dc:creator><author>Kevin_Zhang</author><pubDate>Wed, 10 Nov 2010 01:31:00 GMT</pubDate><guid>http://www.cppblog.com/zzfmars/archive/2010/11/10/133175.html</guid><wfw:comment>http://www.cppblog.com/zzfmars/comments/133175.html</wfw:comment><comments>http://www.cppblog.com/zzfmars/archive/2010/11/10/133175.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zzfmars/comments/commentRss/133175.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zzfmars/services/trackbacks/133175.html</trackback:ping><description><![CDATA[<p class="MsoNormal" style="text-align: left; text-indent: 21pt;" align="left"><span style="font-size: 12pt; font-family: 宋体;">在<span lang="EN-US">Linux</span>下，<span lang="EN-US">CPU</span>利用率分为用户态，系统态和空闲态，分别表示<span lang="EN-US">CPU</span>处于用户态执行的时间，系统内核执行的时间，和空闲系统进程执行的时间，三者之和就是<span lang="EN-US">CPU</span>的总时间，当没有用户进程、系统进程等需要执行的时候，<span lang="EN-US">CPU</span>就执行系统缺省的空闲进程。从平常的思维方式理解的话，<span lang="EN-US">CPU</span>的利用率就是非空闲进程占用时间的比例，即<span lang="EN-US">CPU</span>执行非空闲进程的时间 <strong><span lang="EN-US">/ </span></strong><span lang="EN-US">CPU</span>总的执行时间。<span lang="EN-US"></span></span></p>
<p class="MsoNormal" style="text-align: left; text-indent: 21pt;" align="left"><span style="font-size: 12pt; font-family: 宋体;">在<span lang="EN-US">Linux</span>系统中，<span lang="EN-US">CPU</span>时间的分配信息保存在<span lang="EN-US">/proc/stat</span>文件中，利用率的计算应该从这个文件中获取数据。文件的头几行记录了每个<span lang="EN-US">CPU</span>的用户态，系统态，空闲态等状态下分配的时间片（单位是<span lang="EN-US">Jiffies</span>），这些数据是从<span lang="EN-US">CPU</span>加电到当前的累计值。常用的监控软件就是利用<span lang="EN-US">/proc/stat</span>里面的这些数据来计算<span lang="EN-US">CPU</span>的利用率的。<span lang="EN-US"></span></span></p>
<p class="MsoNormal" style="text-align: left; text-indent: 21pt;" align="left"><span style="font-size: 12pt; font-family: 宋体;">不同版本的<span lang="EN-US">linux
/proc/stat</span>文件内容不一样，以<span lang="EN-US">Linux 2.6</span>来说，<span lang="EN-US">/proc/stat</span>文件的内容如下：<span lang="EN-US"></span></span></p>
<p class="MsoNormal" style="text-align: left; text-indent: 21pt;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">&nbsp;</span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">cpu&nbsp;2032004 102648 238344 167130733 758440 15159
17878 0</span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">cpu0 1022597 63462 141826 83528451 366530 9362 15386 0</span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">cpu1 1009407 39185 96518 83602282 391909 5796 2492 0</span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">intr 303194010 212852371 3 0 0 11 0 0 2 1 1 0 0 3 0
11097365 0 72615114 6628960 0 179 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">ctxt 236095529</span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">btime 1195210746</span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">processes 401389</span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">procs_running 1</span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">procs_blocked 0</span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">&nbsp;</span></p>
<p class="MsoNormal" style="text-align: left; text-indent: 21pt;" align="left"><span style="font-size: 12pt; font-family: 宋体;">第一行的数值表示的是<span lang="EN-US">CPU</span>总的使用情况，所以我们只要用第一行的数字计算就可以了。下表解析第一行各数值的含义：<span lang="EN-US"></span></span></p>
<table class="MsoNormalTable" style="border-collapse: collapse;" border="0" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td style="border: 1pt solid windowtext; padding: 0cm 5.4pt; background: none repeat scroll 0% 0% gray; width: 86.4pt;" valign="top" width="115">
            <p class="MsoNormal" style="text-align: left;" align="left"><strong><span style="font-size: 12pt; font-family: 宋体;">参数</span></strong><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"></span></p>
            </td>
            <td style="padding: 0cm 5.4pt; background: none repeat scroll 0% 0% gray; width: 339.7pt;" valign="top" width="453">
            <p class="MsoNormal" style="text-align: left;" align="left"><strong><span style="font-size: 12pt; font-family: 宋体;">解析（单位：<span lang="EN-US">jiffies</span>）</span></strong><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"></span></p>
            </td>
        </tr>
        <tr>
            <td style="padding: 0cm 5.4pt; width: 86.4pt;" valign="top" width="115">
            <p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">user (2032004)</span></p>
            </td>
            <td style="padding: 0cm 5.4pt; width: 339.7pt;" valign="top" width="453">
            <p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">从系统启动开始累计到当前时刻，用户态的<span lang="EN-US">CPU</span>时间，不包含<span lang="EN-US">
            nice</span>值为负进程。<span lang="EN-US"></span></span></p>
            </td>
        </tr>
        <tr>
            <td style="padding: 0cm 5.4pt; width: 86.4pt;" valign="top" width="115">
            <p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">nice (102648)</span></p>
            </td>
            <td style="padding: 0cm 5.4pt; width: 339.7pt;" valign="top" width="453">
            <p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">从系统启动开始累计到当前时刻，<span lang="EN-US">nice</span>值为负的进程所占用的<span lang="EN-US">CPU</span>时间<span lang="EN-US"></span></span></p>
            </td>
        </tr>
        <tr>
            <td style="padding: 0cm 5.4pt; width: 86.4pt;" valign="top" width="115">
            <p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">system (238344)</span></p>
            </td>
            <td style="padding: 0cm 5.4pt; width: 339.7pt;" valign="top" width="453">
            <p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">从系统启动开始累计到当前时刻，核心时间<span lang="EN-US"></span></span></p>
            </td>
        </tr>
        <tr>
            <td style="padding: 0cm 5.4pt; width: 86.4pt;" valign="top" width="115">
            <p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">idle (167130733)</span></p>
            </td>
            <td style="padding: 0cm 5.4pt; width: 339.7pt;" valign="top" width="453">
            <p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">从系统启动开始累计到当前时刻，除<span lang="EN-US">IO</span>等待时间以外其它等待时间<span lang="EN-US"></span></span></p>
            </td>
        </tr>
        <tr>
            <td style="padding: 0cm 5.4pt; width: 86.4pt;" valign="top" width="115">
            <p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">iowait (758440)</span></p>
            </td>
            <td style="padding: 0cm 5.4pt; width: 339.7pt;" valign="top" width="453">
            <p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">从系统启动开始累计到当前时刻，<span lang="EN-US">IO</span>等待时间<span lang="EN-US"></span></span></p>
            </td>
        </tr>
        <tr>
            <td style="padding: 0cm 5.4pt; width: 86.4pt;" valign="top" width="115">
            <p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">irq (15159)</span></p>
            </td>
            <td style="padding: 0cm 5.4pt; width: 339.7pt;" valign="top" width="453">
            <p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">从系统启动开始累计到当前时刻，硬中断时间<span lang="EN-US"></span></span></p>
            </td>
        </tr>
        <tr>
            <td style="padding: 0cm 5.4pt; width: 86.4pt;" valign="top" width="115">
            <p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">softirq (17878)</span></p>
            </td>
            <td style="padding: 0cm 5.4pt; width: 339.7pt;" valign="top" width="453">
            <p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">从系统启动开始累计到当前时刻，软中断时间<span lang="EN-US"></span></span></p>
            </td>
        </tr>
    </tbody>
</table>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">&nbsp;</span></p>
<p class="MsoNormal" style="text-align: left; text-indent: 21pt;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">&nbsp;</span></p>
<p class="MsoNormal" style="text-align: left; text-indent: 21pt;" align="left"><span style="font-size: 12pt; font-family: 宋体;">因为<span lang="EN-US">/proc/stat</span>中的数值都是从系统启动开始累计到当前时刻的积累值，所以需要在不同时间点<span lang="EN-US">t1</span>和<span lang="EN-US">t2</span>取值进行比较运算，当两个时间点的间隔较短时，就可以把这个计算结果看作是<span lang="EN-US">CPU</span>的即时利用率。<span lang="EN-US"></span></span></p>
<p class="MsoNormal" style="text-align: left; text-indent: 21pt;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">&nbsp;</span></p>
<p class="MsoNormal" style="text-align: left; text-indent: 21pt;" align="left"><em><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">CPU</span></em><em><span style="font-size: 12pt; font-family: 宋体;">的即时利用率的计算公式：</span></em><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"></span></p>
<p class="MsoNormal" style="text-align: left; text-indent: 21pt;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">CPU</span><span style="font-size: 12pt; font-family: 宋体;">在<span lang="EN-US">t1</span>到<span lang="EN-US">t2</span>时间段总的使用时间<span lang="EN-US"> = ( user2+ nice2+ system2+ idle2+ iowait2+ irq2+ softirq2) - (
user1+ nice1+ system1+ idle1+ iowait1+ irq1+ softirq1)</span></span></p>
<p class="MsoNormal" style="text-align: left; text-indent: 21pt;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">CPU</span><span style="font-size: 12pt; font-family: 宋体;">在<span lang="EN-US">t1</span>到<span lang="EN-US">t2</span>时间段空闲使用时间<span lang="EN-US"> = (idle2 - idle1)</span></span></p>
<p class="MsoNormal" style="text-align: left; text-indent: 21pt;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">CPU</span><span style="font-size: 12pt; font-family: 宋体;">在<span lang="EN-US">t1</span>到<span lang="EN-US">t2</span>时间段即时利用率<span lang="EN-US"> = &nbsp;1 - CPU</span>空闲使用时间<span lang="EN-US"> / CPU</span>总的使用时间<span lang="EN-US"></span></span></p>
<p class="MsoNormal"><span lang="EN-US">&nbsp;</span></p>
<p class="MsoNormal"><span style="font-family: 宋体;">这些值是谁，什么时候记录的呢？</span></p>
<pre>每次<span lang="EN-US">timer</span>的中断就会记录一次，记录在<span lang="EN-US">struct <a  href="http://10.1.16.81/lxr/http/ident?i=cpu_usage_stat"><span style="color: windowtext;">cpu_usage_stat</span></a> </span>里，实现在<span lang="EN-US">timer_tick -&gt;update_process_times</span>里。</pre>
<pre>那么它的精度就是<span lang="EN-US">HZ,</span>如果<span lang="EN-US">HZ</span>是<span lang="EN-US">100</span>，就意味着每<span lang="EN-US">S</span>记录<span lang="EN-US">100</span>次。这个精度当然是不高的，而且容易出错，下面是在<span lang="EN-US">Documentation/cpu-load.txt</span>中的一个例子：</pre>
<pre><span lang="EN-US"><span>&nbsp; </span>time line between two timer interrupts</span></pre>
<pre><span lang="EN-US"> |--------------------------------------|</span></pre>
<pre><span lang="EN-US"> ^<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>^</span></pre>
<pre><span lang="EN-US"> |_ user appA begins working<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>|</span></pre>
<pre><span lang="EN-US"> <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>|_ user appA goes to sleep</span></pre>
<pre>结果这个<span lang="EN-US">A</span>的动作没有被记录下来，这一<span lang="EN-US">S</span>有可能被记录到其他的头上。如果你做的程序正好是那个其他，你就会抱怨说，这真是一陀屎呀。</pre>
<pre>那么有没有高精度的记录呢？</pre>
<pre>有，但是要自己写，就算你用<span lang="EN-US">oprofile</span>之类的，他的原理也是用<span lang="EN-US">timer_interrupt</span>记录的，你可以用其他的高精度<span lang="EN-US">timer</span>，但是，频繁的中断会把系统弄死。所以要自己写，假设有一个高精度的硬件<span lang="EN-US">counter</span>，好像<span lang="EN-US">x86</span>下的<span lang="EN-US">TimeStamp <em><span style="font-family: 宋体; font-style: normal;">Counter</span></em></span><em><span style="font-family: 宋体; font-style: normal;">，<span lang="EN-US"></span></span></em></pre>
<pre><em><span style="font-family: 宋体; font-style: normal;">在<span lang="EN-US">cpu_idle </span>里记录<span lang="EN-US">idle</span>的时间，在<span lang="EN-US">asm_do_IRQ</span>里记录处理<span lang="EN-US">irq</span>的时间，在<span lang="EN-US">context_switch</span>记录进入了那个<span lang="EN-US">process</span>，以及时间，在<span lang="EN-US">__do_softirq</span>里记录处理<span lang="EN-US">softirq</span>的时间，把这些东西记录在一块全局数组里。<span lang="EN-US"></span></span></em></pre>
<pre><span lang="EN-US"><br></span></pre><img src ="http://www.cppblog.com/zzfmars/aggbug/133175.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zzfmars/" target="_blank">Kevin_Zhang</a> 2010-11-10 09:31 <a href="http://www.cppblog.com/zzfmars/archive/2010/11/10/133175.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>linux c 函数库</title><link>http://www.cppblog.com/zzfmars/archive/2010/11/09/133123.html</link><dc:creator>Kevin_Zhang</dc:creator><author>Kevin_Zhang</author><pubDate>Tue, 09 Nov 2010 13:45:00 GMT</pubDate><guid>http://www.cppblog.com/zzfmars/archive/2010/11/09/133123.html</guid><wfw:comment>http://www.cppblog.com/zzfmars/comments/133123.html</wfw:comment><comments>http://www.cppblog.com/zzfmars/archive/2010/11/09/133123.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zzfmars/comments/commentRss/133123.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zzfmars/services/trackbacks/133123.html</trackback:ping><description><![CDATA[<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">http:</span><span style="color: #008000;">//</span><span style="color: #008000;">net.pku.edu.cn/~yhf/linux_c/</span></div>
linux c 函数库<br><img src ="http://www.cppblog.com/zzfmars/aggbug/133123.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zzfmars/" target="_blank">Kevin_Zhang</a> 2010-11-09 21:45 <a href="http://www.cppblog.com/zzfmars/archive/2010/11/09/133123.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>telnet命令的使用详解</title><link>http://www.cppblog.com/zzfmars/archive/2010/11/07/132838.html</link><dc:creator>Kevin_Zhang</dc:creator><author>Kevin_Zhang</author><pubDate>Sun, 07 Nov 2010 01:42:00 GMT</pubDate><guid>http://www.cppblog.com/zzfmars/archive/2010/11/07/132838.html</guid><wfw:comment>http://www.cppblog.com/zzfmars/comments/132838.html</wfw:comment><comments>http://www.cppblog.com/zzfmars/archive/2010/11/07/132838.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zzfmars/comments/commentRss/132838.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zzfmars/services/trackbacks/132838.html</trackback:ping><description><![CDATA[使用telnet<span class=t_tag onclick=tagshow(event) href="tag.php?name=%C3%FC%C1%EE">命令</span><span class=t_tag onclick=tagshow(event) href="tag.php?name=%B7%C3%CE%CA">访问</span>远程<span class=t_tag onclick=tagshow(event) href="tag.php?name=%BC%C6%CB%E3%BB%FA">计算机</span> <br>　　<span class=t_tag onclick=tagshow(event) href="tag.php?name=%D3%C3%BB%A7">用户</span>使用telnet命令进行远程登录。该命令允许用户使用telnet协议在远程计算机之间进行通信，用户可以通过<span class=t_tag onclick=tagshow(event) href="tag.php?name=%CD%F8%C2%E7">网络</span>在远程计算机上登录，就像登录到本地机上执行命令一样。为了通过telnet登录到远程计算机上，必须知道远程机上的合法用户名和口令。<br>&nbsp;&nbsp;虽然有些<span class=t_tag onclick=tagshow(event) href="tag.php?name=%CF%B5%CD%B3">系统</span>确实为远程用户提供登录功能，但出于对安全的考虑，要限制来宾的操作权限，因此，这种情况下能使用的功能是很少的。当允许远程用户登录时，系统通常把这些用户放在一个受限制的shell中，以防系统被怀有恶意的或不小心的用户破坏。用户还可以使用telnet从远程站点登录到自己的计算机上，检查电子<span class=t_tag onclick=tagshow(event) href="tag.php?name=%D3%CA%BC%FE">邮件</span>、编辑<span class=t_tag onclick=tagshow(event) href="tag.php?name=%CE%C4%BC%FE">文件</span>和运行<span class=t_tag onclick=tagshow(event) href="tag.php?name=%B3%CC%D0%F2">程序</span>，就像在本地登录一样。 <br>　　但是，用户只能使用基于终端的环境而不是X Wndows环境，telnet只为普通终端提供终端仿真，而不支持 X Wndow等图形环境。 <br><br>　　telnet命令的一般形式为：<br>telnet <span class=t_tag onclick=tagshow(event) href="tag.php?name=%D6%F7%BB%FA">主机</span>名/IP 其中&#8220;主机名/IP&#8221;是要连接的远程机的主机名或IP<span class=t_tag onclick=tagshow(event) href="tag.php?name=%B5%D8%D6%B7">地址</span>。<br>例：　telnet 192.168.0.1<br>如果这一命令执行成功，将从远程机上得到login：<span class=t_tag onclick=tagshow(event) href="tag.php?name=%CC%E1%CA%BE">提示</span>符。<br>　　使用telnet命令登录的过程如下：$ telnet 主机名/IP 启动telnet会话。 <br>一旦telnet成功地连接到远程系统上，就显示登录信息并提示用户输人用户名和口令。如果用户名和口令输入正确，就能成功登录并在远程系统上工作。在telnet提示符后面可以输入很多命令，用来控制telnet会话过程，在telnet联机帮助手册中对这些命令有详细的说明。 <br>　　下面是一台Linux计算机上的telnet会话举例： <br>　　$ telnet <span class=t_tag onclick=tagshow(event) href="tag.php?name=server">server</span>. somewhere. com Trying 127.0.0.1&#8230; Connected to serve. somewhere. com. Escape character is \';?]\';. &#8220;TurboLinux release 4. 0 （Colgate）<br>　 kernel 2.0.18 on an I486 <br>　 login: bubba password: Last login:Mon Nov l5 20:50:43 for localhost Linux 2. 0.6. （Posix）. server: ~$ server: ~$ logout Connection closed by foreign host $ <br>　　用户结束了远程会话后，一定要确保使用logout命令退出远程系统。然后telnet报告远程会话被关闭，并返回到用户的本地机的Shell提示符下。<br>　　r-系列命令 除ftp和telnet以外，还可以使用r-系列命令访问远程计算机和在网络上交换文件。使用r-系列命令需要特别注意，因为如果用户不小心，就会造成严重的安全漏洞。用户发出一个r-系列命令后，远程系统检查名为/etc/hosts.equiv的文件，以查看用户的主机是否列在这个文件中。如果它没有找到用户的主机，就检查远程机上同名用户的主目录中名为．rhosts的文件，看是否包括该用户的主机。如果该用户的主机包括在这两个文件中的任何一个之中，该用户执行r-系列命令就不用提供口令。 <br>　　虽然用户每次访问远程机时不用键入口令可能是非常方便的，但是它也可能会带来严重的安全问题。我们建议用户在建立/etc/hosts.equiv和.rhosts文件之前，仔细考虑r-命令隐含的安全问题。 <br><br><br>******************************************************　<br>telnet命令的使用详解<br>一 摘要 <br><br>　　Telnet的应用不仅方便了我们进行远程登录，也给hacker们提供了又一种入侵手段和后门，但无论如何，在你尽情享受Telnet所带给你的便捷的同时，你是否真正的了解Telnet呢？ <br><br>　　二 远程登录 <br><br>　　Telnet<span class=t_tag onclick=tagshow(event) href="tag.php?name=%B7%FE%CE%F1">服务</span>虽然也属于客户机/<span class=t_tag onclick=tagshow(event) href="tag.php?name=%B7%FE%CE%F1%C6%F7">服务器</span>模型的服务，但它更大的意义在于实现了基于Telnet协议的远程登录（远程交互式计算），那么就让我们来认识一下远程登录。 <br><br>　　1 远程<span class=t_tag onclick=tagshow(event) href="tag.php?name=%B5%C7%C2%BD">登陆</span>的基本概念 <br><br>　　先来看看什么叫登录：分时系统允许多个用户同时使用一台计算机，为了保证系统的安全和记帐方便，系统要求每个用户有单独的帐号作为登录标识，系统还为每个用户指定了一个口令。用户在使用该系统之前要输入标识和口令，这个过程被称为';登录';。 <br><br>　　远程登陆是指用户使用Telnet命令，使自己的计算机暂时成为远程主机的一个仿真终端的过程。仿真终端等效于一个非智能的<span class=t_tag onclick=tagshow(event) href="tag.php?name=%BB%FA%C6%F7">机器</span>，它只负责把用户输入的每个字符传递给主机，再将主机输出的每个信息回显在屏幕上。 <br><br>　　2 远程登陆的产生及发展 <br><br>　　我们可以先构想一个提供远程文字编辑的服务，这个服务的实现需要一个接受编辑文件请求和<span class=t_tag onclick=tagshow(event) href="tag.php?name=%CA%FD%BE%DD">数据</span>的服务器以及一个发送此请求的客户机。客户机将建立一个从本地机到服务器的TCP连接，当然这需要服务器的应答，然后向服务器发送键入的信息（文件编辑信息），并读取从服务器返回的输出。以上便是一个标准而普通的客户机/服务器模型的服务。 <br><br>　　似乎有了客户机/服务器模型的服务，一切远程问题都可以<span class=t_tag onclick=tagshow(event) href="tag.php?name=%BD%E2%BE%F6">解决</span>了。然而实际并非你想象的那样简单，如果我们仅需要远程编辑文件，那么刚才所构想的服务完全可以胜任，但假如我们的要求并不是这么简单，我们还想实现远程用户<span class=t_tag onclick=tagshow(event) href="tag.php?name=%B9%DC%C0%ED">管理</span>，远程数据录入，远程系统维护，想实现一切可以在远程主机上实现的操作，那么我们将需要大量专用的服务器程序并为每一个可计算服务都使用一个服务器进程，随之而来的问题是：远程机器会很快对服务器进程应接不暇，并淹没在进程的海洋里（我们在这里排除最专业化的远程机器）。 <br><br>　　那么有没有<span class=t_tag onclick=tagshow(event) href="tag.php?name=%B0%EC%B7%A8">办法</span>解决呢？当然有，我们可以用远程登录来解决这一切。我们允许用户在远地机器上建立一个登录会话，然后通过执行命令来实现更一般的服务，就像在本地操作一样。这样，我们便可以访问远地系统上所有可用的命令，并且系统设计员不需提供多个专用地服务器程序。 <br><br>　　问题发展到这里好像前途一片光明了，用远程登录总应该解决问题了吧，但要实现远程登陆并不简单。不考虑网络设计的计算机系统期望用户只从直接相连的键盘和显示器上登录，在这种机器上增加远程登陆功能需要修改机器的操作系统，这是极其艰巨也是我们尽量避免的。因此我们应该集中力量构造远程登陆服务器<span class=t_tag onclick=tagshow(event) href="tag.php?name=%C8%ED%BC%FE">软件</span>，虽然这样也是比较困难的。为什么说这样做也比较困难呢？ <br><br>　　举个例子来说：一般，操作系统会为一些特殊按键分配特殊的含义，比如本地系统将';Ctrl+C';解释为：';终止当前运行的命令进程';。但假设我们已经运行了远程登陆服务器软件，';Ctrl+C';也有可能无法被传送到远地机器，如果客户机真的将';Ctrl+C';传到了远地机器，那么';Ctrl+C';这个命令有可能不能终止本地的进程，也就是说在这里很可能会产生混乱。而且这仅仅是遇到的难题之一。 <br><br>　　但尽管有<span class=t_tag onclick=tagshow(event) href="tag.php?name=%BC%BC%CA%F5">技术</span>上的困难，系统编程人员还是设法构造了能够应用于大多数操作系统的远程登陆服务器软件，并构造了充当客户机的应用软件。通常，客户机软件取消了除一个键以外的所有键的本地解释，并将这些本地解释相应的转换成远地解释，这就使得客户机软件与远地机器的交互，就如同坐在远程主机面前一样，从而避免了上述所提到的混乱。而那个唯一例外的键，可以使用户回到本地环境。 <br><br>　　将远程登陆服务器设计为应用级软件，还有另一个要求，那就是需要操作系统提供对伪终端（pseudo terminal）的支持。我们用伪终端描述操作系统的入口点，它允许像Telnet服务器一样的程序向操作系统传送字符，并且使得字符像是来自本地键盘一样。只有使用这样的操作系统，才能将远程登陆服务器设计为应用级软件（比如Telnet服务器软件），否则，本地操作系统和远地系统传送将不能识别从对方传送过来的信息（因为它们仅能识别从本地键盘所键入的信息），远程登陆将宣告失败。 <br><br>　　将远程登陆服务器设计为应用级软件虽然有其显著的优点：比将<span class=t_tag onclick=tagshow(event) href="tag.php?name=%B4%FA%C2%EB">代码</span>嵌入操作系统更易修改和控制服务器。但其也有效率不高的缺点（后面的内容将会给予解释），好在用户键入信息的速率不高，这种设计还是可以接受的。 <br><br>　　3 远程登录的工作过程 <br><br>　　使用Telnet协议进行远程登陆时需要满足以下条件：在本的计算机上必须装有包含Telnet协议的客户程序；必须知道远程主机的Ip地址或<span class=t_tag onclick=tagshow(event) href="tag.php?name=%D3%F2%C3%FB">域名</span>；必须知道登录标识与口令。 <br><br>　　Telnet远程登录服务分为以下4个过程： <br><br>　　1）本地与远程主机建立连接。该过程实际上是建立一个TCP连接，用户必须知道远程主机的Ip地址或域名； <br><br>　　2）将本地终端上输入的用户名和口令及以后输入的任何命令或字符以NVT（Net Virtual Terminal）格式传送到远程主机。该过程实际上是从本地主机向远程主机发送一个IP数据报； <br><br>　　3）将远程主机输出的NVT格式的数据转化为本地所接受的格式送回本地终端，包括输入命令回显和命令执行结果； <br><br>　　4）最后，本地终端对远程主机进行撤消连接。该过程是撤销一个TCP连接。 <br><br>　　上面的内容只是<span class=t_tag onclick=tagshow(event) href="tag.php?name=%CC%D6%C2%DB">讨论</span>了远程登陆最基本的东西，其中的复杂和编程人员的艰辛是我们难以想象的，不知道你在舒服的使用Telnet的同时，是否想到了这些！ <br><br>　　三 Telnet协议 <br><br>　　我们知道Telnet服务器软件是我们最常用的远程登录服务器软件，是一种典型的客户机/服务器模型的服务，它应用Telnet协议来工作。那么，什么是Telnet协议？它都具备哪些特点呢？ <br><br>　　1 基本内容 <br><br>　　Telnet协议是TCP/IP协议族中的一员，是Internet远程登陆服务的标准协议。应用Telnet协议能够把本地用户所使用的计算机变成远程主机系统的一个终端。它提供了三种基本服务： <br><br>　　1）Telnet定义一个网络虚拟终端为远的系统提供一个标准接口。客户机程序不必详细了解远的系统，他们只需构造使用标准接口的程序； <br><br>　　2）Telnet包括一个允许客户机和服务器协商选项的机制，而且它还提供一组标准选项； <br><br>　　3）Telnet对称处理连接的两端，即Telnet不强迫客户机从键盘输入，也不强迫客户机在屏幕上显示输出。 <br><br>　　2 适应异构 <br><br>　　为了使多个操作系统间的Telnet交互操作成为可能，就必须详细了解异构计算机和操作系统。比如，一些操作系统需要每行文本用ASCII回车控制符（CR）结束，另一些系统则需要使用ASCII换行符（LF），还有一些系统需要用两个字符的序列回车-换行（CR-LF）；再比如，大多数操作系统为用户提供了一个中断程序运行的快捷键，但这个快捷键在各个系统中有可能不同（一些系统使用CTRL+C，而另一些系统使用ESCAPE）。如果不考虑系统间的异构性，那么在本地发出的字符或命令，传送到远地并被远地系统解释后很可能会不准确或者出现错误。因此，Telnet协议必须解决这个问题。 <br><br>　　为了适应异构环境，Telnet协议定义了数据和命令在Internet上的传输方式，此定义被称作网络虚拟终端NVT（Net Virtual Terminal）。它的应用过程如下： <br><br>　　对于发送的数据：客户机软件把来自用户终端的按键和命令序列转换为NVT格式，并发送到服务器，服务器软件将收到的数据和命令，从NVT格式转换为远地系统需要的格式； <br>　　对于返回的数据：远地服务器将数据从远地机器的格式转换为NVT格式，而本地客户机将将接收到的NVT格式数据再转换为本地的格式。 <br>　　对于NVT格式的详细定义，有兴趣的<span class=t_tag onclick=tagshow(event) href="tag.php?name=%C5%F3%D3%D1">朋友</span>可以去查找相关资料。 <br><br>　　3 传送远地命令 <br><br>　　我们知道绝大多数操作系统都提供各种快捷键来实现相应的控制命令，当用户在本地终端键入这些快捷键的时候，本地系统将执行相应的控制命令，而不把这些快捷键作为输入。那么对于Telnet来说，它是用什么来实现控制命令的远地传送呢？ <br><br>　　Telnet同样使用NVT来定义如何从客户机将控制功能传送到服务器。我们知道USASCII字符集包括95个可打印字符和33个控制码。当用户从本地键入普通字符时，NVT将按照其原始含义传送；当用户键入快捷键（组合键）时，NVT将把它转化为特殊的ASCII字符在网络上传送，并在其到达远地机器后转化为相应的控制命令。将正常ASCII字符集与控制命令区分主要有两个原因： <br><br>　　1）这种区分意味着Telnet具有更大的灵活性：它可在客户机与服务器间传送所有可能的ASCII字符以及所有控制功能； <br><br>　　2）这种区分使得客户机可以无二义性的指定信令，而不会产生控制功能与普通字符的混乱。 <br><br>　　4 数据流向 <br><br>　　上面我们提到过将Telnet设计为应用级软件有一个缺点，那就是：效率不高。这是为什么呢？下面给出Telnet中的数据流向： <br><br>　　数据信息被用户从本地键盘键入并通过操作系统传到客户机程序，客户机程序将其处理后返回操作系统，并由操作系统经过网络传送到远地机器，远地操作系统将所接收数据传给服务器程序，并经服务器程序再次处理后返回到操作系统上的伪终端入口点，最后，远地操作系统将数据传送到用户正在运行的应用程序，这便是一次完整的输入过程；输出将按照同一通路从服务器传送到客户机。 <br><br>　　因为每一次的输入和输出，计算机将切换进程环境好几次，这个开销是很昂贵的。还好用户的键入速率并不算高，这个缺点我们仍然能够接受。 <br><br>　　5 强制命令 <br><br>　　我们应该考虑到这样一种情况：假设本地用户运行了远地机器的一个无休止循环的错误命令或程序，且此命令或程序已经停止读取输入，那么操作系统的缓冲区可能因此而被占满，如果这样，远地服务器也无法再将数据写入伪终端，并且最终导致停止从TCP连接读取数据，TCP连接的缓冲区最终也会被占满，从而导致阻止数据流流入此连接。如果以上事情真的发生了，那么本地用户将失去对远地机器的控制。 <br><br>　　为了解决此问题，Telnet协议必须使用外带信令以便强制服务器读取一个控制命令。我们知道TCP用紧急数据机制实现外带数据信令，那么Telnet只要再附加一个被称为数据标记(date mark)的保留八位组，并通过让TCP发送已<span class=t_tag onclick=tagshow(event) href="tag.php?name=%C9%E8%D6%C3">设置</span>紧急数据比特的报文段通知服务器便可以了，携带紧急数据的报文段将绕过流量控制直接到达服务器。作为对紧急信令的相应，服务器将读取并抛弃所有数据，直到找到了一个数据标记。服务器在遇到了数据标记后将返回正常的处理过程。 <br><br>　　6 选项协商 <br><br>　　由于Telnet两端的机器和操作系统的异构性，使得Telnet不可能也不应该严格规定每一个telnet连接的详细配置，否则将大大影响Telnet的适应异构性。因此，Telnet采用选项协商机制来解决这一问题。 <br><br>　　Telnet选项的范围很广：一些选项扩充了大方向的功能，而一些选项制涉及一些微小细节。例如：有一个选项可以控制Telnet是在半双工还是全双工模式下工作（大方向）；还有一个选项允许远地机器上的服务器决定用户终端类型（小细节）。 <br><br>　　Telnet选项的协商方式也很有意思，它对于每个选项的处理都是对称的，即任何一端都可以发出协商<span class=t_tag onclick=tagshow(event) href="tag.php?name=%C9%EA%C7%EB">申请</span>；任何一端都可以接受或拒绝这个申请。另外，如果一端试图协商另一端不了解的选项，接受请求的一端可简单的拒绝协商。因此，有可能将更新，更复杂的Telnet客户机服务器版本与较老的，不太复杂的版本进行交互操作。如果客户机和服务器都理解新的选项，可能会对交互有所改善。否则，它们将一起转到效率较低但可工作的方式下运行。所有的这些设计，都是为了增强适应异构性，可见Telnet的适应异构性对其的应用和发展是多么重要。 <br><br>　　上面讨论了一些原理方面的东西，虽然我们在Telnet的使用过程中很难接触到这一层面，但我认为了解这些是有意义的，它会给我们带来许多启示。下面让我们来看看Win2000的Telnet服务。 <br><br>　　四 Win2000的Telnet服务 <br><br>　　其实从应用层面上，Win2000的Telnet服务并没有什么可说的，绝大部分内容你都可以从HELP文件中得到，我在此只是把它稍微整理一下而已。 <br><br>　　1 基本配置 <br><br>　　Win2000为我们提供了Telnet客户机和服务器程序：Telnet.<span class=t_tag onclick=tagshow(event) href="tag.php?name=exe">exe</span>是客户机程序（Client），tlntsvr.exe是服务器程序（server），同时它还为我们提供了Telnet服务器管理程序tlntadmn.exe。 <br><br>　　Windows 2000 默认安装了 Telnet 服务，但是并没有默认启动。下面给出HELP文件中 Telnet 服务的一部分默认设置： <br><br>　　AllowTrustedDomain：是否允许域用户访问。默认值是1，允许信任域用户访问。可以改为0: 不允许域用户访问（只允许本地用户）。 <br><br>　　DefaultDomain：可以对与该计算机具有信任关系的任何域设置。默认值是"."。 <br><br>　　DefaultShell：显示 shell 安装的路径位置。默认值是： %systemroot%System32Cmd.exe /q /k <br><br>　　MaxFailedLogins：在连接终止之前显示尝试登录失败的最大次数。默认是3。 <br><br>　　LoginScript：显示 Telnet 服务器登录脚本的路径位置。默认的位置就是&#8220;%systemroot%System32login.cmd&#8221;，你可以更改脚本内容，这样登录进Telnet的欢迎屏幕就不一样了。 <br><br>　　NTLM：NTLM身份验证选项。默认是2。可以有下面这些值： <br>　　0: 不使用 NTLM 身份验证。 <br>　　1: 先尝试 NTLM 身份验证，如果失败，再使用用户名和<span class=t_tag onclick=tagshow(event) href="tag.php?name=%C3%DC%C2%EB">密码</span>。 <br>　　2: 只使用 NTLM 身份验证。 <br><br>　　TelnetPort：显示 telnet 服务器侦听 telnet 请求的<span class=t_tag onclick=tagshow(event) href="tag.php?name=%B6%CB%BF%DA">端口</span>。默认是：23。你也可以更改为其他端口。 <br><br>　　以上各项设置你可以使用tlntadmn.exe（Telnet服务器管理程序）来进行非常方便的配置，配置后需要重新启动Telnet服务。如图1 <br><br>　　2 NTLM <br><br>　　提到了telnet就不能不提NTLM，我想这也是让入侵者最为头痛的一件事，哪怕你获得了管理员帐号和密码，想简单通过NTLM也并非易事，况且win2000中的telnet默认仅以NTLM方式验证身份，这就让我们不得不关注NTLM这个东东，那么什么是NTLM呢？ <br><br>　　早期的SMB协议在网络上明文传输口令，后来出现了"LAN Manager Challenge/Response"验证机制，简称LM，它十分简单以至很容易被<span class=t_tag onclick=tagshow(event) href="tag.php?name=%C6%C6%BD%E2">破解</span>，微软随后提出了WindowsNT挑战/响应验证机制，即NTLM。现在已经有了更新的NTLMv2以及Kerberos验证体系。NTLM工作流程是这样的： <br><br>　　1、客户端首先在本地加密当前用户的密码成为密码散列 <br>　　2、客户端向服务器发送自己的帐号，这个帐号是没有经过加密的，明文直接传输 <br>　　3、服务器产生一个16位的随机数字发送给客户端，作为一个 challenge（挑战） <br>　　4、客户端再用加密后的密码散列来加密这个 challenge ，然后把这个返回给服务器。作为 response（响应） <br>　　5、服务器把用户名、给客户端的challenge 、客户端返回的 response 这三个东西，发送域控制器 <br>　　6、域控制器用这个用户名在 SAM密码管理库中找到这个用户的密码散列，然后使用这个密码散列来加密 challenge。 <br>　　7、域控制器比较两次加密的 challenge ，如果一样，那么认证成功。 <br><br>　　从上面的过程我们可以看出，NTLM是以当前用户的身份向Telnet服务器发送登录请求的，而不是用你扫到的对方管理员的帐户和密码登录，显然，你的登录将会失败。举个例子来说，你家的机器名为A（本地机器），你入侵的机器名为B（远地机器），你在A上的帐户是xinxin，密码是1234，你扫到B的管理员帐号是Administrator，密码是5678，当你想Telnet到B时，NTLM将<span class=t_tag onclick=tagshow(event) href="tag.php?name=%D7%D4%B6%AF">自动</span>以当前用户的帐号和密码作为登录的凭据来进行上面的7项操作，即用xinxin和1234，而并非用你扫到的Administrator和5678，且这些都是自动完成的，根本不给你插手的机会，因此你的登录操作将失败。 <br><br>　　由于Telnet服务器对NTLM的使用有3个选项，所以当你Telnet远地机器时，会显示下面情况中的一种： <br><br>　　1)身份验证选项=0时 <br>　　===================================== <br>　　Microsoft (R) Windows (TM) Version 5.00 (Build 2195) <br>　　Welcome to Microsoft Telnet Service <br>　　Telnet Server Build 5.00.99201.1 <br>　　login: <br>　　password: <br><br>　　\为0时不使用NTML身份验证，直接输入用户名和密码，比如你可以输入扫到的Administrator和5678 <br><br>　　2)身份验证选项=1时 <br>　　===================================== <br>　　NTLM Authentication failed due to insufficient credentials. Please login withclear text username and password <br>　　Microsoft (R) Windows (TM) Version 5.00 (Build 2195) <br>　　Welcome to Microsoft Telnet Service <br>　　Telnet Server Build 5.00.99201.1 <br>　　login: <br>　　password: <br><br>　　\先尝试 NTLM 身份验证，如果失败，再使用用户名和密码，其实这种方式对于我们来说，与上一种方式没什么区别 <br><br>　　3)身份验证选项=2时 <br>　　===================================== <br>　　NTLM Authentication failed due to insufficient credentials. Please login withclear text username and password <br>　　Server allows NTLM authentication only <br>　　Server has closed connection <br>　　遗失对主机的连接。 <br>　　C:&gt; <br><br>　　\仔细看看上面的显示，根本没有给你输入用户名和密码的机会，直接断开连接，扫到了密码也是白扫 <br><br>　　所以对于入侵者来说，NTLM是横在我们面前的一座大山，必须要除掉它，一般我们有如下几种方法： <br><br>　　1通过修改远程注册表更改telnet服务器配置，将验证方式从2改为1或0； <br>　　2使用NTLM.exe，上传后直接运行，可将telnet服务器验证方式从2改为1； <br>　　3在本地建立扫描到的用户，以此用户身份开启telnet客户机并进行远程登录； <br>　　4使用软件，比如opentelnet.exe（需要管理员权限且开启IPC管道） <br>　　5使用脚本，如RTCS，（需要管理员权限但不依赖IPC管道） <br><br>　　基本上是以上的5种，其中后两种是我们比较常用的开telnet的手法，而且使用方法十分简单，命令如下： <br><br>　　OpenTelnet.exe \server username password NTLMAuthor telnetport <br>　　OpenTelnet.exe \服务器地址 管理员用户名 密码 验证方式（填0或1） telnet端口 <br><br>　　cscript RTCS.vbe targetIP username password NTLMAuthor telnetport <br>　　cscript RTCS.vbe &lt;目标IP&gt; &lt;管理员用户名&gt; &lt;密码&gt; &lt;验证方式&gt; <br><br>　　五 在telnet中该做什么 <br><br>　　本来写到上面就想结束了，不过许多朋友都说telnet上去后不知道该做什么了，既然这样，那我就抛砖引玉吧，这次不讲具体做法，只是说说思路，什么？为什么不讲具体做法？篇幅不够嘛，以后我会一一解释的。 <br><br>　　1 查看系统信息 <br><br>　　呵呵，其实就是随处看看，看看他的系统配置和版本（用type c:oot.ini来知道pro版或server版），看看都装了什么服务或软件（从目录名就可以知道了），看看有什么重要或有趣的文件啦（唉，要是国外的机器，看也看不懂），看看他的用户情况，总之就是尽可能多的了解系统，为一会装后门摸底。 <br><br>　　2 使用tftp传送文件 <br><br>　　想必大家都遇到过在telnet中传输文件的问题，因为我们习惯了在ipc管道中的文件传输，所以有些朋友喜欢用net share ipc$ 来打开管道，进而利用copy来传输文件。不过这样反而麻烦，既然我们已经得到了shell，我们可以用TFPT命令来完成这一切，什么是T<span class=t_tag onclick=tagshow(event) href="tag.php?name=FTP">FTP</span>呢？ <br><br>　　用TFTP(Trivial File Transfer Protocol)来实现文件的传送是一种基于UDP连接的文件传输，一般是使用Windows自带的tftp.exe和一个TFTP服务器端软件构成一个完整的传输结构。它是这样使用的： 首先运行本地的TFTP Server（比如tftpd32.exe）软件并保证始终开启直至传输全部完成， 然后在telnet中（当然你也可以在其他shell中）运行下面的命令： <br>　　C:&gt;tftp &#8211;i ip get xinxin.exe c:abcxinxin.exe <br>　　其中ip为你自己机器的ip，且上传文件要与TFTP服务器端在同一目录下，这样你就可以把xinxin.exe上传到c盘abc目录下了（其实是从tftp服务器<span class=t_tag onclick=tagshow(event) href="tag.php?name=%CF%C2%D4%D8">下载</span>来的） <br><br>　　需要指出的是，如果使用代理IP，你将不能实现与外部网络的文件传送。因为你的代理网关在进行数据封装的时候会将自己的IP地址加入到你的数据报中，代替你的内部网络地址，所以在外部网络进行MAC寻址时是找不到你这台TFTP服务器的。 <br><br>　　3 安置后门 <br><br>　　安置后门放在第二步好像早了点，如果你入侵还有其他目的，比如以破坏为主，或者是来修改主页的，那么这些事情当然可以在安置后门之前做；如果你只是想得到一只肉鸡，那就没什么可说的了，安后门吧。 <br><br>　　后门的种类繁多，也给我们提供了很大的选择余地，能够根据具体情况选择合适的后门的确是一门学问。常用的后门一般有：<span class=t_tag onclick=tagshow(event) href="tag.php?name=%C4%BE%C2%ED">木马</span>，asp木马，远程控制软件，克隆帐户，建立并隐藏帐户，telnet，telnet扩展的shell，终端服务等。安置一个好的后门通常要注意以下几点： <br><br>　　1 不会被<span class=t_tag onclick=tagshow(event) href="tag.php?name=%B7%C0%BB%F0%C7%BD">防火墙</span>查杀及阻碍通信：被加入病毒库的后门最好加壳以逃过防火墙，尽量用低端口通信，以免被防火墙屏蔽。 <br><br>　　2 最大限度增加隐蔽性：如果你选择远程控制软件，要注意被控端的安装提示和小图标，以及是否同步画面；如果你在帐户上做文章，要尽量保持在cmd和用户管理中都不出破绽；如果你选择放木马或telnet扩展，要注意文件和进程的隐藏；如果新开了终端服务（入侵前并没有开），一定要该掉3389这个显眼的端口，且越低越好。 <br><br>　　3 不要当管理员不存在：这是一个大忌，许多朋友在只有默认帐户的机器上建立类似';hacking';的管理员帐户，真是无知者无畏呀。所以安置后门的时候，想想管理员疏忽的地方会在哪里。 <br><br>　　4 打补丁 <br><br>　　如果想独霸肉鸡，就要会打补丁，要知道对肉鸡的竞争是很激烈的。怎么打补丁呢？这个也要问？想想你是怎么进来的吧。算了，提示一下，除了修补大的漏洞以外（上传官方补丁并运行），也要注意它的共享，ipc$共享（最好都关闭），可疑端口，容易被利用的服务等。不过打补丁也要注意隐蔽性的，不要让管理员发现大的改动。 <br><br>　　5 清除<span class=t_tag onclick=tagshow(event) href="tag.php?name=%C8%D5%D6%BE">日志</span> <br><br>　　可以手动或利用软件，如果不太会就去找相关教材吧，在这里我不详细介绍了。 <br><br>　　六 结束语 <br><br>　　文章的前部分主要说了一些原理性的东西，后部分则侧重于应用，写的多了难免会有些遗漏。<br><br>************************************************<br>当开始运行Telnet时,情况如何呢?一个应用系统由两部分组成:&#8220;client&#8221;——这就是Telnet简介所说的客户机，另一部分是&#8220;server&#8221;——这是运行于网络计算机上提供服务的系统，称之为服务器。而网络（即使用TCP也使用UDP的服务器）则是提供两者（Clinet与Server)通信的<span class=t_tag onclick=tagshow(event) href="tag.php?name=%B9%A4%BE%DF">工具</span>。 <br>这里要求客户机必须做到: <br>(1)建立一个网络与服务器间的TCP连接 <br>(2)以方便的方式接收输入 <br>(3)对某些标准的格式化输入作重新格式化并作重新格式化并传送给服务器。 <br>(4)以某些标准的格式化从服务器中接受输出 <br>(5)重新格式化显示给自己的输出 <br>服务器软件是运行于主机上提供服务的系统，如果没有运行服务系统，也就不能提供相应的服务。 <br>某一类服务被调用，它就可以： <br>(1)通知网络软件，让它准备连接； <br>(2)等待一个标准的格式化要求的产生； <br>(3)服务请求； <br>(4)传送一个标准格式的结果给客户； <br>(5)重新等待 <br>一个服务器应该能够处理各种客户，有的是运行在同类的<span class=t_tag onclick=tagshow(event) href="tag.php?name=%B5%E7%C4%D4">电脑</span>上的，而有的是运行在 IBM / PCs , Macintoshes , Amigas等各种不同的机器上。为了做到这一点，服务器必须具有一套通信规则，这种规则通常叫做协议。由于Telnet协议用于两个应用层之间所以叫做应用层协议。任何人都可以在任何类型的电脑上编制一个客户机。只要这个客户机可以<span class=t_tag onclick=tagshow(event) href="tag.php?name=%C9%CF%CD%F8">上网</span>通讯并遵守协议，他就可以进入服务器。实际上也就是说，用户的 Macintosh可以使用Telnet和其他的的Internet的工具，从而能让很多不同的系统为其工作。 <br>就使用来说，一个应用层协议通常允许客户机和服务器有不同的数据设定，并通告客户机和服务器使用相互的通信方式。这些经常是有每行在开始的几个字节的文本程序来完成的。如果服务器发送一个以&#8220;TXT&#8221;字符开头的行命令给客户，那么这行 &#8220;TXT&#8221; 后边其他的数据就被送入屏幕显示。如果一行的开始是以&#8220;CMD&#8221;开始，则表明这些信息是从服务软件到客户软件。使用者是看不到这些的，这是因为在信息传送到时这些控制信号已去掉了。 <br><br>除了在Telnet是如何工作的例子介绍的以外,Telnet还有很多的特点。Telnet可发送除了"escape"的任何字符到远程主机上。因为"escape"字符在Telnet中是客户机的一个特殊的命令模式，它的默认值是"Ctrl-]"。但要注意不要与键盘上的Esc键混淆，我们可以设定"escape"为任意某个字符，只是对Telnet来说以为着该字符不可能再被传送到远程主机上，而Esc键是一非打印字符，Telnet用它来<span class=t_tag onclick=tagshow(event) href="tag.php?name=%C9%BE%B3%FD">删除</span>远程系统中的命令。而且还应记住，"escape"字符并不总以"Ctrl-]"来表示。 <br>可以仅仅键入Telnet,后面不带机器字句。这种情况下所看到的是Telnet&gt;,这是告知Telnet在等待键入命令，比如键入问号"?"那么就得到一个有用的命令表： <br>telnet: ? <br>CoMMands may be abbreviated, CoMMand are: <br>open connect to a site <br>close close currect connection <br>quit exit telnet <br>display display operating parameters <br>send transmit special characters (';send ?'; for more) <br>set set operating parameters(';set ?'; for more) <br>status print status information <br>toggle toggle operating parameters(';toggle ?'; for more) <br>mode try to enter line-by-line or character-at-a-time mode <br>? print help information <br>虽然命令很多，甚至还有子命令，但只有一些是常用的。现在介绍以下的几个： <br>Close： <br>该命令用语终止连接。它自动切断与远程系统的连接，也可以用它退出Telnet，在冒失的进入一个网络主机时，想退出的话，就可以用到这个命令。 <br>open： <br>用它来与一个命名机器连接，要求给出目标机器的名字或IP地址。如果未给出机器名，Telnet就将要你选择一个机器名。必须注意，在使用"Open"命令之前应该先用"close"来关闭任何已经存在的连接。 <br>Set ECHO： <br>用于本地的响应是On或是Off。作用是是否把输出的内容显示在屏幕上。和DOS的ECHO基本上是一样。如果机器是处于ECHO ON的话，想改变为OFF，那么就可以输入SET ECHO,想再改变回ECHO OFF，那么就再键入SET ECHO就可以了。(这儿说的比较简短,如果有不明白的,可以与我联系) <br>Set escape char: <br>建立"escape"字符到某个特殊的符号，若想用某种控制符号来代替，可以用"asis"或者键入符号"^"加字母b(如：^b）。在正常工作时，是不需要用"escape"这个字符的，并且这个被用作"escape"的符号不应该再被使用。这类似于许多程序中对键盘上的每一个键设定其真正的涵义。但如果正在运行一个 daisy-chained 应用系统，那么可以重新议定"escape"字符的特征便是很有用的。例如：用Telnet从系统A到系统B，接着又用Telnet注册进入系统C。如果正在系统C上工作时出了<span class=t_tag onclick=tagshow(event) href="tag.php?name=%B9%CA%D5%CF">故障</span>，那么当"escape"代表符是相同时，就没法中断系统B到系统C的连接。键入"escape"代表符，将总是处于系统A的命令模式。如果在每个Telnet部分使用不同的"escape"代表符，便可以通过键入适当的符号，来选择其中一个命令模式，这也可以用于其他的应用中（像终端仿真）。 <br>Quit: <br>用它可顺利地推出Telnet程序。 <br>Z: <br>用语保留Telnet但暂时回到本地系统执行其他命令。并且在Telnet中的连接以及其他的选择在Telnet恢复时仍被保留。 <br>Carriage Return: <br>用于不具体的一个命令从命令模式返回到所连接的远程机器上。另外，还有许多其他的命令可以推出命令模式。下面举一个例子，是从注册进入到porky.math.ukans.edu ,然后进入命令模式，然后返回porky:: <br>telnet porky.math.ukans.edu <br>Trying 129.237.128.11... <br>Connected to porky.math.ukans.edu. <br>Escape character is ';^]';. <br>SunOS UNIX(porky) <br>login:wl <br>password: <br>Last Login: Tue Mar 28 05:35 from ns.bta.net.cn <br>SunOS Release 4.1.3_U1(SLIPPERY1) #3: Sun Nov 20 23:47:23 CST 1999 <br>No match. <br>if:Expression syntax. <br>porky/serv/wl%cd/ <br>porky/%CTRL-] <br>telnet:? <br>CoMMands may be abbreviated, CoMMand are: <br>open connect to a site <br>close close currect connection <br>quit exit telnet <br>display display operating parameters <br>send transmit special characters (';send ?'; for more) <br>set set operating parameters(';set ?'; for more) <br>status print status information <br>toggle toggle operating parameters(';toggle ?'; for more) <br>mode try to enter line-by-line or character-at-a-time mode <br>? print help information <br>telnet:set escape ^b <br>escape character is &#8217;^b&#8217; <br>porky/%logout <br>ns.bta.net.cn% <br>注意：set命令也可以退出命令模式。当然，如果不行，可以回车输入一空行，也能回到porky。<br><a href="http://baike.baidu.com/view/44255.htm">http://baike.baidu.com/view/44255.htm</a>
<img src ="http://www.cppblog.com/zzfmars/aggbug/132838.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zzfmars/" target="_blank">Kevin_Zhang</a> 2010-11-07 09:42 <a href="http://www.cppblog.com/zzfmars/archive/2010/11/07/132838.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ubuntu 10.04 源</title><link>http://www.cppblog.com/zzfmars/archive/2010/08/28/125091.html</link><dc:creator>Kevin_Zhang</dc:creator><author>Kevin_Zhang</author><pubDate>Sat, 28 Aug 2010 15:01:00 GMT</pubDate><guid>http://www.cppblog.com/zzfmars/archive/2010/08/28/125091.html</guid><wfw:comment>http://www.cppblog.com/zzfmars/comments/125091.html</wfw:comment><comments>http://www.cppblog.com/zzfmars/archive/2010/08/28/125091.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zzfmars/comments/commentRss/125091.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zzfmars/services/trackbacks/125091.html</trackback:ping><description><![CDATA[ubuntu 10.04 source<br>&nbsp;这是电子科技大学的源，教育网的速度还可以，比自带的源快了很多。<br>修改源的方法：<br>&nbsp;在终端输入：sudo gedit /etc/apt/sources.list<br>然后再打开的源文件中将原来的源列表替换为下面的列表即可。&nbsp;<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%; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #000000">deb&nbsp;http:</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">ubuntu.dormforce.net/ubuntu/&nbsp;lucid&nbsp;main&nbsp;restricted&nbsp;universe&nbsp;multiverse</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">deb&nbsp;http:</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">ubuntu.dormforce.net/ubuntu/&nbsp;lucid-backports&nbsp;main&nbsp;restricted&nbsp;universe&nbsp;multiverse</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">deb&nbsp;http:</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">ubuntu.dormforce.net/ubuntu/&nbsp;lucid-proposed&nbsp;main&nbsp;restricted&nbsp;universe&nbsp;multiverse</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">deb&nbsp;http:</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">ubuntu.dormforce.net/ubuntu/&nbsp;lucid-security&nbsp;main&nbsp;restricted&nbsp;universe&nbsp;multiverse</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">deb&nbsp;http:</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">ubuntu.dormforce.net/ubuntu/&nbsp;lucid-updates&nbsp;main&nbsp;restricted&nbsp;universe&nbsp;multiverse</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">deb</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">src&nbsp;http:</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">ubuntu.dormforce.net/ubuntu/&nbsp;lucid&nbsp;main&nbsp;restricted&nbsp;universe&nbsp;multiverse</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">deb</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">src&nbsp;http:</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">ubuntu.dormforce.net/ubuntu/&nbsp;lucid-backports&nbsp;main&nbsp;restricted&nbsp;universe&nbsp;multiverse</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">deb</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">src&nbsp;http:</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">ubuntu.dormforce.net/ubuntu/&nbsp;lucid-proposed&nbsp;main&nbsp;restricted&nbsp;universe&nbsp;multiverse</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">deb</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">src&nbsp;http:</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">ubuntu.dormforce.net/ubuntu/&nbsp;lucid-security&nbsp;main&nbsp;restricted&nbsp;universe&nbsp;multiverse</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">deb</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">src&nbsp;http:</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">ubuntu.dormforce.net/ubuntu/&nbsp;lucid-updates&nbsp;main&nbsp;restricted&nbsp;universe&nbsp;multiverse</span></div>
<br><br>
<img src ="http://www.cppblog.com/zzfmars/aggbug/125091.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zzfmars/" target="_blank">Kevin_Zhang</a> 2010-08-28 23:01 <a href="http://www.cppblog.com/zzfmars/archive/2010/08/28/125091.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Ubuntu 安装</title><link>http://www.cppblog.com/zzfmars/archive/2010/08/27/124975.html</link><dc:creator>Kevin_Zhang</dc:creator><author>Kevin_Zhang</author><pubDate>Fri, 27 Aug 2010 14:15:00 GMT</pubDate><guid>http://www.cppblog.com/zzfmars/archive/2010/08/27/124975.html</guid><wfw:comment>http://www.cppblog.com/zzfmars/comments/124975.html</wfw:comment><comments>http://www.cppblog.com/zzfmars/archive/2010/08/27/124975.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zzfmars/comments/commentRss/124975.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zzfmars/services/trackbacks/124975.html</trackback:ping><description><![CDATA[<a href="http://bbs.cfanclub.net/read.php?tid-274934.html">http://bbs.cfanclub.net/read.php?tid-274934.html</a>
<img src ="http://www.cppblog.com/zzfmars/aggbug/124975.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zzfmars/" target="_blank">Kevin_Zhang</a> 2010-08-27 22:15 <a href="http://www.cppblog.com/zzfmars/archive/2010/08/27/124975.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ubuntu常用命令集合</title><link>http://www.cppblog.com/zzfmars/archive/2010/08/20/124047.html</link><dc:creator>Kevin_Zhang</dc:creator><author>Kevin_Zhang</author><pubDate>Thu, 19 Aug 2010 18:32:00 GMT</pubDate><guid>http://www.cppblog.com/zzfmars/archive/2010/08/20/124047.html</guid><wfw:comment>http://www.cppblog.com/zzfmars/comments/124047.html</wfw:comment><comments>http://www.cppblog.com/zzfmars/archive/2010/08/20/124047.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zzfmars/comments/commentRss/124047.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zzfmars/services/trackbacks/124047.html</trackback:ping><description><![CDATA[<h1 class="title_txt"><cite class="fav_csdnstylebykimi"> </cite>
</h1>
<div class="blogstory">
<script type="text/javascript">
document.body.oncopy = function () {
if (window.clipboardData) {
setTimeout(function () {
var text = clipboardData.getData("text");
if (text && text.length > 300) {
text = text + "\r\n\n本文来自CSDN博客，转载请标明出处：" + location.href;
clipboardData.setData("text", text);
}
}, 100);
}
}
</script>
<script type="text/javascript">						function StorePage() { d = document; t = d.selection ? (d.selection.type != 'None' ? d.selection.createRange().text : '') : (d.getSelection ? d.getSelection() : ''); void (keyit = window.open('http://www.365key.com/storeit.aspx?t=' + escape(d.title) + '&u=' + escape(d.location.href) + '&c=' + escape(t), 'keyit', 'scrollbars=no,width=475,height=575,left=75,top=20,status=no,resizable=yes')); keyit.focus(); }</script>
<p><span style="color: #ff0000;">1.在终端中或者按alt+f2,在其中输入程序名称即可,如运行EVA,则只需 键入&#8220;eva&#8221;即可，无需附带路径。<br>
(类似Windows下的运行),最基本的操作入口.<br>
</span>
2.添加程序快捷方式到菜单中<br>
系统－首选项－主菜单－新建项目<br>
填入命令（即程序名称,如要建立sopcast的快捷方式，则输入sopcast即可）<br>
<br>
3.虚拟光驱部分<br>
<br>
挂载ISO文件,sudo mount -o loop files.iso 目标文件夹（sudo在终端中暂时取得root权限）<br>
卸载 &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sudo umount 挂载文件夹<br>
&nbsp;&nbsp;<br>
如挂载 /home/dudu/XP.iso 到 /home/dudu/iso文件夹<br>
&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; sudo mount -o loop /home/dudu/XP.iso /home/dudu/iso<br>
or sudo mount -t iso9660 /home/dudu/XP.iso /home/dudu/iso（iso9660为指定文件格式）<br>
<br>
卸载ISO文件 sudo umount /home/dudu/iso<br>
<br>
.iso文件的建立<br>
1.从文件夹建立，如将/home/dudu/ebooks/下的文件镜像为/home/dudu/ebooks.iso<br>
(sudo) mkisofs -o /home/dudu/ebooks.iso /home/dudu/ebboks/<br>
2.从光驱建立(光驱路径根据实际情况会有所不同)<br>
sudo umount /media/cdrom0<br>
(sudo) dd if=/media/cdrom0 of=/home/dudu/ebooks.iso bs=1024<br>
<br>
文件烧录(也可使用k3b等程序烧录)<br>
1.格式化盘片<br>
&nbsp;&nbsp; &nbsp;&nbsp; sudo umount /media/cdrom0<br>
&nbsp;&nbsp; &nbsp;&nbsp; (sudo) cdrecord dev=/media/cdrom0 blank=fast<br>
2.烧录<br>
命令行输入 nautilus burn:///<br>
再打开新窗口，将文件拖入刻录窗口即可<br>
&nbsp;&nbsp; <br>
4.进入目录 cd 目标文件夹<br>
返回上一级目录 cd ..<br>
cd ~ 或 cd 回当前用户的宿主目录<br>
cd ~用户名回指定用户的宿主目录<br>
cd - 回上一次所在的目录<br>
&nbsp;&nbsp;<br>
5.新建文件夹，当然你也可以通过右键建立，如在/home/dudu下建名为iso的文件夹<br>
sudo mkdir /home/dudu/iso<br>
由于使用了sudo，此文件夹只有root才能改动<br>
<br>
6.取得root权限<br>
sudo su<br>
or sudo -i<br>
以root身份使用文件管理器,如我要在图形界面下删除上面建立的iso文件夹<br>
sudo nautilus<br>
&nbsp;&nbsp;<br>
密码修改(慎用)<br>
root密码修改 sudo passwd root 然后二次输入密码<br>
<br>
7.文件管理部分<br>
文件备份（复制）,sudo cp<br>
sudo cp /etc/samba/smb.conf /etc/samba/smb.conf_backup<br>
（备份/etc/samba/smb.comf到/etc/samba/下，命名为smb.conf_backup）&nbsp;&nbsp;<br>
移动 mv 格式同cp<br>
删除 rm filename<br>
ls -a 列出当前目录下的所有文件，包括以.头的隐含文件<br>
ls -l或ll 列出当前目录下文件的详细信息 <br>
<br>
链接（和WIN下快捷方式差不多），摘自《鸟哥私房菜》<br>
ln 源文件链接名 创建当前目录源文件的硬链接<br>
ln /home/test /usr/test1 在/usr下建立/home/test的硬链接<br>
ln -s a b 创建当前目录下a的符号链接b<br>
－s参数形成symbolic链接，相当于快捷方式.此外，如果你做了底下这样的连结：<br>
ln &#8211;s /bin /root/bin<br>
那
么如果你进入 /root/bin 这个目录下，（请注意呦！该目录其实是 /bin 这个目录，因为你做了连结档了！）所以，如果你进入
/root/bin 这个刚刚建立的连结目录，并且将其中的数据杀掉时，嗯！ /bin 里面的数据就通通不见了！这点请千万注意！并不是 /root
底下的资料都是 root 的！还需要注意一下该属性才行<br>
<br>
<br>
8.ADSL<br>
开始设置sudo pppoeconf ，然后一路enter，填上用户名和密码就OK了<br>
手工断线 sudo poff<br>
手工连接 sudo pon dsl-provider<br>
查看连接日志 &nbsp;&nbsp;&nbsp; plog<br>
查看连接详情 ifconfig<br>
有线网络内有漫游和DHCP两种模式，漫游就是让它自动寻找可用连接，一般使用DHCP<br>
ping命令使用 ping ip/网址 -c 要ping的次数 (网址前无http://)<br>
<br>
9.samba的一些设置(与XP互联时)<br>
工作组设置<br>
1.文件备份 sudo cp /etc/samba/smb.conf /etc/samba/smb.conf_backup<br>
2.打开编辑器 sudo gedit /etc/samba/smb.conf<br>
找到 &nbsp;&nbsp;&nbsp; workgroup=MSHOME, 用 &nbsp;&nbsp;&nbsp; workgroup=new_domian_or_workgroup 替换,保存关闭<br>
3. sudo testparm<br>
4.重启samba sudo /etc/init.d/samba restart<br>
<br>
10.软件安装方式<br>
1.新立德安装<br>
2. .deb包安装双击即可，也可到终端安装，如安装/home/dudu/file.debsu<br>
&nbsp;&nbsp; 安装 sudo dpkg -i /home/dudu/file.deb<br>
&nbsp;&nbsp; 卸载 sudo dpkg -r file（此处直接填写程序名称，即菜单里的名称）<br>
&nbsp;&nbsp; 重新配置或修复 sudo dpkg-reconfigure file<br>
3.gz压缩包编译安装，如安装/home/dudu/text.tar.gz<br>
1.解压缩 tar zxvf /home/dudu/text.tar.gz (默认解压到当前用户主目录下)<br>
&nbsp;&nbsp; 然后转到解压后文件夹中 cd /home/dudu/text<br>
<br>
（若文件夹中存在*.pl，*.sh文件，则sudo ./*.pl or ./*.sh即可完成安装，以下是编译安装）<br>
<br>
2.执行./configure (./configure --prefix=路径，即可装入指定目录)<br>
3.执行make，如果没问题<br>
4.执行make install<br>
4.rpm包<br>
1.安装alien<br>
&nbsp;&nbsp; sudo apt-get install alien<br>
2.通过alien安装rpm包<br>
&nbsp;&nbsp; alien -d package-name.rpm<br>
5..bin文件安装<br>
&nbsp;&nbsp; chmod +x filename.bin (取得权限)<br>
&nbsp;&nbsp; ./filename.bin<br>
<br>
11.压缩文件部分<br>
1.zip格式<br>
1.添加压缩文件夹 /home/dudu/zip 为/home/dudu/winrar.zip<br>
zip /home/dudu/winrar.zip zip<br>
注:zip
文件夹和winrar.zip均在../dudu下（即主目录，压缩文件可添加到任何路径，但是源文件需在../dudu下，可以是文件也可以是文件夹，
否则压缩文件解压后会是从/home/dudu/........./zip，即为从新建的home文件夹开始的多个包含文件夹，如zip
/home/dudu/winrar.zip
/home/dudu/zip/则在../dudu下生成home文件夹，里面包含dudu和zip两个文件夹）<br>
zip -m /home/dudu/winrar zip压缩，并自动删除原始文件zip<br>
zip -r 压缩，包含子目录中的内容<br>
zip -j 压缩，忽略子目录中的内容<br>
zip -1 压缩，压缩率为1<br>
2.解压缩<br>
unzip /home/dudu/winrar.zip 解压到当前文件夹<br>
<br>
2.tar与gzip<br>
&nbsp;&nbsp; 说明：tar无法对文件进行压缩，但可以把文件打包。而gzip虽然可以压缩文件，却不能把文件打包。所以我们经常把两个命令结合使用，产生.tar.gz的文件。一般压缩流程是先用tar打包，再用gzip压缩文件。<br>
&nbsp;&nbsp; # tar cvf test.tar * 把当前目录(*)下的文件打包，若有链接文件，直接将链接写入<br>
&nbsp;&nbsp; # tar zcvf test.tar.gz * 把当前目录(*)下的文件打包并压缩为gz格式<br>
&nbsp;&nbsp; # tar jcvf test.tar.bz2 * 把当前目录下的文件打包并压缩为bz2格式<br>
&nbsp;&nbsp; # tar hcvf test.tar * 把当前目录下的文件打包，若有链接文件，直接将原始文件写入<br>
<br>
&nbsp;&nbsp; # tar xvf test.tar 把test.tar解包<br>
&nbsp;&nbsp; # tar zxvf test.tar.gz 把test.tar.gz解压缩并解包<br>
<br>
&nbsp;&nbsp; gzip 压缩文件<br>
&nbsp;&nbsp; # gzip file1 压缩file1，并删除原始文件，这点务必要注意<br>
&nbsp;&nbsp; # gzip -1 * 压缩本目录所有文件，压缩率为1-9，9最高，默认6<br>
&nbsp;&nbsp; # gzip -d file1.gz 解压file1.gz文件<br>
&nbsp;&nbsp; gunzip 解压文件<br>
&nbsp;&nbsp; # gunzip file1.gz 解压file1.gz文件<br>
<br>
12.可移动介质无法打开问题解决，重启DBUS,也可用来解决开机出现"failde to initialize HAL" bug<br>
sudo /etc/init.d/dbus restart<br>
<br>
13.Mplayer无法播放rmvb,rm(参见wiki)<br>
首先确定安装了w32codecs,打开Mplayer界面上右击 - perferences - video - x11/vx<br>
<br>
14.在桌面显示我的电脑等图标<br>
gconf-editor<br>
在/apps/nautilus/desktop/分支下选择相应项目<br>
<br>
15.sudo apt-get install lunar-applet<br>
添加农历日期<br>
<br>
16.进程管理,也可通过系统－系统管理－系统监视器进行管理<br>
ps -A查看进程<br>
kill -9 进程号，终止进程<br>
强行结束终端中运行的操作，如想终止Wget等等.<br>
ctrl+c<br>
<br>
17.开关机的一些操作<br>
ctrl+alt+backspace 登出桌面<br>
sudo shutdown now -h &nbsp;&nbsp;&nbsp; 关机<br>
sudo reboot &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 重启<br>
ctrl+alt+F1 &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 进入控制台（全字符界面）<br>
<br>
18.解决主菜单及应用程序菜单无法打开(安装wine后可能会出现这个问题)<br>
gmenu-simple-editor 然后选择默认值<br>
<br>
19.启动服务管理,同XP的msconfig设置开机自启动项<br>
sudo sysv-rc-conf<br>
<br>
20.opera 无法输入中文<br>
先安装QT<br>
sudo apt-get install scim-qtimm ,同样适用于EVA<br>
1.将opera中切换到主页的快捷方式删除<br>
2.sudo gedit /usr/bin/opera<br>
第二行添加<br>
export QT_IM_MODULE="scim" （去掉双引号也可）<br>
<br>
21.通过sudo apt-get方式安装软件时下载的包默认保存目录<br>
/var/cache/apt/archives<br>
<br>
22.文件权限<br>
chmod chmod u+s file 为file的属主加上特殊权限<br>
chmod g+r file 为file的属组加上读权限<br>
chmod o+w file 为file的其它用户加上写权限<br>
chmod a-x file 为file的所有用户减去执行权限<br>
chmod 765 file 为file的属主设为完全权限，属组设成读写权，其它用户具有读<br>
<br>
chown chown root /home 把/home的属主改成root用户<br>
chgrp chgrp root /home 把/home的属组改成root组<br>
<br>
23.磁盘部分<br>
1.挂载FAT # mount &#8211;t vfat /dev/hda5 /mnt/cdrom 挂第一个ide的第五个逻辑分区<br>
2.df 用于报告文件系统的总容量，使用量，剩余容量。<br>
3.du -b /home 查看目前/HOME目录的容量(k)及子目录的容量(k)。<br>
4. fdisk -l 查看系统分区信息<br>
5. fdisk /dev/sdb 为一块新的SCSI硬盘进行分区<br>
<br>
24.修复Grub<br>
1.用Live cd引导进入终端<br>
2.sudo grub &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; <br>
&nbsp;&nbsp; find /boot/grub/stage1<br>
&nbsp;&nbsp; (若/boot单独分出，则用/grub/stage1替换,stage1也可用menu.lst替换)<br>
root (hdX,Y)<br>
&nbsp;&nbsp; setup (hdX)<br>
&nbsp;&nbsp; quit<br>
&nbsp;&nbsp; (注意：其中X，Y是输入find后出现的提示)<br>
<br>
25.glxinfo|grep "direct rendering" 查看显卡3D加速是否打开<br>
<br>
26./etc/init.d/halt 关机设置的配置文件，可以更改硬盘掉电时间等<br>
<br>
27.密码重置<br>
1.开机<br>
2.在grub启动列表中按ESC<br>
3.按 e 来修改平时启动的那个选项<br>
4.在kernel***那一行再按 e<br>
5.在最后面加上 rw init=/bin/bash<br>
6.按确定<br>
7.按 b 来启动<br>
此时是你在使用root用户，所以要小心不要乱按其他命令，除非你知道你在干什么。<br>
8.用 passwd &lt;用户名&gt; 来重设你的密码<br>
9.重启 shutdown -r now<br>
<br>
28.sudo dpkg-reconfigure xserver-xorg 重调分辨率<br>
<br>
29.更改登录是的黄色背景<br>
sudo gedit /etc/gdm/PreSession/Default<br>
找到<br>
# Default value<br>
if [ "x$BACKCOLOR" = "x" ]; then<br>
&nbsp;&nbsp; BACKCOLOR="#dab082"<br>
fi<br>
#dab082 就是颜色 可以随便改。<br>
<span style="color: #99cc00;">附:Linux常用命令全集<br>
WEB版:&nbsp;&nbsp;&nbsp; </span>
<a  href="http://linux.chinaitlab.com/special/linuxcom/Index.html" id="url_486" onclick="return checkurl(this)" target="_blank"><span style="color: #99cc00;">http://linux.chinaitlab.com/special/linuxcom/Index.html</span></a><a  href="http://linux.chinaitlab.com/special/linuxcom/Index.html" id="url_486" onclick="return checkurl(this)" target="_blank">
</a>
</p>
</div><img src ="http://www.cppblog.com/zzfmars/aggbug/124047.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zzfmars/" target="_blank">Kevin_Zhang</a> 2010-08-20 02:32 <a href="http://www.cppblog.com/zzfmars/archive/2010/08/20/124047.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> ubuntu 终端命令集 2</title><link>http://www.cppblog.com/zzfmars/archive/2010/08/20/124046.html</link><dc:creator>Kevin_Zhang</dc:creator><author>Kevin_Zhang</author><pubDate>Thu, 19 Aug 2010 18:30:00 GMT</pubDate><guid>http://www.cppblog.com/zzfmars/archive/2010/08/20/124046.html</guid><wfw:comment>http://www.cppblog.com/zzfmars/comments/124046.html</wfw:comment><comments>http://www.cppblog.com/zzfmars/archive/2010/08/20/124046.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zzfmars/comments/commentRss/124046.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zzfmars/services/trackbacks/124046.html</trackback:ping><description><![CDATA[<p>整个电脑都划成ubuntu用。<br>
装软件时的一个明显感觉就是很多事情，用终端的命令行去做很容易，用图形界面往往很复杂，而且很多时候还会出现权限的问题，对于ubuntu的用户权限，现在的唯一感觉就是权限在ubuntu里很重要，很多操作都对应着相应的权限<br>
现在把常用的一些命令在这里集中一下，这样以后自己用着也方便一点，不用再开好几个页面看来看去了：<br>
<br>
以下均为网上搜集，非原创...........</p>
<h4><span><span style="font-size: small;">sudo:需要提升权限执行的命令</span>
</span>
</h4>
<ul>
    <li>如果您所在的目录或想操作的文件不在您的帐户所在的目录，下面的大多数命令都需要使用
    <strong>sudo</strong>
    命令。这是一个特殊的命令，它给你临时的权限来修改系统设置。终端会询问你的密码。</li>
</ul>
<h4><span><span style="font-size: small;">文件 &amp;
目录类命令</span>
</span>
</h4>
<ul>
    <li><strong>pwd</strong>
    ：<strong>pwd</strong>
    命令查看您当前所处的路径（<strong>pwd</strong>
    代表
    "打印当前工作目录"）。例如：在桌面文件夹中执行 "pwd" 命令将输出 "~/Desktop"。注意，Gnome
    的终端在窗口标题中也会显示这一信息-具体请看本页顶部的截屏图片。</li>
</ul>
<ul>
    <li>
    <strong>cd</strong>
    ：<strong>cd</strong>
    命令用来改变当前工作目录。当您打开一个终端的时候，您就位于您的home目录中。如果想要切换到其它的目录，就要用
    <strong>cd</strong>
    命令。例如：</li>
    <li>进入root目录，输入 <strong>"cd /"</strong>
    </li>
    <li>进入到您自己的目录（home目录），输入 <strong>"cd"</strong>
    </li>
    <li>进入当前目录的上一层目录，输入 <strong>"cd .."</strong>
    (译者注：cd 与 .. 之间有空格)</li>
    <li>进入前一个操作的目录，输入 <strong>"cd -"</strong>
    </li>
    <li>一次进入多层目录，输入 <strong>"cd /var/www"</strong>
    ,将会直接切换到/var的子目录/www中。另一个例子，
    <strong>"cd ~/Desktop"</strong>
    将会进入到您的桌面目录</li>
</ul>
<ul>
    <li><strong>cp</strong>
    ：<strong>cp</strong>
    命令用来复制文件。例如：<strong>"cp file
    foo"</strong>
    命令将会创建一个"file"的精确的副本，并命名为"foo",而
    "file"不会有任何变化。如果是复制目录，那就得用<strong>"cp -r directory foo"</strong>
    （递归地复制）。</li>
</ul>
<ul>
    <li><strong>mv</strong>
    ：<strong>mv</strong>
    命令将文件移动到另一个位置或者给文件更名。看下面的例子：<strong>"mv file
    foo"</strong>
    命令会将文件"file"更名为"foo"。<strong>"mv foo
    ~/Desktop"</strong>
    会将文件"foo"移动到桌面目录，但不会更名。如果想更名，你必须要指定一个新的名字。</li>
</ul>
<ul>
    <li>为了输入方便，您可以用 '~' 符号来代替您的home目录。</li>
</ul>
<ul>
    <li>
    如果在用mv命令的时候前面加上了sudo，那么&#8220;~&#8220;这个符号将可以正常使用，终端会把他替换成你自己（普通用户）的home目录。而如果你用
    &#8221;sudo -i&#8220;或者&#8221;sudo
    -s&#8220;打开了一个root用户的终端，那么这时&#8221;~&#8220;将指代root用户的home目录，而非你自己的。</li>
</ul>
<ul>
    <li><strong>rm</strong>
    ：这个命令用来移动或删除文件。对于非空的目录，用这个命令不能删除。</li>
</ul>
<ul>
    <li><strong>rmdir</strong>
    ：命令<strong>rmdir</strong>
    用来删除&#8220;空&#8221;目录。要删除目录和其中的所有内容，则需使用<strong>rm
    -r</strong>
    。</li>
</ul>
<ul>
    <li><strong>mkdir</strong>
    ：<strong>mkdir</strong>
    命令用来创建目录。例如：<strong>"mkdir
    music"</strong>
    将会创建一个 music 目录。</li>
</ul>
<ul>
    <li><strong>man</strong>
    ：<strong>man</strong>
    命令用来显示其它命令的手册页。执行 <strong>"man man"</strong>
    可以查看到
    man自己的信息。通过 "<strong>Man</strong>
    &amp; Getting
    Help"能够分页显示更多的信息。</li>
    <li>Linux/Ubuntu tar命令详解使用格式和方法
    <p><span>格式： tar 选项 文件目录列表<br>
    功能： 对文件目录进行打包备份<br>
    选项：<br>
    -c 建立新的归档文件<br>
    -r 向归档文件末尾追加文件<br>
    -x 从归档文件中解出文件<br>
    -O 将文件解开到标准输出<br>
    -v 处理过程中输出相关信息<br>
    -f 对普通文件操作<br>
    -z 调用gzip来压缩归档文件，与-x联用时调用gzip完成解压缩<br>
    -Z 调用compress来压缩归档文件，与-x联用时调用compress完成解压缩</span>
    </p>
    <p><span>例如：</span>
    </p>
    <p><span>1.将当前目录下所有.txt文件打包并压缩归档到文件this.tar.gz，我们可以使用</span>
    </p>
    <p><span>tar czvf this.tar.gz ./*.txt</span>
    </p>
    <p><span>2.将当前目录下的this.tar.gz中的文件解压到当前目录我们可以使用</span>
    </p>
    <p><span>tar xzvf this.tar.gz ./</span>
    </p>
    </li>
</ul>
<h4><span><a  href="http://wiki.ubuntu.org.cn/index.php?title=UbuntuHelp:UsingTheTerminal/zh&amp;action=edit&amp;section=10" title="编辑段落: 系统信息类命令">
</a>
</span>
<span><span style="font-size: small;">系统信息类命令</span>
</span>
</h4>
<ul>
    <li><strong>df</strong>
    ：<strong>df</strong>
    命令用来查看各个文件系统当前的空间使用状况。<strong>"df
    -h"</strong>
    可能是最有用的选项了-它以M和G为单位输出，而不是以块为单位。(<strong>-h</strong>
    的含义是&#8220;便于阅读&#8221;)</li>
</ul>
<ul>
    <li>
    <strong>du</strong>
    ：<strong>du</strong>
    命令可以显示某一个目录使用了多少磁盘空间。它可以显示该目录中的各个子目录分别使用了多少空间，也可以显示当前目录一共占了多少空间。</li>
    <li><strong>-s</strong>
    代表&#8221;概况、总览&#8220;，<strong>-h</strong>
    则代表&#8221;易于人阅读&#8220;。</li>
</ul>
<ul>
    <li><strong>free</strong>
    ：<strong>free</strong>
    命令用来查看系统中使用和剩馀的内存情况。<strong>"free -m"</strong>
    将结果以M为单位输出，这对现在的计算机来说非常有用。</li>
</ul>
<ul>
    <li><strong>top</strong>
    ：<strong>top</strong>
    命令用来查看linux系统的信息，运行着的进程和系统资源，包括
    CPU、内存以及交换分区使用情况和运行着的任务的总的数量。退出 top ，按<strong>"q"</strong>
    。</li>
</ul>
<ul>
    <li><strong>uname -a</strong>
    ：<strong>uname</strong>
    命令的 <strong>-a</strong>
    参数用来查看系统的所有信息，包括
    机器名，内核名称 &amp; 版本 和一些其它的细节。它最大的用处是用来查看当前所用内核的信息。</li>
    <li><strong>lsb_release
    -a</strong>
    ：<strong>lsb_release</strong>
    命令的<strong>-a</strong>
    参数查看当前运行的linux的版本信息</li>
    <li><strong>ifconfig</strong>
    显示当前系统的网络接口信息。
    <h4><span><span style="font-size: small;">添加新用户</span>
    </span>
    </h4>
    </li>
    <li><strong>"adduser newuser"</strong>
    命令用来创建一个用户名为"newuser"的新用户，为新用户 newuser
    创建一个密码，使用如下命令<strong>"passwd newuser"</strong>
    。</li>
</ul>
<h3><span><a  href="http://wiki.ubuntu.org.cn/index.php?title=UbuntuHelp:UsingTheTerminal/zh&amp;action=edit&amp;section=12" title="编辑段落: 选项">
</a>
</span>
<span><span style="font-size: medium;">选项</span>
</span>
</h3>
<p>命令的默认操作常常会被指定一个确定的 <strong>--参数</strong>
所修改。例如<strong>ls</strong>
命令有一个<strong>-s</strong>
参数，因此
<strong>"ls -s"</strong>
就会额外的显示出文件的大小。它也有一个
<strong>-h</strong>
参数，将文件的大小以很好的可读性的格式输出。参数可以以簇聚合,比如 <strong>"ls -sh"</strong>
和<strong>"ls
-s -h"</strong>
的效果相同。大多数的参数都很长，两个破折号前缀代表一个参数，所以<strong>"ls --size
--human-readable"</strong>
也和上面得命令相同。</p>
<h3>&nbsp;<span><span style="font-size: medium;">'Man' 和
获得帮助</span>
</span>
</h3>
<p><strong>man <em>command</em>
</strong>
, <strong>info <em>command</em>
</strong>
and
<strong><em>command</em>
--help</strong>
是命令行下面最重要的工具。</p>
<p>在linux下面，几乎每一个命令和每一个应用程序都会有一个man(manual)文件，所以只要简单的键入<strong>"man
"command""</strong>
就能看到这个命令的手册页。例如，<strong>"man mv"</strong>
会打开mv (Move) 的手册页。</p>
<p>利用键盘上的方向键移动手册页面，用<strong>"q"</strong>
退出。</p>
<p><strong>"man man"</strong>
会查看<strong>man</strong>
命令的手册页，这里是一个很好的开始！</p>
<p><strong>"man intro"</strong>
也非常有用 －它能够查看
"用户命令介绍"，写的非常好！是一份很简介的linux命令的介绍。</p>
<p>还有一个就是<strong>info</strong>
命令了，它通常比<strong>man</strong>
还深入。输入<strong>"info
info"</strong>
命令可得到info页的介绍。</p>
<p>一些软件开发人员喜欢用 <strong>info</strong>
而不是 <strong>man</strong>
（例如Debian和GNU开发人员）。所以，如果你发现一个很常见的命令或者程序没有 <strong>man</strong>
页面，那么就试试
<strong>info</strong>
页面。</p>
<p>几乎所有的命令都能接受一个<strong>-h</strong>
(或
<strong>--help</strong>
)选项，能够输出命令的简要的描述和参数，然后自动退回命令提示符。可以输入<strong>"man
-h"</strong>
或<strong>"man --help"</strong>
查看。</p>
<p>警告：一些软件不认为 <strong>-h</strong>
选项代表帮助，虽然少但是存在这种情况。这时候可以先试试 <strong>man</strong>
或者
<strong>info</strong>
页面，以及使用较长的选项 <strong>--help</strong>
。</p>
<h4><span><span style="font-size: small;">搜索man文档</span>
</span>
</h4>
<p>如果您不确定用哪个命令或程序，您可以试试搜索<strong>man</strong>
文件。</p>
<ul>
    <li><strong>man -k <em>foo</em>
    </strong>
    会搜索关于foo的man文件。试试看<strong>"man -k
    nautilus"</strong>
    是怎样的。</li>
    <li>注意：这同<strong>apropos</strong>
    命令是一样的。</li>
    <li><strong>man -f <em>foo</em>
    </strong>
    仅仅搜所系统man文件的标题。试试<strong>"man -f
    gnome"</strong>
    。</li>
    <li>这个同 <strong>whatis</strong>
    命令是相同的。
    <h4><span><span style="font-size: small;">节省输入</span>
    </span>
    </h4>
    <table border="1" cellspacing="0">
        <tbody>
            <tr>
                <td><strong>Up Arrow</strong>
                or <strong>ctrl+p</strong>
                </td>
                <td><br>
                </td>
                <td>滚动显示你之前输入的命令.（译者注，与msdos相似）</td>
            </tr>
            <tr>
                <td><strong>Down Arrow</strong>
                or <strong>ctrl+n</strong>
                </td>
                <td><br>
                </td>
                <td>回到较近的命令.（与up arrow相反，反方向滚动）</td>
            </tr>
            <tr>
                <td><strong>Enter</strong>
                </td>
                <td><br>
                </td>
                <td>找到你要的命令时按回车确认<br>
                </td>
            </tr>
            <tr>
                <td><strong>tab</strong>
                </td>
                <td><br>
                </td>
                <td>一个非常有用的功能。如果只有一个选项，则自动补全命令或文件名；否则给出所有选项的列表。</td>
            </tr>
            <tr>
                <td><strong>ctrl+r</strong>
                </td>
                <td><br>
                </td>
                <td>搜索你已经输入的命令.当你已经输入了一条很长很复杂的命令并且要重复它时,
                使用这个按键组合，然后输入命令的一部分将会从你的集合历史中搜索. 找到它后，只要轻轻按下回车</td>
            </tr>
        </tbody>
    </table>
    <span>更改字体</span>
    <p>不能用鼠标。你可以容左/方向键来移动。当游标在你想让它在的地方时，输入 <em>inserts</em>
    text - ie
    它不会改写那儿的文字。</p>
    <table border="1" cellspacing="0">
        <tbody>
            <tr>
                <td><strong>ctrl+a</strong>
                or <strong>Home</strong>
                </td>
                <td><br>
                </td>
                <td>移动游标到行首.</td>
            </tr>
            <tr>
                <td><strong>ctrl+e</strong>
                or <strong>End</strong>
                </td>
                <td><br>
                </td>
                <td>移动游标到行尾.</td>
            </tr>
            <tr>
                <td><strong>ctrl+b</strong>
                </td>
                <td><br>
                </td>
                <td>移动游标到上一个或当前单词的前面.</td>
            </tr>
            <tr>
                <td><strong>ctrl+k</strong>
                </td>
                <td><br>
                </td>
                <td>删除从当前游标到行尾的文字.</td>
            </tr>
            <tr>
                <td><strong>ctrl+u</strong>
                </td>
                <td><br>
                </td>
                <td>删除当前整行.</td>
            </tr>
            <tr>
                <td><strong>ctrl+w</strong>
                </td>
                <td><br>
                </td>
                <td>删除游标前的单词.</td>
            </tr>
        </tbody>
    </table>
    </li>
</ul><img src ="http://www.cppblog.com/zzfmars/aggbug/124046.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zzfmars/" target="_blank">Kevin_Zhang</a> 2010-08-20 02:30 <a href="http://www.cppblog.com/zzfmars/archive/2010/08/20/124046.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>