• 信号本质上就是一个软件中断,它既可以作为两个进程间的通信的方式, 更重要的是, 信号可以终止一个正常程序的执行, 通常被用于处理意外情况 ,* 信号是异步的, 也就是进程并不知道信号何时会到达
  • $kill -9 3390 #向PID为3390的进程发送编号为9的信号=>一个两个进程间通信的方式之一
 1) SIGHUP	 	2) SIGINT	 	3) SIGQUIT	 	4) SIGILL	 	5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
  • 一共62个,不是64个, 历史原因, 没有32,33
  • 1~31之间的信号叫做不可靠信号, 不支持排队, 信号可能会丢失, 也叫做非实时信号
  • 34~64之间的信号叫做可靠信号, 支持排队, 信号不会丢失, 也叫做实时信号

绝大多数信号的默认处理方式都是终止进程, 另外两种默认处理方式: 忽略处理, 自定义处理

1) SIGHUP 连接挂断 终止(默认处理)
2) SIGINT 终端中断,Ctrl+c产生该信号 终止(terminate)
3) SIGQUIT 终端退出,Ctrl+\ 终止+转储
4) SIGILL *进程试图执行非法指令 终止+转储
5) SIGTRAP 进入断点 终止+转储
6) SIGABRT *进程异常终止,abort()产生 终止+转储
7) SIGBUS 硬件或对齐错误 终止+转储
8) SIGFPE *浮点运算异常 终止+转储
9) SIGKILL 不可以被捕获或忽略的终止信号 终止
10) SIGUSR1 用户定义信号1 终止
11) SIGSEGV *无效的内存段访问=>Segmentation error 终止+转储
12) SIGUSR2 用户定义信号2 终止
13) SIGPIPE 向读端已关闭的管道写入 终止
14) SIGALRM 真实定时器到期,alarm()产生 终止
15) SIGTERM 可以被捕获或忽略的终止信号 终止
16) SIGSTKFLT 协处理器栈错误 终止
17) SIGCHLD 子进程已经停止, 对于管理子进程很有用 忽略
18) SIGCONT 继续执行暂停进程(用户一般不用) 忽略
19) SIGSTOP 不能被捕获或忽略的停止信号 停止(stop)
20) SIGTSTP 终端挂起,用户产生停止符(Ctrl+Z) 停止
21) SIGTTIN 后台进程读控制终端 停止
22) SIGTTOU 后台进程写控制终端 停止
23) SIGURG 紧急I/O未处理 忽略
24) SIGXCPU 进程资源超限 终止+转储
25) SIGXFSZ 文件资源超限 终止+转储
26) SIGVTALRM 虚拟定时器到期 终止
27) SIGPROF 实用定时器到期 终止
28) SIGWINCH 控制终端窗口大小改变 忽略
29) SIGIO 异步I/O事件 终止
30) SIGPWR 断电 终止
31) SIGSYS 进程试图执行无效系统调用 终止+转储

*系统对信号响应应视具体情况而定

发送信号的主要方式:

  1. 键盘 //只能发送部分特殊的信号 eg:Ctrl+C可以发送SIGINT
  2. 程序出错 //只能发送部分特殊的信号 eg: 出现段错误, 可以发送SIGSEGV
  3. $kill -Signal PID #能发所有信号
  4. 系统函数kill()/raise()/alarm()/sigqueue()

模型

kill()

//给任何进程或进程组发任何信号,成功返回0,失败返回-1设errno

#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);

pid

  • pid>0 //指定pid
  • pid=0 //GID是调用进程PID的子进程
  • pid=-1 //任何子进程
  • pid<-1 //GID是PID的子进程

sig

  • sig == 0 //不发任何信号,但错误检查还是会做,可以检查PID是否存在
#include<sys/types.h>
#include<signal.h>
void fa(int signo){
printf("catch signal number:%d\n",signo);
}
int main(){
pid_t pid=fork();
if(0==pid){

while(1);
}
if(0==kill(pid,0)){ //if child exists
printf("parent starts to raise signal\n");
if(-1==kill(pid,40)) //if fail to kill child
perror("kill"),exit(-1);
}
return 0;
}.

raise()

//给调用的线程或进程发信号,如果发送的信号被handler处理了,会在handler返回后再返回,成功返回0,失败返回非0
#include<signal.h>
int raise(int sig);
  • 在单线程程序中等价于 kill(getpid,sig)
  • 在多线程程序中等价于pthread_kill(pthread_self(), sig);
if(0!=raise(SIGINT))
perror("raise success"),exit(-1);
//raise.c
#include<unistd.h>
#include<signal.h>
#include<stdio.h>
#include<stdlib.h>
void fa(int signo){
printf("catch %d success\n",signo);
}
int main(){
//设置对SIGINT自定义处理
if(SIG_ERR==signal(SIGINT,fa))
perror("signal"),exit(-1); //5s后使用raise发送SIGINT
unsigned int second=sleep(5);
if(0==second)
printf("sleep well");
else
printf("sleep is interrupted, there are %ds left\n",second);
if(0!=raise(SIGINT))
perror("raise success"),exit(-1);
return 0;
}

alarm()

//seconds秒之后给调用进程发送SOGALRM信号,返回距离下次闹钟响起剩余的描述,没有闹钟返回0

#include <unistd.h>
unsigned int alarm(unsigned int seconds);

seconds=0表示不设置新的SIGALRM的同时取消之前的闹钟==>专门用来取消闹钟

//alarm.c
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
void fa(int signo){
printf("catch %d\n",signo);
alarm(1);
}
int main(){
// 设置对信号SIGALRM进行自定义处理;
if(SIG_ERR==signal(SIGALRM,fa))
perror("signal"),exit(-1);
// 设置5s发送SIGALRM;
unsigned int second=alarm(5);
printf("second=%u\n",second); //0
sleep(2);
//调整闹钟10s后响(发SIGALRM),second是3
second=alarm(10);
printf("second=%u\n",second); //3
//取消闹钟(不会发SIGALRM),second是3
// second=alarm(0);
// printf("second=%d\n",second); //10 while(1);
return 0;
}

sigqueue()

//将信号和数据排好发给指定进程,成功返回0,失败返回-1设errno

#include <signal.h>
int sigqueue(pid_t pid, int sig, const union sigval value);

pid //进程的编号(给谁发信号)

sig //信号值/信号的名称(发送什么样的信号)

value //联合类型的附加数据(伴随什么样的数据)

union sigval {
int sival_int;
void *sival_ptr;
};
void fa(int signo,siginfo_t* info,void* pv){
printf("进程%d发来的信号是:%d,附加数据是%d\n",info->si_pid,signo,info->si_value);
}
int main(){
//设置对信号40的自定义处理
struct sigaction action={};
action.sa_sigaction=fa;
action.sa_flags=SA_SIGINFO;
int res=sigaction(40,&action,NULL);
if(-1==res)
perror("sigaction"),exit(-1);
pid_t pid=fork();
if(-1==pid)
perror("fork"),exit(-1);
if(0==pid){ //child开始, 发送1~100之间的数据发给parent
printf("child%dstarts\n",getpid());
int i=1;
for(i=1;i<=100;i++){
union sigval value;
value.sival_int=i;
sigqueue(getppid(),40,value);//这里没有错误处理
}
exit(0);
}
while(1);
return 0;
}

sleep()

//让调用的线程睡seconds秒,除非这期间收到了不能忽略的信号,成功返回0,失败返回剩余没睡的时间

#include <unistd.h>
unsigned int sleep(unsigned int seconds);
unsigned int second=sleep(5);
if(0==second)
printf("sleep well");
else
printf("sleep is interrupted, there are %ds left\n",second);

pause()

//让调用的线程一直睡直到接收到了一个终止进程或者引发捕获信号函数的信号,当接受到这样的信号时,返回-1设errno

int pause(void);
void ding(int signo){
}
int main(){
(void) signal(SIGALRM, ding); //ding是一个函数
pause();
}

Q:pause 放在signal-catching很远的地方可以吗

A:pause就相当于sleep(∞), 跟捕捉语句没什么关系,谁说一定要组合用的

Q: 写了捕获语句, 是不是就使整个进程有了捕获某个信号的能力还是只是这一句???

A:当然不是, signal就像是全局变量, 使用sigaction()对某个信号进行重定向后, 此后的程序遇到这个信号就使用新的处理方式

signal()

//重新设置对信号的处理方式,将信号signum交给handler处理,成功返回之前的signal handler,失败返回-1设errno

#include <signal.h>
sighandler_t signal(int signum, sighandler_t handler);

handler

  • SIG_IGN(Signal ignore)
  • SIG_DFL(Signal default)
  • User-defined fhandler with argument signum
#include<signal.h>
void fa(int signo){
printf("catch signal:%d\n",signo);
if(SIG_ERR==signal(signo,SIG_DFL))
perror("signal"),exit(-1);
}
int main(){
if(SIG_ERR==signal(3,fa))
perror("signal"),exit(-1);
return 0;
}

信号集

信号的集合,当前系统所支持的信号范围:164(共62个),就是说每个进程可以使用信号164,为了对信号操作方便, 我们把一些信号放在一个集合中一起处理, 很多函数(包括sigpromask,sigpending)都是对信号集操作而不是对单个信号

sigset_t

Linux中表示信号集的数据类型, 就是一个超级大的整数(128byte, 32个unsigned long int的数组), 底层采用一个二进制位来代表一个信号, 根据该二进制位为0 or 1表示该信号是否存在

typedef struct{
unsigned long int __val[(1024 / (8 * sizeof (unsigned long int)))];
}__sigset_t;
typedef __sigset_t sigset_t;

在当前系统中, 按照%d打印的话就是打印信号集类型中的低4个字节的数据其实当前只需要8byte, 设计这么大是为了未来扩展

sigemptyset() /sigfillset()/sigaddset()/sigdelset()/sigismember()

//这些都是信号集操作函数
//sigemptyset()/sigfillset()/ sigaddset()/ sigdelset() 成功返回0,失败返回-1设errno
//如果signum是指定信号集的一员,sigismember()返回1,不是返回0,失败返回-1设errno。 #include <signal.h>
int sigemptyset(sigset_t *set); //清空信号集
int sigfillset(sigset_t *set); //填满信号集
int sigaddset(sigset_t *set, int signum); //添加信号到信号集
int sigdelset(sigset_t *set, int signum); //删除信号集的信号
int sigismember(const sigset_t *set, int signum); //判断信号是否属于信号集

sigprocmask()

//sigprocmask()只适用与单线程进程,多线程的参考pthread_sigmask()
//在某些特殊程序的执行过程中, 是不能被信号打断的, 此时需要信号的屏蔽技术来解决该问题
//获取并修改调用线程的屏蔽信号集
//成功返回0,失败返回-1设errno #include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

how

  • SIG_BLOCK //新的屏蔽信号集是原有集合(不是oldset,oldset是用来存储的)和set的合集
  • SIG_UNBLOCK //set内的信号被从屏蔽集合oldset中移除
  • SIG_SETMASK //屏蔽信号集就是setThe set of blocked signals is set to the argument set.

oldset

  • 如果oldset 不是NULL,则之前的信号集被存储在其中
  • 如果set是NULL,屏蔽信号集不会变量,但现存的屏蔽信号集还是会被存储在oldset中
//准备信号集中有:2,3
sigset_t set,oldset;
if(-1==sigemptyset(&set))
perror("sigemptyset"),exit(-1);
if(-1==sigemptyset(&oldset))
perror("sigemptyset"),exit(-1);
if(-1==sigaddset(&set,2))
perror("sigaddset"),exit(-1); //设置屏蔽的信号集
if(-1== sigprocmask(SIG_SETMASK,&set,&oldset))
perror("sigprocmask"),exit(-1);
  • 信号屏蔽并不是删除信号, 而是将信号单独保存起来, 等信号的屏蔽解除之后, 信号还是会被处理的
  • 可靠信号: 支持排队, mask期间有多少信号, mask解除之后就会处理多少
  • 不可靠信号:不支持排队, mask期间有多个信号时, mask解除之后只处理第一个

sigpending()

//检查mask期间捕捉到但是没有处理的信号, 通过形参带出结果,成功返回0,失败返回-1设errno

#include <signal.h>
int sigpending(sigset_t *set);

sigaction()

//是前面的信号处理的集大成者且有很多扩展,是一个非常健壮的signal处理接口,建议使用,成功返回0,失败返回-1设errno

#include <signal.h>
int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);

signum可以代表除了SIGSTOP和SIGKILL之外的任何一个信号

如果NULL!=act,act作为针对signal的新的action。

如果NULL!=oldact, 之前的action被存储在oldact。

act/oldact:

struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void); //obsolete, should not be used.
};

如果 sa_flags 被设为SA_SIGINFO,则sa_sigaction用来作signum的handler, 否则,用sa_handler

sa_handler表明针对signum的handler,和signal()第二个参数类型一致, 都是用于设置signal信号的处理方式SIG_DFL,SIG_IGN,user-defined handler

//sa_sigaction
struct siginfo_t {
int si_signo; /* Signal number */
int si_errno; /* An errno value */
int si_code; /* Signal code */
int si_trapno; /*Trap number that caused hardware-generated signal
pid_t si_pid; /* Sending process ID */ //发送信号的进程号
uid_t si_uid; /* Real user ID of sending process */
int si_status; /* Exit value or signal */
clock_t si_utime; /* User time consumed */
clock_t si_stime; /* System time consumed */
sigval_t si_value; /* Signal value */ //伴随信号到来的附加数据
int si_int; /* POSIX.1b signal */
void* si_ptr; /* POSIX.1b signal */
int si_overrun; /* Timer overrun count; POSIX.1b timers */
int si_timerid; /* Timer ID; POSIX.1b timers */
void* si_addr; /* Memory location which caused fault */
long si_band; /* Band event (was int in glibc 2.3.2 and earlier) */
int si_fd; /* File descriptor */
short si_addr_lsb; /* Least significant bit of address(since kernel 2.6.32) */
}

sa_mask 表明在信号handler执行期间需要屏蔽的信号,此外,出发handler的信号默认是被屏蔽的,除非flag里指定的SA_NODEFE

sa_flags(Bitwise Or)

  • SA_NOCLDSTOP //If signum is SIGCHLD, do not receive notification when child processes stop (i.e., when they receive one of SIGSTOP, SIGTSTP, SIGTTIN or SIGTTOU) or resume (i.e., they receive SIGCONT) (see wait(2)). This flag is only meaningful when establishing a handler for SIGCHLD.
  • SA_NOCLDWAIT //If signum is SIGCHLD, do not transform children into zombies when they terminate. See also waitpid(2). This flag is only meaningful when establishing a handler for SIGCHLD, or when setting that signal's disposition to SIG_DFL.If the SA_NOCLDWAIT flag is set when establishing a handler for SIGCHLD, POSIX.1 leaves it unspecified whether a SIGCHLD signal is generated when a child process terminates. On Linux, a SIGCHLD signal is generated in this case; on some other implementations, it is not.
  • SA_NODEFER //解除对触发信号处理函数相同信号的屏蔽
  • SA_ONSTACK //Call the signal handler on an alternate signal stack provided by sigaltstack(2). If an alternate stack is not available, the default stack will be used. This flag is only meaningful when establishing a signal handler.
  • SA_RESETHAND //一旦信号处理函数被调用之后, 信号的处理方式就会恢复为默认处理方式
  • SA_RESTART //Provide behavior compatible with BSD signal semantics by making certain system calls restartable across signals.This flag is only meaningful when establishing a signal handler. See signal(7) for a discussion of system call restarting.
  • SA_SIGINFO //使用第二个函数指针设置信号的处理方式
//sigaction.c
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<signal.h>
#include<sys/types.h>
void fa(int signo){
printf("fa1...\n");
sleep(3);
printf("fa2...\n");
}
int main(){
printf("current pid:%d\n",getpid());
//prepare struc var
struct sigaction action={};
action.sa_handler=fa;
sigemptyset(&action.sa_mask);
sigaddset(&action.sa_mask,3);
action.sa_flags=SA_NODEFER; //解除对信号2的屏蔽,sigaction(2....)
int res=sigaction(2,&action,NULL);
if(-1==res)
perror("sigaction"),exit(-1);
printf("set signal successfully\n");
while(1);
return 0;
}

sigaction()那点事:

  1. 使用sigaction(),需要明确两个act,一个用来存储老act的oldact,一个用来安装新act的act,
  2. 这两个act都是struct sigaction
  3. 结构体有两个函数分别指明对sig的处理方式,具体使用哪个需要看flag是否被set了SA_SIGINFO,set了,就是sa_sigaction()处理信号,没set,就是sa_handler,前者比后者的功能更多,后者其实就是signal()
  4. 指明了用哪个函数处理了信号,我们还可以指定在signal handler执行的过程中哪些SIG被mask,注意这个是sigset_t类型,把要mask的信号放在一个信号集里,默认条件下the signal which triggered the handler是被mask的,除非在sa_flags中set了SA_NODEFER;
  5. 可以看到,整个act中flags主要起到了配置的作用,它决定使用哪个handler(SA_SIGINFO),也决定要不要屏蔽触发信号(SA_NODEFER);
  6. 除了这两个,flags还有其他选项
void fa(int signo,siginfo_t* info,void* pv){
printf("进程%d发来了信号%d\n",info->si_pid,signo);
}
int main(){
struct sigaction action={};
action.sa_sigaction=fa;
action.sa_flags=SA_SIGINFO;
if(-1== sigaction(2,&action,NULL))
perror("sigaction"),exit(-1);
return 0;
}

父子进程信号

  1. 对于fork()创建的child, child完全照搬parent对信号的处理方式:

    • parent忽略=>child忽略;
    • parent默认=>child默认;
    • arent自定义=>child自定义;
  2. 对于vfork(),execl()启动的child, 部分照搬parent的信号处理方式:
    • parent忽略=>child忽略;
    • parent默认=>child默认;
    • parent自定义=>child默认=>因为execl()已经跳出的子进程, 而process.out里面没有fa,所以会按默认方式处理
#include<unistd.h>
#include<sys/types.h>
#include<signal.h>
#include<stdio.h>
#include<stdlib.h>
void fa(int signo){
printf("%d\n",signo);
}
int main(){
if(SIG_ERR==signal(2,fa))
perror("signal"),exit(-1);
if(SIG_ERR==signal(3,SIG_IGN))
perror("signal"),exit(-1);
pid_t pid=vfork();
if(-1==pid)
perror("vfork"),exit(-1);
if(0==pid){
printf("child's pid=%d\n",getpid());
int res=execl("process.out","process.out",NULL);
if(-1==res)
perror("execl"),exit(-1);
while(1);
}
return 0;
}

Linux信号的更多相关文章

  1. Linux信号类型说明

    说明 在Linux系统开发中经常要使用到信号来实现异步通知机制.而在Linux系统中信号有很多种,也不用全部记住,学习几种常见的信号,学会使用即可:当然也要知道用哪种方式能够发送这样的信号. 查看li ...

  2. Linux信号基础

    Linux信号基础   作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! Linux进程基础一文中已经提到,Linux以进程为单位来 ...

  3. Linux信号(signal) 机制分析

    Linux信号(signal) 机制分析 [摘要]本文分析了Linux内核对于信号的实现机制和应用层的相关处理.首先介绍了软中断信号的本质及信号的两种不同分类方法尤其是不可靠信号的原理.接着分析了内核 ...

  4. 利用linux信号机制调试段错误(Segment fault)

    在实际开发过程中,大家可能会遇到段错误的问题,虽然是个老问题,但是其带来的隐患是极大的,只要出现一次,程序立即崩溃中止.如果程序运行在PC中,segment fault的调试相对比较方便,因为可以通过 ...

  5. Linux信号实践(2) --信号分类

    信号分类 不可靠信号 Linux信号机制基本上是从UNIX系统中继承过来的.早期UNIX系统中的信号机制比较简单和原始,后来在实践中暴露出一些问题,它的主要问题是: 1.进程每次处理信号后,就将对信号 ...

  6. 非常好的一篇对linux信号(signal)的解析 (转载)【转】

    转自:https://blog.csdn.net/return_cc/article/details/78845346 Linux信号(signal) 机制分析 转载至:https://www.cnb ...

  7. Linux 信号:signal 与 sigaction

    0.Linux下查看支持的信号列表: france@Ubuntux64:~$ kill -l ) SIGHUP ) SIGINT ) SIGQUIT ) SIGILL ) SIGTRAP ) SIGA ...

  8. Linux信号机制

    Linux信号(signal) 机制分析 [摘要]本文分析了Linux内核对于信号的实现机制和应用层的相关处理.首先介绍了软中断信号的本质及信号的两种不同分类方法尤其是不可靠信号的原理.接着分析了内核 ...

  9. python学习笔记——多进程间通信——Linux信号基础

    1 信号的基本描述 Signal信号(其全程为软中断信号)是Linux系统编程中非常重要的概念,信号是异步进程中通信的一种方式. 作用是通知进程发生了异步事件.进程之间可以调用系统来传递信号, 本身内 ...

  10. linux信号Linux下Signal信号太详细了,终于找到了

    linux信号Linux下Signal信号太详细了,终于找到了 http://www.cppblog.com/sleepwom/archive/2010/12/27/137564.html

随机推荐

  1. GJM :自定义基于 VLC 的视频播放器 [转载]

    感谢您的阅读.喜欢的.有用的就请大哥大嫂们高抬贵手"推荐一下"吧!你的精神支持是博主强大的写作动力以及转载收藏动力.欢迎转载! 版权声明:本文原创发表于 [请点击连接前往] ,未经 ...

  2. Java中的GOF23(23中设计模式)--------- 单例模式(Singleton)

    Java中的GOF23(23中设计模式)--------- 单例模式(Singleton) 在Java这这门语言里面,它的优点在于它本身的可移植性上面,而要做到可移植的话,本身就需要一个中介作为翻译工 ...

  3. [AngularJS] 使用AngularCSS动态加载CSS

    [AngularJS] 使用AngularCSS动态加载CSS 前言 使用AngularAMD动态加载Controller 使用AngularAMD动态加载Service 上列两篇文章里,介绍了如何如 ...

  4. Play!中使用HTTP异步编程

    本章译者:@Sam Liu (译者未留下自己的主页,请Sam Liu见此文,加入群168013302联系‘大黄蜂@翻译play’) 这一章主要讲解如何运用异步模式实现典型的长连接(long-polli ...

  5. jquery多次上传同一张图片

    $().reset(); wrap():$('p').wrap('div');===><div><p></p></div>; .closest() ...

  6. 【CSS3】CSS3:border-image的详解和实例

    border-image简介 border-image是CSS3中的新特性.目前几乎所有的主流浏览器都已经支持该特性,详情请移步border-image的兼容性. border-image属性及使用说 ...

  7. 实例之HTML标签属性

    鼠标放在图片上会显示说明文字的代码 <img src="图片地址" width=620 height=138 border=0 title="说明文字" ...

  8. 苹果浏览器和uc浏览器在移动端的坑(日常积累,随时更新)

    先mark 1 .  移动端uc浏览器不兼容css3 calc() 2 .  ie8下a标签没有内容给宽高也不能触发点击跳转 3 . safari输入框加上readOnly="ture&qu ...

  9. 【初探HTML本相】道之真谛不过自然,html标签脱俗还真

    前言 须弥般若有无空,阴阳道化真虚同:洗尽前恩本非相,还吾面目下九重. 咳咳,其实老夫对佛教文化有点点研究啦,说以我们这里来了一点很有哲理的东西,因为我这里准备干一件很戳的事情,我准备来看看我们的ht ...

  10. SAP学习日志--RFC REMOTE FUNCTION CALL

    RFC  Remote function Call 远程功能调用, 是SAP系统之间以及非SAP系统之间程序通信的基本接口技术. 例如BAPI , ALE都是基于RFC实现的 SAP系统提供了三种外部 ...