关于作者

用户名:chongsoft
笔名:chongsoft
地区: 北京-海淀
行业:本科

日历  

快速登录

+ 用户名:
+ 密 码:

在线留言


访问统计:
文章个数:62
评论个数:8
留言条数:1




Powered by BlogDriver 2.1

Make everyday colorful!

 

学而下者谓之器,学而上者谓之道

文章

setsockopt使用 (转)

Linux系统调用--getsockopt/setsockopt函数详解

2007-09-07 23:33

【 getsockopt/setsockopt系统调用】  
   
功能描述:
获取或者设置与某个套接字关联的选 项。选项可能存在于多层协议中,它们总会出现在最上面的套接字层。当操作套接字选项时,选项位于的层和选项的名称必须给出。为了操作套接字层的选项,应该 将层的值指定为SOL_SOCKET。为了操作其它层的选项,控制选项的合适协议号必须给出。例如,为了表示一个选项由TCP协议解析,层应该设定为协议 号TCP。


用法:
#include <sys/types.h>
#include <sys/socket.h>

int getsockopt(int sock, int level, int optname, void *optval, socklen_t *optlen);

int setsockopt(int sock, int level, int optname, const void *optval, socklen_t optlen);

参数:  
sock:将要被设置或者获取选项的套接字。
level:选项所在的协议层。
optname:需要访问的选项名。
optval:对于getsockopt(),指向返回选项值的缓冲。对于setsockopt(),指向包含新选项值的缓冲。
optlen:对于getsockopt(),作为入口参数时,选项值的最大长度。作为出口参数时,选项值的实际长度。对于setsockopt(),现选项的长度。

   
返回说明:  
成功执行时,返回0。失败返回-1,errno被设为以下的某个值  
EBADF:sock不是有效的文件描述词
EFAULT:optval指向的内存并非有效的进程空间
EINVAL:在调用setsockopt()时,optlen无效
ENOPROTOOPT:指定的协议层不能识别选项
ENOTSOCK:sock描述的不是套接字

http://club.cn.yahoo.com/bbs/threadview/1200062866_62__pn1.html

--------------------------
开发网络程序使用setsockopt的一些好并且需要常注意的地方:

1. 如果在已经处于 ESTABLISHED状态下的socket(一般由端口号和标志符区分)调用
closesocket(一般不会立即关闭而经历TIME_WAIT的过程)后想继续重用该socket:
BOOL bReuseaddr=TRUE;
setsockopt(s,SOL_SOCKET ,SO_REUSEADDR,(const char*)&bReuseaddr,sizeof(BOOL));

2. 如果要已经处于连接状态的soket在调用closesocket后强制关闭,不经历
TIME_WAIT的过程:
BOOL   bDontLinger = FALSE;
setsockopt(s,SOL_SOCKET,SO_DONTLINGER,(const char*)&bDontLinger,sizeof(BOOL));

3.在send(),recv()过程中有时由于网络状况等原因,发收不能预期进行,而设置收发时限:
int nNetTimeout=1000;//1秒
//发送时限
setsockopt(socket,SOL_S0CKET,SO_SNDTIMEO,(char *)&nNetTimeout,sizeof(int));
//接收时限
setsockopt(socket,SOL_S0CKET,SO_RCVTIMEO,(char *)&nNetTimeout,sizeof(int));

4.在send()的时候,返回的是实际发送出去的字节(同步)或发送到socket缓冲区的字节
(异步);系统默认的状态发送和接收一次为8688字节(约为8.5K);在实际的过程中发送数据
和接收数据量比较大,可以设置socket缓冲区,而避免了send(),recv()不断的循环收发:
// 接收缓冲区
int nRecvBuf=32*1024;//设置为32K
setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int));
//发送缓冲区
int nSendBuf=32*1024;//设置为32K
setsockopt(s,SOL_SOCKET,SO_SNDBUF,(const char*)&nSendBuf,sizeof(int));

5. 如果在发送数据的时,希望不经历由系统缓冲区到socket缓冲区的拷贝而影响
程序的性能:
int nZero=0;
setsockopt(socket,SOL_S0CKET,SO_SNDBUF,(char *)&nZero,sizeof(nZero));

6.同上在recv()完成上述功能(默认情况是将socket缓冲区的内容拷贝到系统缓冲区):
int nZero=0;
setsockopt(socket,SOL_S0CKET,SO_RCVBUF,(char *)&nZero,sizeof(int));

7.一般在发送UDP数据报的时候,希望该socket发送的数据具有广播特性:
BOOL   bBroadcast=TRUE;
setsockopt(s,SOL_SOCKET,SO_BROADCAST,(const char*)&bBroadcast,sizeof(BOOL));

8.在client连接服务器过程中,如果处于非阻塞模式下的socket在connect()的过程中可
以设置connect()延时,直到accpet()被呼叫(本函数设置只有在非阻塞的过程中有显著的
作用,在阻塞的函数调用中作用不大)
BOOL bConditionalAccept=TRUE;
setsockopt(s,SOL_SOCKET,SO_CONDITIONAL_ACCEPT,(const char*)&bConditionalAccept,sizeof(BOOL));

9.如果在发送数据的过程中(send()没有完成,还有数据没发送)而调用了closesocket(),以前我们
一般采取的措施是"从容关闭"shutdown(s,SD_BOTH),但是数据是肯定丢失了,如何设置让程序满足具体
应用的要求(即让没发完的数据发送出去后在关闭socket)?
struct linger {
   u_short     l_onoff;
   u_short     l_linger;
};
linger m_sLinger;
m_sLinger.l_onoff=1;//(在closesocket()调用,但是还有数据没发送完毕的时候容许逗留)
// 如果m_sLinger.l_onoff=0;则功能和2.)作用相同;
m_sLinger.l_linger=5;//(容许逗留的时间为5秒)
setsockopt(s,SOL_SOCKET,SO_LINGER,(const char*)&m_sLinger,sizeof(linger));
Note:1.在设置了逗留延时,用于一个非阻塞的socket是作用不大的,最好不用;
     2.如果想要程序不经历SO_LINGER需要设置SO_DONTLINGER,或者设置l_onoff=0;

10.还一个用的比较少的是在SDI或者是Dialog的程序中,可以记录socket的调试信息:
(前不久做过这个函数的测试,调式信息可以保存,包括socket建立时候的参数,采用的
具体协议,以及出错的代码都可以记录下来)
BOOL bDebug=TRUE;
setsockopt(s,SOL_SOCKET,SO_DEBUG,(const char*)&bDebug,sizeof(BOOL));

zhaizi
http://www.libing.net.cn/post/setsockopt.php

- 作者: chongsoft 2008年11月9日, 星期日 15:06  回复(0) |  引用(0) 加入博采

Anti-strace 技术 strace及相关内核的实现细节(转)

--[ 内容
    0 - 前言
    1 - strace的原理
    2 - strace死循环的分析
    3 - anti-strace
        3.1 方法一
        3.2 方法二
        3.3 方法三
    4 - anti anti-strace
        4.1 int3的情况
        4.2 kill的情况
    5 - 参考
    6 - strace.4.5.8.patch
--[ 0 - 前言
前面在介绍Burneye加密文档的时候,碰到了两个问题,一个是GDB中无法配置断点,另一个
问题是strace时死循环。GDB的问题已找到,无法配置断点是GDB的一个Bug,具体的结
论见[1].至于strace的问题,一直没有解决,假如真能写出一个让strace死循环的程式,
也算是一种anti-strace的技术。但是一直没有将死循环的现象用程式重现。
后来经Grip2的指点,发现了问题的原因,经过对内核和strace源代码的研究,写了一个
防止strace死循环的patch,之后更进一步的patch,使得strace更加健壮,能够跟踪anti-
strace程式的系统调用。
在这里感谢Grip2的帮助和测试程式。
本文的环境是Redhat Fedora Core 2, Linux 2.6.5/2.6.8.1,
            gcc 3.3.1, strace 4.5.8
--[ 1 - strace的原理
要想了解strace的原理,首先得谈谈ptrace。
ptrace是操作系统为了调试为用户程式提供的系统接口。先来看看ptrace的用法:[2]
       long  ptrace(enum __ptrace_request request, pid_t pid, void *addr, void
       *data)
strace需要使用的__ptrace_request主要有以下几个:
被调试的进程)
       PTRACE_TRACEME 自己主动提供被跟踪的请求,当被跟踪的进程收到信号时,会先被
                      父进程截获.同样,execve时也是如此.
监控进程strace)
       PTRACE_GETREGS 获得被跟踪进程的寄存器状况,周详的结构请参见asm/user.h的
                      user_regs_struct
       PTRACE_PEEKDATA 获得系统堆栈中的参数
       PTRACE_SYSCALL 这是最重要的,每次本跟踪的进程在系统调用时,ptrace会返回
                      两次,一次是系统调用之前,会调用PTRACE_PEEKDATA获得参数
                      值,另一次是系统调用之后,会调用PTRACE_GETREGS获得返回值
ENTRY(system_call)
...
                                        # system call tracing in operation
        testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
        jnz syscall_trace_entry
...
syscall_trace_entry:
        movl $-ENOSYS,EAX(%esp)
        movl %esp, %eax
        xorl %edx,%edx
        call do_syscall_trace    do_sigaction()
2298         if (signal_pending(current)) {
2299                 /*
2300                  * If there might be a fatal signal pending on multiple
2301                  * threads, make sure we take it before changing the action.
2302                  */
2303                 spin_unlock_irq(¤t->sighand->siglock);
2304                 return -ERESTARTNOINTR;
2305         }
也就是说当程式执行sys_signal时,假如有信号还未处理,就直接返回-ERESTARTNOINTR
接下来当系统调用返回时,会依次调用
resume_userspace->work_pending->work_notify_sig->do_notify_resume->do_sign
al
590  no_signal:
591         /* Did we come from a system call? */
592         if (regs->orig_eax >= 0) {
593                 /* Restart the system call - no handlers present */
594                 if (regs->eax == -ERESTARTNOHAND ||
595                     regs->eax == -ERESTARTSYS ||
596                     regs->eax == -ERESTARTNOINTR) {
597                         regs->eax = regs->orig_eax;
598                         regs->eip -= 2;
599                 }
600                 if (regs->eax == -ERESTART_RESTARTBLOCK){
601                         regs->eax = __NR_restart_syscall;
602                         regs->eip -= 2;
603                 }
604         }
605         return 0;
606 }
此时,  regs->eip -= 2;正好代表int $0x80 (0xcd 0x80)两个字节,可见,内核重启
系统调用。
那么,究竟什么时候signal_pending(current)为真呢?经过GDB调试,发现strace在处理
sys_signal系统调用时,syscall.c:trace_syscall会调用signal的sys_signal函数
        sys_res = (*sysent[tcp->scno].sys_func)(tcp)
signal.c::sys_signal()
...
#ifndef USE_PROCFS
                        if (tcp->u_arg[0] == SIGTRAP) {
                                tcp->flags |= TCB_SIGTRAPPED;
                                kill(tcp->pid, SIGSTOP);
                        }
#endif /* !USE_PROCFS */
死循环的问题就在这个kill(tcp->pid, SIGSTOP)上,当程式被处于跟踪的时刻,向已
停止的进程发送SIGSTOP本来是没有必要的,不知道strace的作者为什么还要单独来上这
么一句?Linux 2.4和2.6内核又出现了差异,在2.6内核的do_sigaction判断了是否有信
号pending,而2.4却没有,因此在2.4的机器上,运行strace不会出现死循环的情况,在
2.6上,我们只须将改行注释掉即可。
我们能够认为这是strace和2.6内核不兼容的一个Bug!
注意:假如您在程式里用的是C库的signal,实际上使用的是sys_rt_sigaction而不是
sys_signal,而strace在处理sys_rt_sigaction时,并没有kill(tcp->pid, SIGSTOP);
也许strace的作者认为用C写的程式不会用到sys_signal?
接下来让我们试一试新的strace来跟踪burneye加密的程式
#./strace /tmp/ls.new (ls.new是burneye加密的程式)
execve("/tmp/ls.new", ["/tmp/ls.new"], [/* 20 vars */]) = 0
signal(SIGTRAP, 0x5371991)              = 0 (SIG_DFL)
--- SIGSEGV (Segmentation fault) @ 0 (0) ---
+++ killed by SIGSEGV ++
OK,不死循环了,但是我们现在还无法继续跟踪,因为burneye加密的时候使用了某些anti-
strace的技术。
--[ 3 - anti-strace的原理
了解了strace的工作原理,就能够有针对的使用anti-strace的技术
--[ 3.1 方法一
利用上边介绍的strace和2.6内核的不兼容,造成死循环.对上边打过patch的strace不适用
测试程式(Grip2提供)
#include
#include
#include
#include
#include
#include
#include
void sig_handler(int sig)
{
        printf("signal trap\n");
        return;
}
static inline int my_signal(int num, void *func)
{
        int ret;
       
        __asm__ __volatile__ ( "int $0x80"
                                :"=a"(ret)
                                :"0" (48), "b" ((long)num),
                                "c" ((int)func));
        return ret;
       
}       
       
int main(int argc, char *argv[])
{
        my_signal(SIGTRAP, sig_handler);
        return 0;
}
注意一定不能使用C库的signal,原因在前边已提过
--[ 3.2 方法二
自己发送int3
这种方法是Silvio Cesare在[3]中介绍的方法,由程式自己执行int3,这样会产生一个
陷阱,内核会向程式发送一个SIGTRAP信号,由于程式被跟踪,因此信号由strace截获,
根据strace的源代码,if (ptrace(PTRACE_SYSCALL, pid, (char *) 1, 0)
#include
#include
#include
#include
#include
#include
static int not_trace
void sig_handler(int sig)
{
        not_trace++;
        return;
}
       
int main(int argc, char *argv[])
{
        signal(SIGTRAP, sig_handler);
        __asm__ __volatile__ ( "int3" );
        if(!not_trace){
                printf("TRACING...\n");
                exit(-1);
        }
        return 0;
}
--[ 3.3 方法三
程式使用kill向自己发送SIGTRAP,跟方法二类似,这里就不赘述了
        kill(getpid(), SIGTRAP);
--[ 4 - anti anti-strace
现在我们来进一步完善strace,让他也能对付方法二和方法三,其实问题的关键就是看
strace在ptrace退出之后,下次使用ptrace能不能将SIGTRAP信号返回给被跟踪程式。
根据ptrace的手册页对PTRACE_CONT和PTRACE_SYSCALL的描述
PTRACE_CONT ... If data is non-zero and not SIGSTOP, it is interpreted as a
             signal to be delivered to the child ...
PTRACE_SYSCALL ... Restarts the stopped child as for PTRACE_CONT
看来我们只须在下一次调用ptrace时指定返回的信号是SIGTRAP即可,但是不能胡乱发送,
只有在发现int3和kill(pid, SIGTRAP)的情况下才适用。
--[ 4.1 int3的情况
首先,我们需要判断int3的情况,因此,需要在strace.c::trace()最后添加以下几行
tracing:
                if(ptrace(PTRACE_GETREGS, pid, NULL, (int)®s) scno != __NR_sigreturn && tcp->scno != __NR_rt_sigreturn)
--[ 4.2 kill的情况
kill情况比较简单,只须在sys_kill调用的第二次ptrace返回时,将返回值设定为SIGTRAP
                if(tcp->scno == __NR_kill){
                        if(!(tcp->flags & TCB_INSYSCALL)){
                                tprintf("\n!! Self SIGTRAP !!\n");
                                if(ptrace(PTRACE_SYSCALL,
                                        pid,
                                        (char *)1,
                                        SIGTRAP)

附录:

strace使用及举例

(一) strace 命令
  
 
  strace: option requires an argument -- e
  usage: strace [-dffhiqrtttTvVxx] [-a column] [-e expr] ... [-o file]
   [-p pid] ... [-s strsize] [-u username] [-E var=val] ...
   [command [arg ...]]
   or: strace -c [-e expr] ... [-O overhead] [-S sortby] [-E var=val] ...
   [command [arg ...]]
  -c -- count time, calls, and errors for each syscall and report summary
  -f -- follow forks, -ff -- with output into separate files
  -F -- attempt to follow vforks, -h -- print help message
  -i -- print instruction pointer at time of syscall
  -q -- suppress messages about attaching, detaching, etc.
  -r -- print relative timestamp, -t -- absolute timestamp, -tt -- with usecs
  -T -- print time spent in each syscall, -V -- print version
  -v -- verbose mode: print unabbreviated argv, stat, termio[s], etc. args
  -x -- print non-ascii strings in hex, -xx -- print all strings in hex
  -a column -- alignment COLUMN for printing syscall results (default 40)
  -e expr -- a qualifying expression: option=[!]all or option=[!]val1[,val2]...
   options: trace, abbrev, verbose, raw, signal, read, or write
  -o file -- send trace output to FILE instead of stderr
  -O overhead -- set overhead for tracing syscalls to OVERHEAD usecs
  -p pid -- trace process with process id PID, may be repeated
  -s strsize -- limit length of print strings to STRSIZE chars (default 32)
  -S sortby -- sort syscall counts by: time, calls, name, nothing (default time)
  -u username -- run command as username handling setuid and/or setgid
  -E var=val -- put var=val in the environment for command
  -E var -- remove var from the environment for command
  
  
  strace - 跟踪系统调用和信号
  
  usage: strace [-dffhiqrtttTvVxx] [-a column] [-e expr] [-o file]
  [-p pid] [-s strsize] [-u username] [command [arg]]
  strace -c [-e expr] [-O overhead] [-S sortby] [command [arg]]
  
  -a column
   指定显示返回值的列位置,默认是40(从0开始计数),就是说"="出现在40列的位
   置。
  
  -c 产生类似下面的统计信息
  
   strace -c -p 14653 (Ctrl-C)
   % time seconds usecs/call calls errors syscall
   ------ ----------- ----------- --------- --------- ----------------
   53.99 0.012987 3247 4 2 wait4
   42.16 0.010140 2028 5 read
   1.78 0.000429 61 7 write
   0.76 0.000184 10 18 ioctl
   0.50 0.000121 2 52 rt_sigprocmask
   0.48 0.000115 58 2 fork
   0.18 0.000043 2 18 rt_sigaction
   0.06 0.000014 14 1 1 stat
   0.03 0.000008 4 2 sigreturn
   0.02 0.000006 2 3 time
   0.02 0.000006 3 2 1 setpgid
   ------ ----------- ----------- --------- --------- ----------------
   100.00 0.024053 114 4 total
  
   -d 输出一些strace自身的调试信息到标准输出
  
   strace -c -p 14653 -d (Ctrl-C)
   [wait(0x137f) = 14653]
   pid 14653 stopped, [SIGSTOP]
   [wait(0x57f) = 14653]
   pid 14653 stopped, [SIGTRAP]
   cleanup: looking at pid 14653
   % time seconds usecs/call calls errors syscall
   ------ ----------- ----------- --------- --------- ----------------
   ------ ----------- ----------- --------- --------- ----------------
   100.00 0.000000 0 total
  
   -e expr
   A qualifying expression which modifies which events to trace or how to trace
   them. The format of the expression is:
  
   [qualifier=][!]value1[,value2]...
  
   这里qualifier可以是trace、abbrev、verbose、raw、signal、read或者write。
   value是qualifier相关的符号或数值。缺省qualifier是trace。!表示取反。
   -eopen等价于-e trace=open,表示只跟踪open系统调用。-etrace=!open意思是
   跟踪除open系统调用之外的其他所有系统调用。此外value还可以取值all和none。
  
   某些shell用!表示重复历史指令,此时可能需要引号、转义符号(\)的帮助。
  
   -e trace=set
   只跟踪指定的系统调用列表。决定跟踪哪些系统调用时,-c选项很有用。
   trace=open,close,read,write意即只跟踪这四种系统调用,缺省是trace=all
  
   -e trace=file
   跟踪以指定文件名做参数的所有系统调用。
  
   -e trace=process
   Trace all system calls which involve process management. This is
   useful for watching the fork, wait, and exec steps of a process.
  
   -e trace=network
   跟踪所有和网络相关的系统调用
  
   -e trace=signal
   Trace all signal related system calls.
  
   -e trace=ipc
   Trace all IPC related system calls.
  
   -e abbrev=set
   Abbreviate the output from printing each member of large structures.
   缺省是abbrev=all,-v选项等价于abbrev=none
  
   -e verbose=set
   Dereference structures for the specified set of system calls.
   The default is verbose=all.
  
   -e raw=set
   Print raw, undecoded arguments for the specifed set of system calls.
   This option has the effect of causing all arguments to be printed in
   hexadecimal. This is mostly useful if you don"t trust the decoding or
   you need to know the actual numeric value of an argument.
  
   -e signal=set
   只跟踪指定的信号列表,缺省是signal=all。signal=!SIGIO (or signal=!io)
   导致 SIGIO 信号不被跟踪
  
   -e read=set
   Perform a full hexadecimal and ASCII dump of all the data read from
   file descriptors listed in the specified set. For example, to see all
   input activity on file descriptors 3 and 5 use -e read=3,5. Note that
   this is independent from the normal tracing of the read(2) system call
   which is controlled by the option -e trace=read.
  
   -e write=set
   Perform a full hexadecimal and ASCII dump of all the data written to
   file descriptors listed in the specified set. For example, to see all
   output activity on file descriptors 3 and 5 use -e write=3,5. Note
   that this is independent from the normal tracing of the write(2)
   system call which is controlled by the option -e trace=write.
  
   -f
   follow forks,跟随子进程?
  
   Trace child processes as they are created by currently traced
   processes as a result of the fork(2) system call. The new process
   is attached to as soon as its pid is known (through the return value
   of fork(2) in the parent process). This means that such children may
   run uncontrolled for a while (especially in the case of a vfork(2)),
   until the parent is scheduled again to complete its (v)fork(2)
   call. If the parent process decides to wait(2) for a child that is
   currently being traced, it is suspended until an appropriate child
   process either terminates or incurs a signal that would cause it to
   terminate (as determined from the child"s current signal disposition).
  
   意思应该是说跟踪某个进程时,如果发生fork()调用,则选择跟踪子进程
   可以参考gdb的set follow-fork-mode设置
  
   -F
   attempt to follow vforks
   (On SunOS 4.x, this is accomplished with some dynamic linking trickery.
   On Linux, it requires some kernel functionality not yet in the
   standard kernel.) Otherwise, vforks will not be followed even if -f
   has been given.
  
   类似-f选项
  
   -ff
   如果-o file选项有效指定,则跟踪过程中新产生的其他相关进程的信息分别写
   入file.pid,这里pid是各个进程号。
  
   -h
   显示帮助信息
  
   -i
   显示发生系统调用时的IP寄存器值
   strace -p 14653 -i
  
   -o filename
   指定保存strace输出信息的文件,默认使用标准错误输出stderr
  
   Use filename.pid if -ff is used. If the argument begins with `|" or
   with `!" then the rest of the argument is treated as a command and all
   output is piped to it. This is convenient for piping the debugging
   output to a program without affecting the redirections of executed
   programs.
  
   -O overhead
   Set the overhead for tracing system calls to overhead microseconds.
   This is useful for overriding the default heuristic for guessing how
   much time is spent in mere measuring when timing system calls using
   the -c option. The acuracy of the heuristic can be gauged by timing
   a given program run without tracing (using time(1)) and comparing
   the accumulated system call time to the total produced using -c.
  
   好象是用于确定哪些系统调用耗时多
  
   -p pid
  
   指定待跟踪的进程号,可以用Ctrl-C终止这种跟踪而被跟踪进程继续运行。可以
   指定多达32个-p参数同时进行跟踪。
  
   比如 strace -ff -o output -p 14653 -p 14117
  
   -q
   Suppress messages about attaching, detaching etc. This happens
   automatically when output is redirected to a file and the command is
   run directly instead of attaching.
  
   -r
   Print a relative timestamp upon entry to each system call. This
   records the time difference between the beginning of successive
   system calls.
  
   strace -p 14653 -i -r
  
   -s strsize
   指定字符串最大显示长度,默认32。但文件名总是显示完整。
   -S sortby
   Sort the output of the histogram printed by the -c option by the
   specified critereon. Legal values are time, calls, name, and nothing
   (default time).
  
   -t
   与-r选项类似,只不过-r采用相对时间戳,-t采用绝对时间戳(当前时钟)
  
   -tt
   与-t类似,绝对时间戳中包含微秒
  
   -ttt
   If given thrice, the time printed will include the microseconds and
   the leading portion will be printed as the number of seconds since
   the epoch.
  
   -T
   这个选项显示单个系统调用耗时
  
   -u username
   用指定用户的UID、GID以及辅助组身份运行待跟踪程序
  
   -v
   冗余显示模式
   Print unabbreviated versions of environment, stat, termios, etc. calls.
   These structures are very common in calls and so the default behavior
   displays a reasonable subset of structure members. Use this option to
   get all of the gory details.
  
   -V
   显示strace版本信息
  
   -x 以16进制字符串格式显示非ascii码,比如"\x08",默认采用8进制,比如"\10"
  
   -xx 以16进制字符串格式显示所有字节

===============================================

(二)应用
strace 命令是一种强大的工具,它能够显示所有由用户空间程序发出的系统调用。
  strace 显示这些调用的参数并返回符号形式的值。strace 从内核接收信息,而且不需要以任何特殊的方式来构建内核。
  下面记录几个常用 option .
  1 -f -F选项告诉strace同时跟踪fork和vfork出来的进程
  2 -o xxx.txt 输出到某个文件。
  3 -e execve 只记录 execve 这类系统调用
  -------------------------------------------------------------------------------------------------------------------------
  进程无法启动,软件运行速度突然变慢,程序的"SegmentFault"等等都是让每个Unix系统用户头痛的问题,
  本文通过三个实际案例演示如何使用truss、strace和ltrace这三个常用的调试工具来快速诊断软件的"疑难杂症"。
  
  
  truss和strace用来跟踪一个进程的系统调用或信号产生的情况,而 ltrace用来跟踪进程调用库函数的情况。truss是早期为System V R4开发的调试程序,包括Aix、FreeBSD在内的大部分Unix系统都自带了这个工具;
  而strace最初是为SunOS系统编写的,ltrace最早出现在GNU/DebianLinux中。
  这两个工具现在也已被移植到了大部分Unix系统中,大多数Linux发行版都自带了strace和ltrace,而FreeBSD也可通过Ports安装它们。
  
  你不仅可以从命令行调试一个新开始的程序,也可以把truss、strace或ltrace绑定到一个已有的PID上来调试一个正在运行的程序。三个调试工具的基本使用方法大体相同,下面仅介绍三者共有,而且是最常用的三个命令行参数:
  
  -f :除了跟踪当前进程外,还跟踪其子进程。
  -o file :将输出信息写到文件file中,而不是显示到标准错误输出(stderr)。
  -p pid :绑定到一个由pid对应的正在运行的进程。此参数常用来调试后台进程。
  
   使用上述三个参数基本上就可以完成大多数调试任务了,下面举几个命令行例子:
  truss -o ls.truss ls -al: 跟踪ls -al的运行,将输出信息写到文件/tmp/ls.truss中。
  strace -f -o vim.strace vim: 跟踪vim及其子进程的运行,将输出信息写到文件vim.strace。
  ltrace -p 234: 跟踪一个pid为234的已经在运行的进程。
  
   三个调试工具的输出结果格式也很相似,以strace为例:
  
  brk(0) = 0x8062aa8
  brk(0x8063000) = 0x8063000
  mmap2(NULL, 4096, PROT_READ, MAP_PRIVATE, 3, 0x92f) = 0x40016000
  
  每一行都是一条系统调用,等号左边是系统调用的函数名及其参数,右边是该调用的返回值。 truss、strace和ltrace的工作原理大同小异,都是使用ptrace系统调用跟踪调试运行中的进程,详细原理不在本文讨论范围内,有兴趣可以参考它们的源代码。
  举两个实例演示如何利用这三个调试工具诊断软件的"疑难杂症":
  
  案例一:运行clint出现Segment Fault错误
  
  操作系统:FreeBSD-5.2.1-release
  clint是一个C++静态源代码分析工具,通过Ports安装好之后,运行:
  
  # clint foo.cpp
  Segmentation fault (core dumped)
   在Unix系统中遇见"Segmentation Fault"就像在MS Windows中弹出"非法操作"对话框一样令人讨厌。OK,我们用truss给clint"把把脉":
  
  # truss -f -o clint.truss clint
  Segmentation fault (core dumped)
  # tail clint.truss
   739: read(0x6,0x806f000,0x1000) = 4096 (0x1000)
   739: fstat(6,0xbfbfe4d0) = 0 (0x0)
   739: fcntl(0x6,0x3,0x0) = 4 (0x4)
   739: fcntl(0x6,0x4,0x0) = 0 (0x0)
   739: close(6) = 0 (0x0)
   739: stat("/root/.clint/plugins",0xbfbfe680) ERR#2 'No such file or directory'
  SIGNAL 11
  SIGNAL 11
  Process stopped because of: 16
  process exit, rval = 139
  我们用truss跟踪clint的系统调用执行情况,并把结果输出到文件clint.truss,然后用tail查看最后几行。
  注意看clint执行的最后一条系统调用(倒数第五行):stat("/root/.clint/plugins",0xbfbfe680) ERR#2 'No such file or directory',问题就出在这里:clint找不到目录"/root/.clint/plugins",从而引发了段错误。怎样解决?很简单: mkdir -p /root/.clint/plugins,不过这次运行clint还是会"Segmentation Fault"9。继续用truss跟踪,发现clint还需要这个目录"/root/.clint/plugins/python",建好这个目录后 clint终于能够正常运行了。
  
  案例二:vim启动速度明显变慢
  
  操作系统:FreeBSD-5.2.1-release
  vim版本为6.2.154,从命令行运行vim后,要等待近半分钟才能进入编辑界面,而且没有任何错误输出。仔细检查了.vimrc和所有的vim脚本都没有错误配置,在网上也找不到类似问题的解决办法,难不成要hacking source code?没有必要,用truss就能找到问题所在:
  
  # truss -f -D -o vim.truss vim
  
  这里-D参数的作用是:在每行输出前加上相对时间戳,即每执行一条系统调用所耗费的时间。我们只要关注哪些系统调用耗费的时间比较长就可以了,用less仔细查看输出文件vim.truss,很快就找到了疑点:
  
  735: 0.000021511 socket(0x2,0x1,0x0) = 4 (0x4)
  735: 0.000014248 setsockopt(0x4,0x6,0x1,0xbfbfe3c8,0x4) = 0 (0x0)
  735: 0.000013688 setsockopt(0x4,0xffff,0x8,0xbfbfe2ec,0x4) = 0 (0x0)
  735: 0.000203657 connect(0x4,{ AF_INET 10.57.18.27:6000 },16) ERR#61 'Connection refused'
  735: 0.000017042 close(4) = 0 (0x0)
  735: 1.009366553 nanosleep(0xbfbfe468,0xbfbfe460) = 0 (0x0)
  735: 0.000019556 socket(0x2,0x1,0x0) = 4 (0x4)
  735: 0.000013409 setsockopt(0x4,0x6,0x1,0xbfbfe3c8,0x4) = 0 (0x0)
  735: 0.000013130 setsockopt(0x4,0xffff,0x8,0xbfbfe2ec,0x4) = 0 (0x0)
  735: 0.000272102 connect(0x4,{ AF_INET 10.57.18.27:6000 },16) ERR#61 'Connection refused'
  735: 0.000015924 close(4) = 0 (0x0)
  735: 1.009338338 nanosleep(0xbfbfe468,0xbfbfe460) = 0 (0x0)
  
  vim试图连接10.57.18.27这台主机的6000端口(第四行的connect()),连接失败后,睡眠一秒钟继续重试(第6行的 nanosleep())。以上片断循环出现了十几次,每次都要耗费一秒多钟的时间,这就是vim明显变慢的原因。可是,你肯定会纳闷:"vim怎么会无缘无故连接其它计算机的6000端口呢?"。问得好,那么请你回想一下6000是什么服务的端口?没错,就是X Server。看来vim是要把输出定向到一个远程X Server,那么Shell中肯定定义了DISPLAY变量,查看.cshrc,果然有这么一行:setenv DISPLAY ${REMOTEHOST}:0,把它注释掉,再重新登录,问题就解决了。
  
  
  案例三:用调试工具掌握软件的工作原理
  
  操作系统:Red Hat Linux 9.0
  用调试工具实时跟踪软件的运行情况不仅是诊断软件"疑难杂症"的有效的手段,也可帮助我们理清软件的"脉络",即快速掌握软件的运行流程和工作原理,不失为一种学习源代码的辅助方法。下面这个案例展现了如何使用strace通过跟踪别的软件来"触发灵感",从而解决软件开发中的难题的。
  大家都知道,在进程内打开一个文件,都有唯一一个文件描述符(fd:file descriptor)与这个文件对应。而本人在开发一个软件过程中遇到这样一个问题:
  已知一个fd,如何获取这个fd所对应文件的完整路径?不管是Linux、FreeBSD或是其它Unix系统都没有提供这样的API,怎么办呢?我们换个角度思考:Unix下有没有什么软件可以获取进程打开了哪些文件?如果你经验足够丰富,很容易想到lsof,使用它既可以知道进程打开了哪些文件,也可以了解一个文件被哪个进程打开。好,我们用一个小程序来试验一下lsof,看它是如何获取进程打开了哪些文件。lsof: 显示进程打开的文件。
  
  /* testlsof.c */
  #include #include #include #include #include
  int main(void)
  {
   open("/tmp/foo", O_CREAT|O_RDONLY); /* 打开文件/tmp/foo */
   sleep(1200); /* 睡眠1200秒,以便进行后续操作 */
   return 0;
  }
  
  将testlsof放入后台运行,其pid为3125。命令lsof -p 3125查看进程3125打开了哪些文件,我们用strace跟踪lsof的运行,输出结果保存在lsof.strace中:
  
  # gcc testlsof.c -o testlsof
  # ./testlsof &
  [1] 3125
  # strace -o lsof.strace lsof -p 3125
  
  我们以"/tmp/foo"为关键字搜索输出文件lsof.strace,结果只有一条:
  
  
  # grep '/tmp/foo' lsof.strace
  readlink("/proc/3125/fd/3", "/tmp/foo", 4096) = 8
  
  原来lsof巧妙的利用了/proc/nnnn/fd/目录(nnnn为pid):Linux内核会为每一个进程在/proc/建立一个以其pid为名的目录用来保存进程的相关信息,而其子目录fd保存的是该进程打开的所有文件的fd。目标离我们很近了。好,我们到/proc/3125/fd/看个究竟:
  
  # cd /proc/3125/fd/
  # ls -l
  total 0
  lrwx------ 1 root root 64 Nov 5 09:50 0 -> /dev/pts/0
  lrwx------ 1 root root 64 Nov 5 09:50 1 -> /dev/pts/0
  lrwx------ 1 root root 64 Nov 5 09:50 2 -> /dev/pts/0
  lr-x------ 1 root root 64 Nov 5 09:50 3 -> /tmp/foo
  # readlink /proc/3125/fd/3
  /tmp/foo
  
  答案已经很明显了:/proc/nnnn/fd/目录下的每一个fd文件都是符号链接,而此链接就指向被该进程打开的一个文件。我们只要用readlink()系统调用就可以获取某个fd对应的文件了,代码如下:
  
  
  #include #include #include #include #include #include
  int get_pathname_from_fd(int fd, char pathname[], int n)
  {
   char buf[1024];
   pid_t pid;
   bzero(buf, 1024);
   pid = getpid();
   snprintf(buf, 1024, "/proc/%i/fd/%i", pid, fd);
   return readlink(buf, pathname, n);
  }
  int main(void)
  {
   int fd;
   char pathname[4096];
   bzero(pathname, 4096);
   fd = open("/tmp/foo", O_CREAT|O_RDONLY);
   get_pathname_from_fd(fd, pathname, 4096);
   printf("fd=%d; pathname=%sn", fd, pathname);
   return 0;
  }
  
  出于安全方面的考虑,在FreeBSD 5 之后系统默认已经不再自动装载proc文件系统,因此,要想使用truss或strace跟踪程序,你必须手工装载proc文件系统:mount -t procfs proc /proc;或者在/etc/fstab中加上一行:
  
  proc /proc procfs rw 0 0

- 作者: chongsoft 2008年11月8日, 星期六 08:48  回复(0) |  引用(0) 加入博采

楼市该不该救
希望政府能关注实体经济,因为金融危机对实体经济的打击非常大.如果在国外,银行都倒闭了,或者出现巨额亏损,哪有什么能力去贷款? 即使有人想投资,供给非常有限,所以需求就会被极大的抑制.这必然会使资金的使用价格提高,反过来会抑制需求.等经济下行了,投资需求就非常小了.在国内,如何引进外资呢? 楼市股市外资肯定会大量的撤出,因为他们都担心而且也需要资金.所以深圳的楼市先降了,北京好一点点,但是因为国内以往紧缩的货币政策,外资的撤退使得开发商不能回笼资金.只好降价.如果楼市暴跌的话,资产的财富价格就会大规模的缩水,人们的经济预期就会更加悲观.谁会花钱买奢侈品呢? 谈何刺激内需呢? 还有,如果楼市暴跌的话, 开发商破产, 坏账会增大, 优质个人客户都成了次级客户, 那时资不抵债, 引发新的一轮的金融危机.对人们的心理预期也是个巨大的打击。谈GDP的增长, 意义不大. 我现在怀疑房地产行业的统计数据,很多人说影响不大, 看和谁比. 和老美比是不大,但是对国内来说也是导致经济下行的一个重要因素.因为房地产曾经是个暴利的行业,如今都关门破产了,对GDP只有负的贡献了,对国家财政收入也是个打击.所以应该救一救.

- 作者: chongsoft 2008年10月18日, 星期六 18:49  回复(0) |  引用(0) 加入博采

中国货币供给理论 M0-M2

M0、M1、M2是货币供应量的范畴。人们一般根据流动性的大小,将货币供应量划分不同的层次加以测量、分析和调控。实践中,各国对M。、M1、M2的定义不尽相同,但都是根据流动性的大小来划分的,M。的流动性最强,M1次之,M2的流动性最差。
我国现阶段也是将货币供应量划分为三个层次,其含义分别是:
M0:流通中现金,即在银行体系以外流通的现金;
M1:狭义货币供应量,即M。+企事业单位活期存款;
M2:广义货币供应量,即M1+企事业单位定期存款+居民储蓄存款。
在这三个层次中,M0与消费变动密切相关,是最活跃的货币;
M1反映居民和企业资金松紧变化,是经济周期波动的先行指标,流动性仅次于M0;
M2流动性偏弱,但反映的是社会总需求的变化和未来通货膨胀的压力状况,通常所说的货币供应量,主要指M2。

看一个例子

中国人民银行昨天公布的数据显示,2008年9月末,广义货币供应量(M2)余额为45.29万亿元,同比增长15.29%,比上月末低0.71个百分点。这是自今年6月份开始M2数据连续第四个月出现放缓,M2增速也创下2005年6月份以来的最低值。狭义货币供应量(M1)的降幅更大。截至9月末,M1余额为15.57万亿元,同比增长9.43%,比上月末低2.05个百分点。

  市场人士认为,上述数据显示经济存在进一步下滑的压力,下一步宏观政策预计将继续放松,除了继续降息降准备金率外,财税部门可能出台减税政策。

  ⊙本报记者 但有为

  兴业银行资金运营中心首席经济学家鲁政委认为,尽管从7月底开始,央行从紧力度在减弱,但M2增速还是在下降,这说明国内经济活跃程度在下降。

  中信证券首席宏观分析师诸建芳则认为,M2偏低,但是更加突出的是M1非常低。这说明经济活动正在收缩。原因可能主要有两个:一是担心经济下滑导致银行惜贷;二是企业对实体经济比较悲观,信贷需求放缓。

  而根据国家统计局10日公布的数据,三季度全国企业家信心指数大幅回落,其中房地产业的企业家信心指数跌幅最深。

  虽然9月当月人民币贷款增加3745亿元,同比多增910亿元。但诸建芳认为,去年央行对信贷实行严格的规模控制,年底控制的力度甚至更大,导致去年同期贷款基数很小,所以今年9月份新增贷款达到3745亿元也并不算多。

  谈及下一步的宏观政策走向,市场人士普遍认为,政策将进一步放松。

  近日召开的央行货币政策委员会会议指出,当前要根据国内外形势变化采取灵活审慎的宏观政策,适时适度把握调控的方向、力度和节奏,进一步加强货币政策与财政、产业、外贸、金融监管等政策的协调配合,加快经济结构调整和增长方式转变,着力扩大内需,促进国际收支趋于基本平衡。

  鲁政委认为,要防止经济继续下行,货币政策应进一步放松。他预计今年央行至少会再降一次息,存款准备金率会下调2-3次。此外,央行将会解冻一部分定向央票。他同时认为,由于目前对通胀压力不必担心,上述政策有实施的空间。

  根据目前多家机构发布的预测数据,市场普遍认为9月份CPI仍会进一步下降,同比增幅在4.5%-4.9%之间。

  光大证券首席宏观分析师潘向东认为,由于通胀压力在年底会继续减小,在货币政策方面,首先应该实施的是降息。存款准备金率也应该下调。在财政政策方面,他认为应该减税。

  本月8日,央行决定下调一年期人民币存贷款基准利率各0.27个百分点,同时10月15日起下调存款类金融机构人民币存款准备金率0.5个百分点。此前,央行已于9月15日下调人民币贷款基准利率,及部分中小金融机构的人民币存款准备金率。

- 作者: chongsoft 2008年10月15日, 星期三 10:58  回复(0) |  引用(0) 加入博采

学而时习之 -- 硬盘那点事儿 (转载)

110栏的比赛中,一直以来都是飞人鲍威尔的天下。鲍威尔的100的最好成绩达到了974,这也让他在110栏比赛中占尽先机。自从刘翔横空出世,鲍威尔就再也无缘110栏的金牌了,金牌都被刘翔收入囊中。可刘翔的100最好成绩才103,但为啥又能在110栏中战胜鲍威尔呢?原来,110栏拼的不仅仅是奔跑的速度,还有跨栏的技巧。

 同样,在硬盘的读写效率方面比拼的不仅仅是看谁转的快,还有寻道时间,还有内置缓存。


为了理解硬盘的工作原理,我们先来打开硬盘看看:

 hard disk1

那光洁如银镜的圆盘叫磁碟,它的表面就是存放数据的地方。那细如米粒的尖端上就装着读写数据的部件,叫磁头。一个磁碟的两面都可以记录数据,因此磁碟的正反面都会有一个读写磁头。而一个硬盘内可以安装多个磁碟,也就有多个磁头,磁碟和磁头都是好几层的。看看下面的解剖图就明白了:

 hard disk2

我们再来看看硬盘是如何读写数据的。

在还未给硬盘通电前,磁头总体靠在一个安全的飞机场。这个飞机场要么在磁碟的最内侧,要么在磁碟的最外侧。飞机场部分的表面是不存放数据的,仅用于磁头的起飞和着陆。

磁碟的大部分区域是用来记录数据的,这些区域由一圈一圈的磁道组成,每个磁道又被划分成若干扇区。而磁碟的层叠看起来就像一个圆柱,那些磁道就形成以一层包裹一层的柱面结构,就像大树的年轮一样。而硬盘管理存储空间的方式都是先按柱面来存,再把磁道换到下一个柱面,并非按一个个磁碟来走的。

早期的硬盘采用CHS坐标体系规划硬盘存储空间,内侧磁道和外侧磁道的扇区数都相同。即使外侧磁道比内侧磁道要长得多,但容量只能与内侧磁道相同。硬盘总存储容量实际受内侧磁道的记录密度所限制,这显然是一种浪费。当磁道密度达到第一次极限时,人类发明了LBA的坐标映射,允许外侧磁道划分出更多的扇区,大幅度提升了硬盘容量。

同样,当LBA模式的硬盘容量又抵达距离的极限时,人类又发明了垂直记录技术,这又将大幅提升硬盘容量。所谓垂直记录技术就是把本来在磁碟表面平放的磁记录单元,改成竖着放。就像一个接一个平躺着的人会占据很长的距离,但这些人站起来就可以靠拢,从而缩小占据的距离。因此,垂直记录技术就可以在同样长度的磁道上放置更多的磁记录单元,从而提升硬盘容量。

当硬盘加电时,磁碟便开始加速转动。磁头是按精巧的好空气动力学原理设计出来的战斗机,当它在磁头的表面滑行到一定的速度时就会飞起来,从而浮在磁碟的表面。相信没有哪种飞机能像硬盘磁头那样,以零点几微米的超低空状态保持高速飞行。这样的超低空可以保证磁头能有效地分辨细小的磁记录单元的信号变化。

硬盘最怕什么?震动!在硬盘高速运转时,震动可能导致超低空飞行的磁头碰到磁碟表面,从而划伤磁碟,产生坏道。因此,硬盘运行时绝对禁止震动。

硬盘的转速和磁碟记录密度与磁头读写的速度都成近似的正比关系。转速越快,磁头读取数据就越快;而记录密度越高,相同时间下磁头读取的数据就越多。因此,人们总喜欢购买转速高的硬盘或容量大的硬盘。但除了转速和记录密度之外,其他方面的因素对硬盘的读写效率更加总要。

当硬盘接到读写命令时,磁头首先需要移动到要读写数据的磁道上,这个过程称为寻道。寻道需要时间的,这取决于磁头当前磁道与目标磁道的距离。如果距离远,移动磁头的时间就长,寻道就慢;如果距离很近,移动磁头的时间就短,寻道就快。平均寻道时间是影响硬盘读写效率的最重要指标。

磁头找到需要读取的磁道后,要读取的数据块可能还没有转过来,这也需要等待。平均等待读取数据块的时间称为平均潜伏时间,一般是磁碟旋转周期的一半。由于现在的硬盘转速都很快,因此这个等待时间比起平均寻道时间来说要小得多。

整体读写效率是由硬盘的平均访问时间来衡量的,它是指从硬盘收到访问命令,到完成所有操作并返回最终结果所花费的时间。平均访问时间基本就等于平均寻道时间与平均潜伏时间之和。因为这两个时间指标都与硬盘的机械结构有关,其他电信号切换和指令时间比起机械上所花的时间来说基本可以忽略不计。

由此可见,影响硬盘读写效率的主要是平均寻道时间。如果一个文件在硬盘中扇区太分散,东一块西一段的,那么读取这个文件时,磁头就会嚓嚓嚓地乱跳。由于把大多数的时间都花在寻找不连续的磁道上,读取文件的效率也就大大降低了。同样,当我们的硬盘由于文件的平凡更迭,会自然形成许多不连续的文件和磁盘碎片。这时,系统的运行效率也就大大降低,根源也是寻道时间太多。

为了对硬盘运行原理有一个感性的认识,我们来看看一段录像:(Sorry, Blog is not supportted)



录像中,Copy & Paste 这种交替跨磁道的读写导致了磁头的剧烈振动,这不仅仅会导致读写效率的下降,还会制造噪音,并加速硬盘的损耗。而类似Format那种连续操作时,速度非常快,磁头也运行得很平稳和安静。

现代的硬盘都有内置缓存,这些缓存可提供一项重要的功能:预取。预读就是在硬盘读取完指定扇 区的数据之后、接到系统的下一条指令之前,磁头接着读取相邻的若干扇区的数据并存入缓存中。如果系统接下来所需的数据正好就是相邻扇区的数据,那么便可以 直接从缓存中读取而不用磁头再寻址,从而极大提高数据访问速度。

如果,我们定期对硬盘进行碎片整理,尽量保持文件的连续和有序,将对硬盘带来巨大好处。硬盘在读取这些连续数据时,磁头很少剧烈震动,磁盘运行很安静。因为连续有序的数据文件可以极大减少寻道时间,既能提高读取数据的速度,又可减少硬盘损耗,延长使用寿命。

此外,磁盘内置缓存的预读能力正好符合连续数据的读取。从寻道时间和缓存命中率两项指标来看,连续有序的数据可以极大提升电脑系统的运行效率。在实际生活中,一般的文件都会占用成千上万个扇区的空间,根据缓存预取的原理,如果硬盘中的文件完全没有磁盘碎片的话,那么预取的命中率就可以达到几乎100%,但因为有磁盘碎片,通常预取的命中率只在50%左右。

同样,在数据库应用系统中,我们也应该尽量保持数据存储的连续和有序。尽管数据库会有自己存放数据的格式,操作系统也存在自己的缓存机制。但这些上层的顺序结构和缓存机制,也会多多少少体现在硬盘的磁道和扇区的相邻性上。因为这些结构和机制也是基于硬盘的顺序结构和缓存机制来设计的。因此,在数据库的数据存储中尽量保证其物理连续性,将有助于提高数据库的查询效率。这也是为什么聚集索引要比其他索引快的原因,也是为什么精心设计的主键可以让索引的B树在硬盘上更连续的原因。

如果您读过薛定谔的那本著名的《生命是什么》,您将会明白生命的物理学意义就是让宇宙变得有序。让世界更有序是生命的天性,有智慧的程序员会让这种天性融入自己的程序中的。

预祝刘翔在2008奥运会上跑得更加有序!

原创:李战(leadzen) 2008-6-25
原文:http://www.cnblogs.com/leadzen/archive/2008/06/25/1229413.html

- 作者: chongsoft 2008年09月15日, 星期一 12:44  回复(0) |  引用(0) 加入博采

关于手机时钟的文章

手机中的时钟大致分为逻辑电路主时钟和实时时钟两大类。逻辑电路的主时钟通常有13M26M、和19.5M等;实时时钟一般为32.768KHz。无论是逻辑电路的主时钟还是实时时钟,均是手机正常工作的必要条件,由于手机各厂家设计思路和电路结构不同,主时钟和实时时钟电路若不正常时,反映出的故障现象也不尽相同。

 

一、时钟频率的产生

1 逻辑电路主时钟的产生
大多数GSM手机的主时钟是13MCDMA19.68M,小灵通19.2M);摩托罗拉手机多采用26M,三星手机A系列手机多采用19.5M,经分频后获得13M供逻辑电路。13M作为逻辑电路的主时钟(好比人按照北京时间安排作息),逻辑电路按时序进行有规律的工作。
手机中13M的频率是否准确,决定于AFC电压,AFC电压的产生,是基站根据手机传送的频率信息与网络系统高精度、高稳定的频率鉴相后,把信息传给手机,由CPU处理后产生直流电压,去控制13M的振荡频率,使手机中13M与基站保持严格同步。
13M
产生电路分为纯石英晶振和13M组件两种。石英晶体是与其他电路共同组成振荡产生13M13M组件电路只要加电即可产生13M频率。
在手机电路中,无论纯石英晶体或13M组件电路,均需要电源正常工作输出供电,13M电路才能产生13M输出。

 

2 实时时钟频率的产生

手机中的实时时钟频率基本上都是32.768KHz,是由32.768KHz晶体配合其他电路产生。为了维持手机中时间的连续性, 32.768KHz不能间断工作,关机或去下电池后,由备用电池供电工作(有的手机去下电池一段时间后,开机需再调整时间,是机内没有备用电池或备用电池需要更换)。

二、时钟频率的作用
1
、逻辑电路主时钟的作用
13M
作为逻辑电路的主时钟,是逻辑电路工作的必要条件。开机时需要有足够的幅度(9—15M范围内均可开机)。
开机后,13M作为射频电路的基准频率时钟,完成射频系统共用收发本振频率合成、PLL锁相以及倍频作为基准副载波用于I/Q调制解调。因此,信号对13M的频率要求精度较高(应在12.9999M13.0000M之间,±误差不超过150Hz),只有13M基准频率精确,才能保证收发本振的频率准确,使手机与基站保持正常的通讯,完成基本的收发功能。

2、实时时钟电路的作用

32.768KHz实时时钟的作用一般有两个,一是保持手机中时间的准确性,二是在待机状态下,作为逻辑电路的主时钟(目的是为了节电,待机时13M间隔工作的周期延长,基本处于休眠,逻辑电路主要由32.768KHz作为主时钟)。

由于各厂家设计思路不同,32.768KHz的具体作用也有所不同,如摩托罗拉手机中32.768KHz损坏,直接影响开机;诺基亚、三星、松下、西门子等手机中32.768KHz不正常影响开机和信号。

三、时钟电路的故障

1
、逻辑电路主时钟故障
众所周知,13M出现停振或振荡幅度过小,逻辑电路不工作造成不开机,大部分手机13M不正常的故障现象是开机电流很小(一般在10mA左右)。

逻辑电路正常工作的经典电流是50mA左右,当开机电流小于50mA时,重点检查逻辑电路正常工作的所必要条件电路,如电源、13M、复位、软件电路等。若开机后13M停振,会造成手机自动关机。

如果13M出现频偏较小,使收发本振和混频后的中频以及调制解调出的I/Q基带信号均产生偏离,形成信号时有时无;若13M偏离较大,造成无信号;如13M偏离太远,还会出现死机、定屏、开机困难、自动关机等故障。

检修13M是否正常,可用示波器或频率计测量,正常时示波器可测量到密集正弦波形成的亮带,调低示波器的频率可见到规律的正弦波;频率计可直接读到13M的具体频率数值(若停振什么也测不到)。一般情况下,13M停振或频偏,只要供电正常,多为晶振问题,更换即可。

2、实时时钟故障

32.768KHz不正常时,由于机型不同反映出的故障现象也不同,开机电流比13M主时钟不正常稍大(一般在20mA左右)。
如摩托罗拉手机中的32.768KHz与电源块构成振荡,是作为逻辑电路工作的一个前提条件,如果32.768KHz不工作,逻辑电路就不能工作出现不开机;诺基亚手机中的32.768KHz作为逻辑电路CPU数据传输的时钟,损坏后不开机,拆下后可以开机但无时间显示,若性能不良会引起信号时有时无(信号条逐渐消失);松下、西门子部分手机32.768KHz损坏可以开机,但无时间显示或时间不准;三星部分手机32.768KHz损坏不开机,拆下可以开机但无时间显示或开机后灯灭关机;还有部分手机如夏新A832.768KHz作为CPU