公 告

欢迎各位网友添加友情链接,在您添加本博客:http://linux0818.blogspot.com/ 做为链接后, E-mail:linux0818@gmail.com给我,我将将您的网址添加到本博客。

2008年12月18日星期四

linux下正则表达式匹配使用(C语言)

regular_expression.c
/*----------------------------------------------------------------------------------*/
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <regex.h>

/* Function: int StringMatch(char *buf, char *pattern, int type)
* Return: if regular expression match,return 1, else return 0;
* Pass:
* buf: need compare string;
* patttern: regular expression;
* type: if type=1,is regular expression compare,else if type=0 is string and string compare.
*/
int StringMatch(char *buf, char *pattern, int type)
{
int errcode;

regex_t pregex; /* regex */


if (buf == NULL pattern == NULL) {
return 0;
}
printf("\tStringMatch: type %d\n", type);
if (0 == type) {
if (!strcasecmp(buf, pattern)) {
return 1;
}
} else if (1 == type) {
regmatch_t regoff;
if (0 != (errcode = regcomp(&pregex, (const char *) pattern, REG_EXTENDED REG_ICASE))) {
char errbuf[256];
regerror(errcode, &pregex, errbuf, sizeof(errbuf));
printf("\tStringMatch: Invalid regular expression '%s', '%s'\n",
pattern, errbuf);
regfree(&pregex);
return 0;
}
if (!regexec(&pregex, buf, 1, &regoff, 0)) {
printf("\tStringMatch: found string: %s\n", buf);
regfree(&pregex);
return 1;
} else {
printf("\tStringMatch: cannot find string: %s\n", buf);
}
regfree(&pregex);
}

return 0;
}

int main(int argc, char **argv)
{
char *pattern = "xiong([0-9]+)";
char *str[5] = { "xiongabcd", "xiong1234", "fxiong12", "abcdef", "xiong()()" };
int i = 0;
int ret = 0;
printf("---------------------------------------------------\n");
printf("Regular Expression:%s\n",pattern);
printf("---------------------------------------------------\n");
printf("\t\n");
for (i = 0; i < 5; i++) {
printf("\t-------------------------------------------\n");
ret = StringMatch(str[i], pattern, 1);
printf("\tret:%d\n", ret);
}
printf("---------------------------------------------------\n");
return 0;
}
/*----------------------------------------------------------------------------------*/

编译后运行:gcc regular_expression.c; ./a.out
运行结果:
---------------------------------------------------
Regular Expression:xiong([0-9]+)
---------------------------------------------------

-------------------------------------------
StringMatch: type 1
StringMatch: cannot find string: xiongabcd
ret:0
-------------------------------------------
StringMatch: type 1
StringMatch: found string: xiong1234
ret:1
-------------------------------------------
StringMatch: type 1
StringMatch: found string: fxiong12
ret:1
-------------------------------------------
StringMatch: type 1
StringMatch: cannot find string: abcdef
ret:0
-------------------------------------------
StringMatch: type 1
StringMatch: cannot find string: xiong()()
ret:0
---------------------------------------------------

补充:

GNU C 的规则表达式功能,

发现使用起来也很简单,只是觉得支持的不够强大,不能够进行文本的替换,只能进行文本的查找,至少目前我是

没有发现基规则表达式的

文本替换功能。

下面我就简单的介绍一下GNU C 的规则表达式使用方法,有理解不对的地方,还请朋友们多指正。

GNU C 中要使用规则表达式,需要用到以下几个函数。(定义在/usr/include/regex.h文件中)

* int regcomp (regex_t *compiled, const char *pattern, int cflags)

* int regexec (regex_t *compiled, char *string, size_t nmatch, regmatch_t matchptr [], int

eflags)

* void regfree (regex_t *compiled)

* size_t regerror (int errcode, regex_t *compiled, char *buffer, size_t length)

下面我就介绍分别一下这几个函数和它用到的一些数据类型。

1.int regcomp (regex_t *compiled, const char *pattern, int cflags)

这个函数把指定的规则表达式pattern编译成一种特定的数据格式compiled,这样可以使匹配更有效。函数

regexec 会使用这个数据在目标文

本串中进行模式匹配。执行成功返回0。

regex_t 是一个结构体数据类型,用来存放编译的规则表达式,它的成员re_nsub 用来存储规则表达式中的子

规则表达式的个数,子规则表

达式就是用圆括号包起来的部分表达式。

pattern 是指向我们写好的规则表达式的指针。

cflags 有如下4个值或者是它们或运算()的值:

REG_EXTENDED 以功能更加强大的扩展规则表达式的方式进行匹配。

REG_ICASE 匹配字母时忽略大小写。

REG_NOSUB 不用存储匹配的结果。

REG_NEWLINE 识别换行符,这样'$'就可以从行尾开始匹配,'^'就可以从行的开头开始匹配。

2. int regexec (regex_t *compiled, char *string, size_t nmatch, regmatch_t matchptr [], int

eflags)

当我们编译好规则表达式,就可以用regexec 匹配我们的目标文本串了,如果在编译规则表达式的时候没有指

cflags的参数为

REG_NEWLINE,则默认情况下是忽略换行符的,也就是把整个文本串当作一个字符串处理。执行成功返回0。

regmatch_t 是一个结构体数据类型,成员rm_so 存放匹配文本串在目标串中的开始位置,rm_eo 存放结束位

置。通常我们以数组的形式定义

一组这样的结构。因为往往我们的规则表达式中还包含子规则表达式。数组0单元存放主规则表达式位置,边的

单元依次存放子规则表达式位

置。

compiled 是已经用regcomp函数编译好的规则表达式。

string 是目标文本串。

nmatch regmatch_t结构体数组的长度。

matchptr regmatch_t类型的结构体数组,存放匹配文本串的位置信息。

eflags 有两个值

REG_NOTBOL 按我的理解是如果指定了这个值,那'^'就不会从我们的目标串开始匹配。总之我到现在还不是很

明白这个参数的意义,

原文如下:

If this bit is set, then the beginning-of-line operator doesn't match the beginning of the

string (presumably

because it's not the beginning of a line).If not set, then the beginning-of-line operator

does match the beginning

of the string.

REG_NOTEOL 和上边那个作用差不多,不过这个指定结束end of line

3. void regfree (regex_t *compiled)

当我们使用完编译好的规则表达式,或者要重新编译其它规则表达式的时候,我们可以用这个函数清空

compiled指向的regex_t结构体的内

容,请记住,如果是重新编译的话,一定要先清空regex_t结构体。

4. size_t regerror (int errcode, regex_t *compiled, char *buffer, size_t length)

当执行regcomp 或者regexec 产生错误的时候,就可以调用这个函数而返回一个包含错误信息的字符串。

errcode 是由regcomp regexec 函数返回的错误代号。

compiled 是已经用regcomp函数编译好的规则表达式,这个值可以为NULL

buffer 指向用来存放错误信息的字符串的内存空间。

length 指明buffer的长度,如果这个错误信息的长度大这个值,则regerror 函数会自动截断超出的字符串,

但他仍然会返回完整的字符

串的长度。所以我们可以用如下的方法先得到错误字符串的长度。

size_t length = regerror (errcode, compiled, NULL, 0);






--
/**************************************/
Name: Xiong Feng
E-mail: linux0818@gmail.com
MSN: linux0818@hotmail.com
QQ:23562033
Address: GuangZhou.China
/**************************************/

2008年12月16日星期二

HTTP 头部解释

1. Accept:告诉WEB服务器自己接受什么介质类型,*/* 表示任何类型,type/* 表示该类型下的所有子类型,type/sub-type。

2. Accept-Charset: 浏览器申明自己接收的字符集
Accept-Encoding: 浏览器申明自己接收的编码方法,通常指定压缩方法,是否支持压缩,支持什么压缩方法(gzip,deflate)
Accept-Language::浏览器申明自己接收的语言
语言跟字符集的区别:中文是语言,中文有多种字符集,比如big5,gb2312,gbk等等。

3. Accept-Ranges:WEB服务器表明自己是否接受获取其某个实体的一部分(比如文件的一部分)的请求。
bytes:表示接受,none:表示不接受。

4. Age:当代理服务器用自己缓存的实体去响应请求时,用该头部表明该实体从产生到现在经过多长时间了。

5. Authorization:当客户端接收到来自WEB服务器的 WWW-Authenticate 响应时,用该头部来回应自己的身份验证信息给WEB服务器。

6. Cache-Control:请求:no-cache(不要缓存的实体,要求现在从WEB服务器去取)
max-age:(只接受 Age 值小于 max-age 值,并且没有过期的对象)
max-stale:(可以接受过去的对象,但是过期时间必须小于 max-stale 值)
min-fresh:(接受其新鲜生命期大于其当前 Age 跟 min-fresh 值之和的缓存对象)
响应:public(可以用 Cached 内容回应任何用户)
private(只能用缓存内容回应先前请求该内容的那个用户)
no-cache(可以缓存,但是只有在跟WEB服务器验证了其有效后,才能返回给客户端)
max-age:(本响应包含的对象的过期时间)
ALL: no-store(不允许缓存)

7. Connection:请求:close(告诉WEB服务器或者代理服务器,在完成本次请求的响应后,断开连接,不要等待本次连接的后续请求了)。
keepalive(告诉WEB服务器或者代理服务器,在完成本次请求的响应后,保持连接,等待本次连接的后续请求)。
响应:close(连接已经关闭)。
keepalive(连接保持着,在等待本次连接的后续请求)。
Keep-Alive:如果浏览器请求保持连接,则该头部表明希望 WEB 服务器保持连接多长时间(秒)。
例如:Keep-Alive:300

8. Content-Encoding:WEB服务器表明自己使用了什么压缩方法(gzip,deflate)压缩响应中的对象。
例如:Content-Encoding:gzip
Content-Language:WEB 服务器告诉浏览器自己响应的对象的语言。

Content-Length: WEB 服务器告诉浏览器自己响应的对象的长度。
例如:Content-Length: 26012
Content-Range: WEB 服务器表明该响应包含的部分对象为整个对象的哪个部分。
例如:Content-Range: bytes 21010-47021/47022
Content-Type: WEB 服务器告诉浏览器自己响应的对象的类型。
例如:Content-Type:application/xml

9. ETag:就是一个对象(比如URL)的标志值,就一个对象而言,比如一个 html 文件,如果被修改了,其 Etag 也会别修改,
所以,ETag 的作用跟 Last-Modified 的作用差不多,主要供 WEB 服务器判断一个对象是否改变了。
比如前一次请求某个 html 文件时,获得了其 ETag,当这次又请求这个文件时,浏览器就会把先前获得的 ETag 值发送给
WEB 服务器,然后 WEB 服务器会把这个 ETag 跟该文件的当前 ETag 进行对比,然后就知道这个文件有没有改变了。


10. Expired:WEB服务器表明该实体将在什么时候过期,对于过期了的对象,只有在跟WEB服务器验证了其有效性后,才能用来响应客户请求。
是 HTTP/1.0 的头部。
例如:Expires:Sat, 23 May 2009 10:02:12 GMT

11. Host:客户端指定自己想访问的WEB服务器的域名/IP 地址和端口号。
例如:Host:rss.sina.com.cn

12. If-Match:如果对象的 ETag 没有改变,其实也就意味著对象没有改变,才执行请求的动作。
If-None-Match:如果对象的 ETag 改变了,其实也就意味著对象也改变了,才执行请求的动作。

13. If-Modified-Since:如果请求的对象在该头部指定的时间之后修改了,才执行请求的动作(比如返回对象),否则返回代码304,告诉浏览器该对象没有修改。
例如:If-Modified-Since:Thu, 10 Apr 2008 09:14:42 GMT
If-Unmodified-Since:如果请求的对象在该头部指定的时间之后没修改过,才执行请求的动作(比如返回对象)。

14. If-Range:浏览器告诉 WEB 服务器,如果我请求的对象没有改变,就把我缺少的部分给我,如果对象改变了,就把整个对象给我。
浏览器通过发送请求对象的 ETag 或者 自己所知道的最后修改时间给 WEB 服务器,让其判断对象是否改变了。
总是跟 Range 头部一起使用。

15. Last-Modified:WEB 服务器认为对象的最后修改时间,比如文件的最后修改时间,动态页面的最后产生时间等等。
例如:Last-Modified:Tue, 06 May 2008 02:42:43 GMT

16. Location:WEB 服务器告诉浏览器,试图访问的对象已经被移到别的位置了,到该头部指定的位置去取。
例如:Location:http://i0.sinaimg.cn/dy/deco/2008/0528/sinahome_0803_ws_005_text_0.gif

17. Pramga:主要使用 Pramga: no-cache,相当于 Cache-Control: no-cache。
例如:Pragma:no-cache

18. Proxy-Authenticate: 代理服务器响应浏览器,要求其提供代理身份验证信息。
Proxy-Authorization:浏览器响应代理服务器的身份验证请求,提供自己的身份信息。

19. Range:浏览器(比如 Flashget 多线程下载时)告诉 WEB 服务器自己想取对象的哪部分。
例如:Range: bytes=1173546-

20. Referer:浏览器向 WEB 服务器表明自己是从哪个 网页/URL 获得/点击 当前请求中的网址/URL。
例如:Referer:http://www.sina.com/

21. Server: WEB 服务器表明自己是什么软件及版本等信息。
例如:Server:Apache/2.0.61 (Unix)

22. User-Agent: 浏览器表明自己的身份(是哪种浏览器)。
例如:User-Agent:Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.8.1.14) Gecko/20080404 Firefox/2.0.0.14

23. Transfer-Encoding: WEB 服务器表明自己对本响应消息体(不是消息体里面的对象)作了怎样的编码,比如是否分块(chunked)。
例如:Transfer-Encoding: chunked

24. Vary: WEB服务器用该头部的内容告诉 Cache 服务器,在什么条件下才能用本响应所返回的对象响应后续的请求。
假如源WEB服务器在接到第一个请求消息时,其响应消息的头部为:Content-Encoding: gzip; Vary: Content-Encoding
那么 Cache 服务器会分析后续请求消息的头部,检查其 Accept-Encoding,是否跟先前响应的 Vary 头部值一致,即是否使用
相同的内容编码方法,这样就可以防止 Cache 服务器用自己 Cache 里面压缩后的实体响应给不具备解压能力的浏览器。
例如:Vary:Accept-Encoding

25. Via: 列出从客户端到 OCS 或者相反方向的响应经过了哪些代理服务器,他们用什么协议(和版本)发送的请求。
当客户端请求到达第一个代理服务器时,该服务器会在自己发出的请求里面添加 Via 头部,并填上自己的相关信息,当下一个代理服务器
收到第一个代理服务器的请求时,会在自己发出的请求里面复制前一个代理服务器的请求的Via 头部,并把自己的相关信息加到后面,
以此类推,当 OCS 收到最后一个代理服务器的请求时,检查 Via 头部,就知道该请求所经过的路由。
例如:Via:1.0 236-81.D07071953.sina.com.cn:80 (squid/2.6.STABLE13)

============================================================================================================================
HTTP 请求消息头部实例:
Host:rss.sina.com.cn
User-Agent:Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.8.1.14) Gecko/20080404 Firefox/2.0.0.14
Accept:text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language:zh-cn,zh;q=0.5
Accept-Encoding:gzip,deflate
Accept-Charset:gb2312,utf-8;q=0.7,*;q=0.7
Keep-Alive:300
Connection:keep-alive
Cookie:userId=C5bYpXrimdmsiQmsBPnE1Vn8ZQmdWSm3WRlEB3vRwTnRtW &lt;-- Cookie
If-Modified-Since:Sun, 01 Jun 2008 12:05:30 GMT
Cache-Control:max-age=0

HTTP 响应消息头部实例:
Status:OK - 200 &lt;-- 响应状态码,表示 web 服务器处理的结果。
Date:Sun, 01 Jun 2008 12:35:47 GMT
Server:Apache/2.0.61 (Unix)
Last-Modified:Sun, 01 Jun 2008 12:35:30 GMT
Accept-Ranges:bytes
Content-Length:18616
Cache-Control:max-age=120
Expires:Sun, 01 Jun 2008 12:37:47 GMT
Content-Type:application/xml
Age:2
X-Cache:HIT from 236-41.D07071951.sina.com.cn &lt;-- 反向代理服务器使用的 HTTP 头部
Via:1.0 236-41.D07071951.sina.com.cn:80 (squid/2.6.STABLE13)
Connection:close

--
/**************************************/
Name: Xiong Feng
E-mail:linux0818@gmail.com
MSN:linux0818@hotmail.com
QQ:23562033
Address: GuangZhou.China
/**************************************/

关于fatal致命错误的处理

在平时我们写一些小的例子程序,可能对一些程序的退出并没有做出一些更好的做法,一般就是使用

exit(-1)或return 等方法退出。但是,在一个产品的开发过程中,特别是长时间不重启工作的产品,我

们还使用这种方法就有点不负"责任"了。

fatal在计算机中我们理解为"致命的",也就是说出现一些致命的错误时,我们得处理好善后工作后才

能退出。不然对有些没有MMU且不经常断电重启的嵌入式产品来说,会使你的内存不断的耗尽。当然,对

一些服务器也会有不同的情况发生。

今天在看到squid2.6的源代码时,发现里面就有这么一个好的方法,这也是开源产品及大型产品中经常用

到的,现在贴出来研究一下:


--------------------------------------------------------------------------------
void fatal(const char *message)
{
    releaseServerSockets();
    /* check for store_dirs_rebuilding because fatal() is often
     * used in early initialization phases, long before we ever
     * get to the store log. */
    if (0 == store_dirs_rebuilding)
        storeDirWriteCleanLogs(0);
        fatal_common(message);
    if (shutting_down)
        exit(1);
    else
        abort();
}
--------------------------------------------------------------------------------


该函数就对系统在发生异常时调用此函数对相应的资源释放以后才退出,这样明显对系统的资源就进行了

一个很好的管理了。能做到有申请,就有释放。

当然,我在网上也找了两个实例,一起贴出来,供网友及我以后参考:

example 1:
--------------------------------------------------------------------------------
#include   <stdio.h>
#include   <stdlib.h>
#include   <string.h>
#include   <stdarg.h>
 
void fatal(char *fmt, ...)
{
    va_list v;
    va_start(v, fmt);
    vprintf(fmt, v);
    va_end(v);
    exit(0);
}
 
int main(int argc, char *argv[])
{
    fatal("This   is   a   fatal.%d\n", 78);
    return 0;
}
--------------------------------------------------------------------------------

example 2:
--------------------------------------------------------------------------------
#include   <stdio.h>
#include   <stdlib.h>
#include   <string.h>
#include   <stdarg.h>
int fatal(char *s)
{
    perror(s);
    exit(1);
}
 
int main(int argc, char *argv[])
{
    fatal("Fatal Error:\n");
    return 0;
}
--------------------------------------------------------------------------------


--
/**************************************/
Name: Xiong Feng
E-mail:linux0818@gmail.com
MSN:linux0818@hotmail.com
QQ:23562033
Address: GuangZhou.China
/**************************************/

C语言中fflush等函数的使用

在有些时候,你会发现你的输出并没有按照你代码的流程输出, 比如说当你用C语言写了做了一个写文件的函数并印出一些信息,供perl或php等调用.而这时你会发现, perl或php并没有获取到你C语言中的打印信息.而代码什么都没有错误,在linux终端也可以正确打印出来. 这时可真是郁闷吧. 那么, 记住了, 这很大可能是没有更新你的缓冲区了. 这时int  fflush(FILE *stream)这个函数就有用了. 下面看看这个函数的信息:
fflush
【功能】清空某个流。
【原型】int fflush(FILE *fp)
【位置】stdio.h
【说明】如果出现任何错误则返回 EOF。
【参见】flushall,fclose
 
下面还是用例子来说明吧:
文件名: fflush.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int writefile(char *filename, char *buf, int length)
{
   FILE *fp;
   int j = 0;
   size_t i = 0;
   fp = fopen(filename, "w");
   if (fp == NULL) {
       printf("\topen file error!\n");
       return -1;
   } else {
       while (length != 0) {
           i = fwrite(&buf[j], 1, 1, fp);
           length--;
           j ;
       }
   }
   fflush(fp);
   fclose(fp);
   return 0;
}
int readfile(char *filename, char *buf)
{
   FILE *fp;
   int j = 0;
   size_t i;
   fp = fopen(filename, "rb");
   if (fp == NULL) {
       printf("error\n");
       return -1;
   } else {
       while (1) {
           i = fread(&buf[j], 1, 1, fp);
           if (i == 0)
               break;
           j ;
       }
   }
   fflush(fp);
   fclose(fp);
   return 111;
}
int main(int argc, char **argv)
{
   char msg[128] = "hello,xiong feng!";
   char fbuf[1024] = "";
   char *filename = "/xiongfeng";
   int w_ret = 0;
   int r_ret = 0;
   w_ret = writefile(filename, msg, strlen(msg));
   if (w_ret < 0) {
       printf("Write file %s fail!\n", filename);
   }
   printf("msg:%s\n", msg);    // 如果在未加入fflush(fp), 该输出有可能不能正常输出,特别是在perl调用该程序时, perl不能获取该程序中的输出
   r_ret = readfile(filename, fbuf);
   if (r_ret < 0) {
       printf("Read file %s fail!\n", filename);
   }
   printf("fbuf:%s\n", fbuf);   // 这行同上面的: printf("msg:%s\n", msg);    
   return 0;
}
--------------------------------end-----------------------------------
我在网上还找了一些个封装了一次fflush的函数, 如下:
void flush(FILE *stream)
{
    int duphandle;
    /* flush the stream's internal buffer */
    fflush(stream);
    /* make a duplicate file handle */
    duphandle = dup(fileno(stream));
    /* close the duplicate handle to flush/
       the DOS buffer */
    close(duphandle);
}
用此函数来替代fflush也行,但我感觉在这时, 调用dup(), fileno()等函数没什么用.
下面是这两个函数的分析:
dup():
int   dup(int   handle);  
作用:复制一个文件句柄
--------------------------------end-----------------------------------
fileno():
范例:
fileno.c:
#include <stdio.h>
int main(int argc, char **argv)
{
   FILE *fp;
   int fd;
   fp = fopen("/xiongfeng", "r");
   fd = fileno(fp);
   printf("fd = %d\n", fd);
   fclose(fp);
   return 0;
}
运行结果: fd = 3
--------------------------------end-----------------------------------
--
/**************************************/
Name: Xiong Feng
QQ:23562033
Address: GuangZhou.China
/**************************************/

linux终端出现"-bash-2.05b$"现象的解决方法!

在linux下面我们有时在头一次使用时,终端的显示界面面现:

onejet20080605 (root) ~ $ <显示正常>

可是当你下次开机时却发同自己的终端变成了这样:

-bash-2.05b$ <显示不正常>

而且终端的彩色的显示也没了,真是郁闷吧. 不要紧,现在有解决方法了:

一、首先确认你的root目录下(如果你用的是root用户登录的话)有下面这两个文件:

1、/root/.bashrc

2、/root/.bash_profile

注意这两个文件是隐藏文件来的。

二、如果没有,那就创建这两个文件吧,并在这两个文件中加入以下内容:

/root/.bashrc内容:

# .bashrc

# User specific aliases and functions

# Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi

/root/.bash_profile内容:

# .bash_profile

# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi

# User specific environment and startup programs
export BASH_ENV=$HOME/.bashrc

三、由上面的两个脚本看,还跟/etc/bashrc这个文件有关,如果没有,那也创建吧,其内容如下:

/etc/bashrc内容:

# /etc/bashrc

# System wide functions and aliases
# Environment stuff goes in /etc/profile

# Uncomment if you liked the old colourfull prompt
# PS1='\[\033[1;33m\]\u\[\033[1;37m\]@\[\033[1;32m\]\h\[\033[1;31m\]\w\[\033[1;36m\]\$
\[\033[0m\]'

PS1='\[\033[0;34m\]\h (\[\033[0;31m\]\u\[\033[0;34m\])
\[\033[0;32m\]\w $ \[\033[0m\]'

VIM="/usr/share/vim"

alias ls='ls --color=tty -F -b -T 0'

至于什么意思就慢慢踹磨吧,呵呵,其实PS1是什么意思我也不知道。觉得帮了你就顶一下吧 :-)

经过上面的三步一般都会成功的,你只要重开一个终端就可以看出效果了。当然这还跟/etc/hosts,
/etc/passwd等文件相关,但一般就是上面的哪个文件没有或出错了的。


--
/**************************************/
Name: Xiong Feng
E-mail:linux0818@gmail.com
MSN:linux0818@hotmail.com
QQ:23562033
Address: GuangZhou.China
/**************************************/

利用变长参数va_start得出DEBUG print

在C语言的开发过程中, 我们常需要打印一些调试信息,但当形成一个用户版本时我们又得将其注释,于是我们想到了宏,如:

--------------------------------------------------------------

#define _DEBUG

#ifdef _DEBUG

printf("debug info:%s\n",info);

linux下如何获取网卡IP地址及MAC地址

文件名: get_ipmac.c

代码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <net/if_arp.h>

#define MAXINTERFACES 16

int main(int argc, char **argv)
{
register int fd, interface, retn = 0;
struct ifreq buf[MAXINTERFACES];
struct arpreq arp;
struct ifconf ifc;
char mac[32] = "";

if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) {
ifc.ifc_len = sizeof buf;
ifc.ifc_buf = (caddr_t) buf;
if (!ioctl(fd, SIOCGIFCONF, (char *) &ifc)) {
interface = ifc.ifc_len / sizeof(struct ifreq);
printf("interface num is interface=%d\n\n", interface);
while (interface-- > 0) {
printf("net device %s\n", buf[interface].ifr_name);

/*Jugde whether the net card status is promisc */
if (!(ioctl(fd, SIOCGIFFLAGS, (char *) &buf[interface]))) {
if (buf[interface].ifr_flags & IFF_PROMISC) {
printf("the interface is PROMISC");
retn ;
}
} else {
char str[256] = "";

sprintf(str, "cpm: ioctl device %s",
buf[interface].ifr_name);
perror(str);
}

/*Jugde whether the net card status is up */
if (buf[interface].ifr_flags & IFF_UP) {
printf("the interface status is UP\n");
} else {
printf("the interface status is DOWN\n");
}

/*Get IP of the net card */
if (!(ioctl(fd, SIOCGIFADDR, (char *) &buf[interface]))) {
printf("IP address is:");
printf("%s\n",
inet_ntoa(((struct sockaddr_in
*) (&buf[interface].ifr_addr))->
sin_addr));
} else {
char str[256] = "";

sprintf(str, "cpm: ioctl device %s",
buf[interface].ifr_name);
perror(str);
}

/*Get HW ADDRESS of the net card */
if (!(ioctl(fd, SIOCGIFHWADDR, (char *) &buf[interface]))) {
printf("HW address is:");

sprintf(mac, "%02x%02x%02x%02x%02x%02x",
(unsigned char) buf[interface].ifr_hwaddr.
sa_data[0],
(unsigned char) buf[interface].ifr_hwaddr.
sa_data[1],
(unsigned char) buf[interface].ifr_hwaddr.
sa_data[2],
(unsigned char) buf[interface].ifr_hwaddr.
sa_data[3],
(unsigned char) buf[interface].ifr_hwaddr.
sa_data[4],
(unsigned char) buf[interface].ifr_hwaddr.
sa_data[5]); // 利用sprintf转换成char *
printf("%s\n", mac);

printf("\n");
}

else {
char str[256];

sprintf(str, "cpm: ioctl device %s",
buf[interface].ifr_name);
perror(str);
}
} //end of while
} else
perror("cpm: ioctl");

} else
perror("cpm: socket");

close(fd);
return retn;
}

/********************************end********************************/

编译: gcc get_ipmac.c

运行: ./a.out

结果:

interface num is interface=4

net device eth2
the interface status is UP
IP address is:192.168.100.48
HW address is:00e04cd803ae

net device eth1
the interface status is UP
IP address is:192.168.60.48
HW address is:000aeb5f92ce

net device eth0
the interface status is UP
IP address is:192.168.80.48
HW address is:00d0b7b8b22e

net device lo
the interface status is UP
IP address is:127.0.0.1
HW address is:000000000000

--
/**************************************/
Name: Xiong Feng
E-mail:linux0818@gmail.com
MSN:linux0818@hotmail.com
QQ:23562033
Address: GuangZhou.China
/**************************************/

GNU 长选项命令解析--getopt_long()

Linux系统下,需要大量的命令行选项,如果自己手动解析他们的话实在是有违软件复用的思想,不过还好,GNU C
library留给我们一个解析命令行的接口(X/Open规范),好好使用它可以使你的程序改观不少。

使用getopt_long()需要引入头文件

#include <getopt.h>

现在我们使用一个例子来说明它的使用。

一个应用程序需要如下的短选项和长选项。

短选项 长选项 作用

-h --help 输出程序命令行参数说明然后退出
-c filename --cat filename 给定显示文件名
-v --version 显示程序当前版本后退出

为了使用getopt_long函数,我们需要先确定两个结构:

1.一个字符串,包括所需要的短选项字符,如果选项后有参数,字符后加一个":"符号。本例中,这个字符串应该为"hc:v"。(因为-o后面有参数filename,所以字符后面要加":")

2.一个包含长选项字符串的结构体数组,每一个结构体包含4个域,第一个域为长选项字符串,第二个域是一个标识,只能为0或1,分别代表没有、有。第三个域永远为NULL。第四个域为对应的短选项字符串。结构体数组的最后一个元素全部为NULL和0,标识结束。在本例中,它应该像一下的样子:

const struct option long_options[] = {
{ "help", 0, NULL, 'h' },
{ "cat", 1, NULL, 'c' },
{ "version", 0, NULL, 'v' },
{ NULL, 0, NULL, 0}
};

调用时需要把main的两个参数argc和argv以及上述两个数据结构传给getopt_long。

每次调用getopt_long,它会解析一个符号,返回相应的短选项字符,如果解析完毕返回-1。所以需要使用一个循环来处理所有的参数,而相应的循环里会使用switch语句进行选择。如果getopt_long遇到一个无效的选项字符,它会打印一个错误消息并且返回'?',很多程序会打印出帮助信息并且中止运行;当getopt_long解析到一个长选项并且发现后面没有参数则返回':',表示缺乏参数。当处理一个参数时,全局变量optarg指向下一个要处理的变量。当getopt_long处理完所有的选项后,全局变量optind指向第一个未知的选项索引。

这一个例子代码为下:

/*-----------------------------------------------------------------------

文件名:getopt_long.c

编译环境: Ubuntu6.10, gcc

功能: 对可执行文件的参数的长短选项的解析.

_____________________________________________*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>

#define FLAG_VERSION (1<<0)
#define FLAG_HELP (1<<1)
#define FLAG_LS (1<<2)
#define FLAG_CAT (1<<4)
#define VERSION "1.01"

struct opt {
unsigned int flags;
char *filename;
};
struct opt opt;

/* Return -1 on error, 0 on success */
int parse_cmd_line(int argc, char *const argv[])
{
int option;
const char *optstring = "hlc:v?";
struct option longopts[] = {
{"cat", required_argument, NULL, 'c'},
{"ls", no_argument, NULL, 'l'},
{"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 'v'},
{0, 0, 0, 0}
};

while ((option =
getopt_long(argc, argv, optstring, longopts, NULL)) != -1)
switch (option) {
case 'c':
opt.flags |= FLAG_CAT;
opt.filename = optarg;
break;
case 'h':
opt.flags |= FLAG_HELP;
break;
case 'l':
opt.flags |= FLAG_LS;
break;
case 'v':
opt.flags |= FLAG_VERSION;
break;
case '?':
opt.flags |= FLAG_HELP;
return -1;
}

if ((opt.flags & FLAG_CAT) && (opt.filename == NULL)) {
return -1;
}

return 0;
}

void print_help(void)
{
static const char *help =
"Usage: getopt_long [OPTIONS]\n"
"Options are:\n"
" -c, --cat Get one file content (Format: getopt_long -c
/etc/password)\n"
" -l, --ls Get current directory's file and directory\n"
" -h, --help Display this help text and exit\n"
" -v, --version Display the version and exit\n";
printf("%s", help);
}

int main(int argc, char **argv)
{
char par[128] = "";

if (argc < 2) {
print_help();
exit(0);
}

opt.flags = 0;

if (parse_cmd_line(argc, argv) < 0) { // parse command line.
exit(-1);
}

if (opt.flags & FLAG_HELP) { // get 'help' .
print_help();
exit(0);
}

if (opt.flags & FLAG_VERSION) { // get version of soft.
printf("Soft Version:%s\n", VERSION);
exit(0);
}

if (opt.flags & FLAG_CAT) { // 'cat' a file
sprintf(par, "%s%c%s", "cat", ' ', opt.filename);
system(par);
exit(0);
}

if (opt.flags & FLAG_LS) { // 'ls' current directory
system("ls -l");
exit(0);
}

return 0;
}

编译: gcc -o getopt_long getopt_long.c

---------------------------------------------------------------------------

运行:

./getopt_long -c /etc/passwd

结果:

root:x:0:0:root:/root:/bin/bash
setup:x:0:0:root:/:/usr/sbin/setup
nobody:x:99:99:Nobody:/:
squid:x:100:100:Squid user:/:
snort:x:101:101:Snort user:/:
sshd:x:102:102:SSH user:/:
ntpd:x:103:103:NTPD user:/:
imspector:x:104:104:IMSpector user:/:
clam:x:105:105:Clam user:/:
sip:x:106:106:SIP user:/:
mysql:x:107:107:MySQL user:/:
---------------------------------------------------------------------------

运行: ./getopt_long -v

结果: Soft Version:1.01

---------------------------------------------------------------------------

如果要运行长选项也是一样的结果,如:

./getopt_long --cat /etc/passwd

./getopt_long --ls

./getopt_long --version


--
/**************************************/
Name: Xiong Feng
E-mail:linux0818@gmail.com
MSN:linux0818@hotmail.com
QQ:23562033
Address: GuangZhou.China
/**************************************/

linux中crontab使用

红帽企业 Linux 随带几个自动化任务的工具:cron、at、和 batch。

一、 cron
cron 是一个可以用来根据时间、日期、月份、星期的组合来调度对重复任务的执行的守护进程。

cron 假定系统持续运行。如果当某任务被调度时系统不在运行,该任务就不会被执行。

要使用 cron 服务,你必须安装了 vixie-cron RPM 软件包,而且必须在运行 crond 服务。要判定该软件包是否已安装,使用
rpm -q vixie-cron 命令。要判定该服务是否在运行,使用 /sbin/service crond status 命令。

1. 配置 cron 任务
cron 的主配置文件是 /etc/crontab,它包括下面几行:

SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/
# run-parts
01 * * * * root run-parts /etc/cron.hourly
02 4 * * * root run-parts /etc/cron.daily
22 4 * * 0 root run-parts /etc/cron.weekly
42 4 1 * * root run-parts /etc/cron.monthly


前四行是用来配置 cron 任务运行环境的变量。SHELL 变量的值告诉系统要使用哪个 shell 环境(在这个例子里是 bash
shell);PATH 变量定义用来执行命令的路径。cron 任务的输出被邮寄给 MAILTO 变量定义的用户名。如果 MAILTO
变量被定义为空白字符串(MAILTO=""),电子邮件就不会被寄出。HOME 变量可以用来设置在执行命令或脚本时使用的主目录。

/etc/crontab 文件中的每一行都代表一项任务,它的格式是:

minute hour day month dayofweek command


minute ― 分钟,从 0 到 59 之间的任何整数

hour ― 小时,从 0 到 23 之间的任何整数

day ― 日期,从 1 到 31 之间的任何整数(如果指定了月份,必须是该月份的有效日期)

month ― 月份,从 1 到 12 之间的任何整数(或使用月份的英文简写如 jan、feb 等等)

dayofweek ― 星期,从 0 到 7 之间的任何整数,这里的 0 或 7 代表星期日(或使用星期的英文简写如 sun、mon 等等)

command ― 要执行的命令(命令可以是 ls /proc >> /tmp/proc 之类的命令,也可以是执行你自行编写的脚本的命令。)

在以上任何值中,星号(*)可以用来代表所有有效的值。譬如,月份值中的星号意味着在满足其它制约条件后每月都执行该命令。

整数间的短线(-)指定一个整数范围。譬如,1-4 意味着整数 1、2、3、4。

用逗号(,)隔开的一系列值指定一个列表。譬如,3, 4, 6, 8 标明这四个指定的整数。

正斜线(/)可以用来指定间隔频率。在范围后加上 /<integer> 意味着在范围内可以跳过 integer。譬如,0-59/2
可以用来在分钟字段定义每两分钟。间隔频率值还可以和星号一起使用。例如,*/3 的值可以用在月份字段中表示每三个月运行一次任务。

开头为井号(#)的行是注释,不会被处理。

如你在 /etc/crontab 文件中所见,它使用 run-parts 脚本来执行
/etc/cron.hourly、/etc/cron.daily、/etc/cron.weekly 和 /etc/cron.monthly
目录中的脚本,这些脚本被相应地每小时、每日、每周、或每月执行。这些目录中的文件应该是 shell 脚本。

如果某 cron 任务需要根据调度来执行,而不是每小时、每日、每周、或每月地执行,它可以被添加到 /etc/cron.d
目录中。该目录中的所有文件使用和 /etc/crontab 中一样的语法。

# record the memory usage of the system every monday
# at 3:30AM in the file /tmp/meminfo
30 3 * * mon cat /proc/meminfo >> /tmp/meminfo
# run custom script the first day of every month at 4:10AM
10 4 1 * * /root/scripts/backup.sh


例 1. crontab 的例子

根用户以外的用户可以使用 crontab 工具来配置 cron 任务。所有用户定义的 crontab 都被保存在
/var/spool/cron 目录中,并使用创建它们的用户身份来执行。要以某用户身份创建一个 crontab 项目,登录为该用户,然后键入
crontab -e 命令,使用由 VISUAL 或 EDITOR 环境变量指定的编辑器来编辑该用户的 crontab。该文件使用的格式和
/etc/crontab 相同。当对 crontab 所做的改变被保存后,该 crontab 文件就会根据该用户名被保存,并写入文件
/var/spool/cron/username 中。

cron 守护进程每分钟都检查 /etc/crontab 文件、etc/cron.d/ 目录、以及 /var/spool/cron
目录中的改变。如果发现了改变,它们就会被载入内存。这样,当某个 crontab 文件改变后就不必重新启动守护进程了。

2. 控制对 cron 的使用
/etc/cron.allow 和 /etc/cron.deny 文件被用来限制对 cron
的使用。这两个使用控制文件的格式都是每行一个用户。两个文件都不允许空格。如果使用控制文件被修改了,cron
守护进程(crond)不必被重启。使用控制文件在每次用户添加或删除一项 cron 任务时都会被读取。

无论使用控制文件中的规定如何,根用户都总是可以使用 cron。

如果 cron.allow 文件存在,只有其中列出的用户才被允许使用 cron,并且 cron.deny 文件会被忽略。

如果 cron.allow 文件不存在,所有在 cron.deny 中列出的用户都被禁止使用 cron。

3. 启动和停止服务
启动cron服务:service crond start 或 /etc/init.d/crond start

停止cron服务:service crond stop 或 /etc/init.d/crond stop

重启cron服务:service crond restart 或 /etc/init.d/crond restart

推荐你在引导时启动该服务。


--
/**************************************/
Name: Xiong Feng
E-mail:linux0818@gmail.com
MSN:linux0818@hotmail.com
QQ:23562033
Address: GuangZhou.China
/**************************************/

完全优化MySQL数据库性能的八个方法

完全优化MySQL数据库性能的八个方法

本文从八个方面来讲解如何全新优化MySQL数据库性能。
1、选取最适用的字段属性
  MySQL可以很好的支持大数据量的存取,但是一般说来,数据库中的表越小,在它上面执行的查询也就会越快。因此,在创建表的时候,为了获得更好的性能,我们可以将表中字段的宽度设得尽可能小。例如,在定义邮政编码这个字段时,如果将其设置为CHAR(255),显然给数据库增加了不必要的空间,甚至使用VARCHAR这种类型也是多余的,因为CHAR(6)就可以很好的完成任务了。同样的,如果可以的话,我们应该使用MEDIUMINT而不是BIGIN来定义整型字段。
  另外一个提高效率的方法是在可能的情况下,应该尽量把字段设置为NOT NULL,这样在将来执行查询的时候,数据库不用去比较NULL值。
  对于某些文本字段,例如"省份"或者"性别",我们可以将它们定义为ENUM类型。因为在MySQL中,ENUM类型被当作数值型数据来处理,而数值型数据被处理起来的速度要比文本类型快得多。这样,我们又可以提高数据库的性能。


2、使用连接(JOIN)来代替子查询(Sub-Queries)
  MySQL从4.1开始支持SQL的子查询。这个技术可以使用SELECT语句来创建一个单列的查询结果,然后把这个结果作为过滤条件用在另一个查询中。例如,我们要将客户基本信息表中没有任何订单的客户删除掉,就可以利用子查询先从销售信息表中将所有发出订单的客户ID取出来,然后将结果传递给主查询,如下所示:

DELETE FROM customerinfo
WHERE CustomerID NOT in (SELECT CustomerID FROM salesinfo )

  使用子查询可以一次性的完成很多逻辑上需要多个步骤才能完成的SQL操作,同时也可以避免事务或者表锁死,并且写起来也很容易。但是,有些情况下,子查询可以被更有效率的连接(JOIN)..
替代。例如,假设我们要将所有没有订单记录的用户取出来,可以用下面这个查询完成:

SELECT * FROM customerinfo
WHERE CustomerID NOT in (SELECT CustomerID FROM salesinfo )

  如果使用连接(JOIN)..
来完成这个查询工作,速度将会快很多。尤其是当salesinfo表中对CustomerID建有索引的话,性能将会更好,查询如下:

SELECT * FROM customerinfo
LEFT JOIN salesinfoON customerinfo.CustomerID=salesinfo.
CustomerID
WHERE salesinfo.CustomerID IS NULL

  连接(JOIN).. 之所以更有效率一些,是因为 MySQL不需要在内存中创建临时表来完成这个逻辑上的需要两个步骤的查询工作。

3、使用联合(UNION)来代替手动创建的临时表
  MySQL 从 4.0 的版本开始支持 UNION 查询,它可以把需要使用临时表的两条或更多的 SELECT
查询合并的一个查询中。在客户端的查询会话结束的时候,临时表会被自动删除,从而保证数据库整齐、高效。使用 UNION
来创建查询的时候,我们只需要用 UNION作为关键字把多个 SELECT 语句连接起来就可以了,要注意的是所有 SELECT
语句中的字段数目要想同。下面的例子就演示了一个使用 UNION的查询。

SELECT Name, Phone FROM client
UNION
SELECT Name, BirthDate FROM author
UNION
SELECT Name, Supplier FROM product

4、事务
  尽管我们可以使用子查询(Sub-Queries)、连接(JOIN)和联合(UNION)来创建各种各样的查询,但不是所有的数据库操作都可以只用一条或少数几条SQL语句就可以完成的。更多的时候是需要用到一系列的语句来完成某种工作。但是在这种情况下,当这个语句块中的某一条语句运行出错的时候,整个语句块的操作就会变得不确定起来。设想一下,要把某个数据同时插入两个相关联的表中,可能会出现这样的情况:第一个表中成功更新后,数据库突然出现意外状况,造成第二个表中的操作没有完成,这样,就会造成数据的不完整,甚至会破坏数据库中的数据。要避免这种情况,就应该使用事务,它的作用是:要么语句块中每条语句都操作成功,要么都失败。换句话说,就是可以保持数据库中数据的一致性和完整性。事物以BEGIN
关键字开始,COMMIT关键字结束。在这之间的一条SQL操作失败,那么,ROLLBACK命令就可以把数据库恢复到BEGIN开始之前的状态。

BEGIN;
INSERT INTO salesinfo SET CustomerID=14;
UPDATE inventory SET Quantity=11
WHERE item='book';
COMMIT;

  事务的另一个重要作用是当多个用户同时使用相同的数据源时,它可以利用锁定数据库的方法来为用户提供一种安全的访问方式,这样可以保证用户的操作不被其它的用户所干扰。

5、锁定表
  尽管事务是维护数据库完整性的一个非常好的方法,但却因为它的独占性,有时会影响数据库的性能,尤其是在很大的应用系统中。由于在事务执行的过程中,数据库将会被锁定,因此其它的用户请求只能暂时等待直到该事务结束。如果一个数据库系统只有少数几个用户来使用,事务造成的影响不会成为一个太大的问题;但假设有成千上万的用户同时访问一个数据库系统,例如访问一个电子商务网站,就会产生比较严重的响应延迟。

  其实,有些情况下我们可以通过锁定表的方法来获得更好的性能。下面的例子就用锁定表的方法来完成前面一个例子中事务的功能。

LOCK TABLE inventory WRITE
SELECT Quantity FROM inventory
WHEREItem='book';
...
UPDATE inventory SET Quantity=11
WHEREItem='book';
UNLOCK TABLES

  这里,我们用一个 SELECT 语句取出初始数据,通过一些计算,用 UPDATE 语句将新值更新到表中。包含有 WRITE 关键字的
LOCK TABLE 语句可以保证在 UNLOCK TABLES 命令被执行之前,不会有其它的访问来对 inventory
进行插入、更新或者删除的操作。

6、使用外键
  锁定表的方法可以维护数据的完整性,但是它却不能保证数据的关联性。这个时候我们就可以使用外键。例如,外键可以保证每一条销售记录都指向某一个存在的客户。在这里,外键可以把customerinfo
表中的CustomerID映射到salesinfo表中CustomerID,任何一条没有合法CustomerID的记录都不会被更新或插入到salesinfo中。

CREATE TABLE customerinfo
(
CustomerID INT NOT NULL ,
PRIMARY KEY ( CustomerID )
) TYPE = INNODB;

CREATE TABLE salesinfo
(
SalesID INT NOT NULL,
CustomerID INT NOT NULL,
PRIMARY KEY(CustomerID, SalesID),
FOREIGN KEY (CustomerID) REFERENCES customerinfo
(CustomerID) ON DELETECASCADE
) TYPE = INNODB;

  注意例子中的参数"ON DELETE CASCADE"。该参数保证当 customerinfo
表中的一条客户记录被删除的时候,salesinfo 表中所有与该客户相关的记录也会被自动删除。如果要在 MySQL
中使用外键,一定要记住在创建表的时候将表的类型定义为事务安全表 InnoDB类型。该类型不是 MySQL 表的默认类型。定义的方法是在
CREATE TABLE 语句中加上 TYPE=INNODB。如例中所示。

7、使用索引
  索引是提高数据库性能的常用方法,它可以令数据库服务器以比没有索引快得多的速度检索特定的行,尤其是在查询语句当中包含有MAX(),
MIN()和ORDERBY这些命令的时候,性能提高更为明显。那该对哪些字段建立索引呢?一般说来,索引应建立在那些将用于JOIN,
WHERE判断和ORDER BY排序的字段上。尽量不要对数据库中某个含有大量重复的值的字段建立索引。对于一个ENUM类型的字段来说,出现大量重复值是很有可能的情况,例如customerinfo中的"province"..
字段,在这样的字段上建立索引将不会有什么帮助;相反,还有可能降低数据库的性能。我们在创建表的时候可以同时创建合适的索引,也可以使用ALTER
TABLE或CREATE INDEX在以后创建索引。此外,MySQL从版本3.23.23开始支持全文索引和搜索。全文索引在MySQL
中是一个FULLTEXT类型索引,但仅能用于MyISAM
类型的表。对于一个大的数据库,将数据装载到一个没有FULLTEXT索引的表中,然后再使用ALTER TABLE或CREATE
INDEX创建索引,将是非常快的。但如果将数据装载到一个已经有FULLTEXT索引的表中,执行过程将会非常慢。

8、优化的查询语句
  绝大多数情况下,使用索引可以提高查询的速度,但如果SQL语句使用不恰当的话,索引将无法发挥它应有的作用。下面是应该注意的几个方面。首先,最好是在相同类型的字段间进行比较的操作。在MySQL
3.23版之前,这甚至是一个必须的条件。例如不能将一个建有索引的INT字段和BIGINT字段进行比较;但是作为特殊的情况,在CHAR类型的字段和VARCHAR类型字段的字段大小相同的时候,可以将它们进行比较。其次,在建有索引的字段上尽量不要使用函数进行操作。

  例如,在一个DATE类型的字段上使用YEAE()函数时,将会使索引不能发挥应有的作用。所以,下面的两个查询虽然返回的结果一样,但后者要比前者快得多。

SELECT * FROM order WHERE YEAR(OrderDate)<2001;

SELECT * FROM order WHERE OrderDate<"2001-01-01";

  同样的情形也会发生在对数值型字段进行计算的时候:

SELECT * FROM inventory WHERE Amount/7<24;

SELECT * FROM inventory WHERE Amount<24*7;

  上面的两个查询也是返回相同的结果,但后面的查询将比前面的一个快很多。第三,在搜索字符型字段时,我们有时会使用 LIKE
关键字和通配符,这种做法虽然简单,但却也是以牺牲系统性能为代价的。例如下面的查询将会比较表中的每一条记录。

SELECT * FROM books
WHERE name like "MySQL%"

  但是如果换用下面的查询,返回的结果一样,但速度就要快上很多:

SELECT * FROM books
WHERE name>="MySQL"and name<"MySQM"

  最后,应该注意避免在查询中让MySQL进行自动类型转换,因为转换过程也会使索引变得不起作用。


--
/**************************************/
Name: Xiong Feng
E-mail:linux0818@gmail.com
MSN:linux0818@hotmail.com
QQ:23562033
Address: GuangZhou.China
/**************************************/

sprintf函数使用详解

printf 可能是许多程序员在开始学习C 语言时接触到的第二个函数(我猜第一个是main),说
起来,自然是老朋友了,可是,你对这个老朋友了解多吗?你对它的那个孪生兄弟sprintf 了解多
吗?在将各种类型的数据构造成字符串时,sprintf 的强大功能很少会让你失望。
由于sprintf 跟printf 在用法上几乎一样,只是打印的目的地不同而已,前者打印到字符串中,
后者则直接在命令行上输出。这也导致sprintf 比printf 有用得多。所以本文着重介绍sprintf,有时
也穿插着用用pritnf。
sprintf 是个变参函数,定义如下:
int sprintf( char *buffer, const char *format [, argument] ... );
除了前两个参数类型固定外,后面可以接任意多个参数。而它的精华,显然就在第二个参数:
格式化字符串上。
printf 和sprintf 都使用格式化字符串来指定串的格式,在格式串内部使用一些以"%"开头的
格式说明符(format specifications)来占据一个位置,在后边的变参列表中提供相应的变量,最终
函数就会用相应位置的变量来替代那个说明符,产生一个调用者想要的字符串。
格式化数字字符串
sprintf 最常见的应用之一莫过于把整数打印到字符串中,所以,spritnf 在大多数场合可以替代
itoa。如:
//把整数123 打印成一个字符串保存在s 中。
sprintf(s, "%d", 123); //产生"123"
可以指定宽度,不足的左边补空格:
sprintf(s, "%8d%8d", 123, 4567); //产生:" 123 4567"
当然也可以左对齐:
sprintf(s, "%-8d%8d", 123, 4567); //产生:"123 4567"
也可以按照16 进制打印:
sprintf(s, "%8x", 4567); //小写16 进制,宽度占8 个位置,右对齐
sprintf(s, "%-8X", 4568); //大写16 进制,宽度占8 个位置,左对齐

这样,一个整数的16 进制字符串就很容易得到,但我们在打印16 进制内容时,通常想要一
种左边补0 的等宽格式,那该怎么做呢?很简单,在表示宽度的数字前面加个0 就可以了。
sprintf(s, "%08X", 4567); //产生:"000011D7"
上面以"%d"进行的10 进制打印同样也可以使用这种左边补0 的方式。
这里要注意一个符号扩展的问题:比如,假如我们想打印短整数(short)-1 的内存16 进制表
示形式,在Win32 平台上,一个short 型占2 个字节,所以我们自然希望用4 个16 进制数字来打
印它:
short si = -1;
sprintf(s, "%04X", si);
产生"FFFFFFFF",怎么回事?因为spritnf 是个变参函数,除了前面两个参数之外,后面的
参数都不是类型安全的,函数更没有办法仅仅通过一个"%X"就能得知当初函数调用前参数压栈
时被压进来的到底是个4 字节的整数还是个2 字节的短整数,所以采取了统一4 字节的处理方式,
导致参数压栈时做了符号扩展,扩展成了32 位的整数-1,打印时4 个位置不够了,就把32 位整数
-1 的8 位16 进制都打印出来了。如果你想看si 的本来面目,那么就应该让编译器做0 扩展而不是
符号扩展(扩展时二进制左边补0 而不是补符号位):
sprintf(s, "%04X", (unsigned short)si);
就可以了。或者:
unsigned short si = -1;
sprintf(s, "%04X", si);
sprintf 和printf 还可以按8 进制打印整数字符串,使用"%o"。注意8 进制和16 进制都不会打
印出负数,都是无符号的,实际上也就是变量的内部编码的直接的16 进制或8 进制表示。
控制浮点数打印格式
浮点数的打印和格式控制是sprintf 的又一大常用功能,浮点数使用格式符"%f"控制,默认保
留小数点后6 位数字,比如:
sprintf(s, "%f", 3.1415926); //产生"3.141593"
但有时我们希望自己控制打印的宽度和小数位数,这时就应该使用:"%m.nf"格式,其中m 表
示打印的宽度,n 表示小数点后的位数。比如:
sprintf(s, "%10.3f", 3.1415626); //产生:" 3.142"
sprintf(s, "%-10.3f", 3.1415626); //产生:"3.142 "
sprintf(s, "%.3f", 3.1415626); //不指定总宽度,产生:"3.142"
注意一个问题,你猜
int i = 100;
sprintf(s, "%.2f", i);
会打出什么东东来?"100.00"?对吗?自己试试就知道了,同时也试试下面这个:
sprintf(s, "%.2f", (double)i);
第一个打出来的肯定不是正确结果,原因跟前面提到的一样,参数压栈时调用者并不知道跟i
相对应的格式控制符是个"%f"。而函数执行时函数本身则并不知道当年被压入栈里的是个整数,
于是可怜的保存整数i 的那4 个字节就被不由分说地强行作为浮点数格式来解释了,整个乱套了。
不过,如果有人有兴趣使用手工编码一个浮点数,那么倒可以使用这种方法来检验一下你手
工编排的结果是否正确。?
字符/Ascii 码对照
我们知道,在C/C 语言中,char 也是一种普通的scalable 类型,除了字长之外,它与short,
int,long 这些类型没有本质区别,只不过被大家习惯用来表示字符和字符串而已。(或许当年该把
这个类型叫做"byte",然后现在就可以根据实际情况,使用byte 或short 来把char 通过typedef 定
义出来,这样更合适些)
于是,使用"%d"或者"%x"打印一个字符,便能得出它的10 进制或16 进制的ASCII 码;反过
来,使用"%c"打印一个整数,便可以看到它所对应的ASCII 字符。以下程序段把所有可见字符的
ASCII 码对照表打印到屏幕上(这里采用printf,注意"#"与"%X"合用时自动为16 进制数增加"0X"
前缀):
for(int i = 32; i < 127; i ) {
printf("[ %c ]: %3d 0x%#04X\n", i, i, i);
}
连接字符串
sprintf 的格式控制串中既然可以插入各种东西,并最终把它们"连成一串",自然也就能够连
接字符串,从而在许多场合可以替代strcat,但sprintf 能够一次连接多个字符串(自然也可以同时
在它们中间插入别的内容,总之非常灵活)。比如:
char* who = "I";
char* whom = "CSDN";
sprintf(s, "%s love %s.", who, whom); //产生:"I love CSDN. "
strcat 只能连接字符串(一段以'\0'结尾的字符数组或叫做字符缓冲,null-terminated-string),
但有时我们有两段字符缓冲区,他们并不是以'\0'结尾。比如许多从第三方库函数中返回的字符数
组,从硬件或者网络传输中读进来的字符流,它们未必每一段字符序列后面都有个相应的'\0'来结
尾。如果直接连接,不管是sprintf 还是strcat 肯定会导致非法内存操作,而strncat 也至少要求第
一个参数是个null-terminated-string,那该怎么办呢?我们自然会想起前面介绍打印整数和浮点数
时可以指定宽度,字符串也一样的。比如:
char a1[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};
char a2[] = {'H', 'I', 'J', 'K', 'L', 'M', 'N'};
如果:
sprintf(s, "%s%s", a1, a2); //Don't do that!
十有八九要出问题了。是否可以改成:
sprintf(s, "%7s%7s", a1, a2);
也没好到哪儿去,正确的应该是:
sprintf(s, "%.7s%.7s", a1, a2);//产生:"ABCDEFGHIJKLMN"
这可以类比打印浮点数的"%m.nf",在"%m.ns"中,m 表示占用宽度(字符串长度不足时补空
格,超出了则按照实际宽度打印),n 才表示从相应的字符串中最多取用的字符数。通常在打印字
符串时m 没什么大用,还是点号后面的n 用的多。自然,也可以前后都只取部分字符:
sprintf(s, "%.6s%.5s", a1, a2);//产生:"ABCDEFHIJKL"
在许多时候,我们或许还希望这些格式控制符中用以指定长度信息的数字是动态的,而不是
静态指定的,因为许多时候,程序要到运行时才会清楚到底需要取字符数组中的几个字符,这种
动态的宽度/精度设置功能在sprintf 的实现中也被考虑到了,sprintf 采用"*"来占用一个本来需要一
个指定宽度或精度的常数数字的位置,同样,而实际的宽度或精度就可以和其它被打印的变量一
样被提供出来,于是,上面的例子可以变成:
sprintf(s, "%.*s%.*s", 7, a1, 7, a2);
或者:
sprintf(s, "%.*s%.*s", sizeof(a1), a1, sizeof(a2), a2);
实际上,前面介绍的打印字符、整数、浮点数等都可以动态指定那些常量值,比如:
sprintf(s, "%-*d", 4, 'A'); //产生"65 "
sprintf(s, "%#0*X", 8, 128); //产生"0X000080","#"产生0X
sprintf(s, "%*.*f", 10, 2, 3.1415926); //产生" 3.14"
打印地址信息
有时调试程序时,我们可能想查看某些变量或者成员的地址,由于地址或者指针也不过是个32 位的数,你完全可以使用打印无符号整数的"%u"把他们打印出来:
sprintf(s, "%u", &i);
不过通常人们还是喜欢使用16 进制而不是10 进制来显示一个地址:
sprintf(s, "%08X", &i);
然而,这些都是间接的方法,对于地址打印,sprintf 提供了专门的"%p":
sprintf(s, "%p", &i);
我觉得它实际上就相当于:
sprintf(s, "%0*x", 2 * sizeof(void *), &i);
利用sprintf 的返回值
较少有人注意printf/sprintf 函数的返回值,但有时它却是有用的,spritnf 返回了本次函数调用
最终打印到字符缓冲区中的字符数目。也就是说每当一次sprinf 调用结束以后,你无须再调用一次
strlen 便已经知道了结果字符串的长度。如:
int len = sprintf(s, "%d", i);
对于正整数来说,len 便等于整数i 的10 进制位数。
下面的是个完整的例子,产生10 个[0, 100)之间的随机数,并将他们打印到一个字符数组s 中,
以逗号分隔开。
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
int main() {
srand(time(0));
char s[64];
int offset = 0;
for(int i = 0; i < 10; i ) {
offset = sprintf(s offset, "%d,", rand() % 100);
}
s[offset - 1] = '\n';//将最后一个逗号换成换行符。
printf(s);
return 0;
}
设想当你从数据库中取出一条记录,然后希望把他们的各个字段按照某种规则连接成一个字
符串时,就可以使用这种方法,从理论上讲,他应该比不断的strcat 效率高,因为strcat 每次调用
都需要先找到最后的那个'\0'的位置,而在上面给出的例子中,我们每次都利用sprintf 返回值把这
个位置直接记下来了。
使用sprintf 的常见问题
sprintf 是个变参函数,使用时经常出问题,而且只要出问题通常就是能导致程序崩溃的内存访
问错误,但好在由sprintf 误用导致的问题虽然严重,却很容易找出,无非就是那么几种情况,通
常用眼睛再把出错的代码多看几眼就看出来了。
?? 缓冲区溢出
第一个参数的长度太短了,没的说,给个大点的地方吧。当然也可能是后面的参数的问
题,建议变参对应一定要细心,而打印字符串时,尽量使用"%.ns"的形式指定最大字符数。
?? 忘记了第一个参数
低级得不能再低级问题,用printf 用得太惯了。//偶就常犯。:。(
?? 变参对应出问题
通常是忘记了提供对应某个格式符的变参,导致以后的参数统统错位,检查检查吧。尤
其是对应"*"的那些参数,都提供了吗?不要把一个整数对应一个"%s",编译器会觉得你
欺她太甚了(编译器是obj 和exe 的妈妈,应该是个女的,:P)。
strftime
sprnitf 还有个不错的表妹:strftime,专门用于格式化时间字符串的,用法跟她表哥很像,也
是一大堆格式控制符,只是毕竟小姑娘家心细,她还要调用者指定缓冲区的最大长度,可能是为
了在出现问题时可以推卸责任吧。这里举个例子:
time_t t = time(0);
//产生"YYYY-MM-DD hh:mm:ss"格式的字符串。
char s[32];
strftime(s, sizeof(s), "%Y-%m-%d %H:%M:%S", localtime(&t));
sprintf 在MFC 中也能找到他的知音:CString::Format,strftime 在MFC 中自然也有她的同道:
CTime::Format,这一对由于从面向对象哪里得到了赞助,用以写出的代码更觉优雅。

选自《CSDN 社区电子杂志――C/C 杂志》
http://emag.csdn.net 2005 年1 月 总第1 期 - 93 -
本文作者:steedhorse(晨星)


--
/**************************************/
Name: Xiong Feng
E-mail:linux0818@gmail.com
MSN:linux0818@hotmail.com
QQ:23562033
Address: GuangZhou.China
/**************************************/

C++ STL map的使用

以下是对C++中STL map的插入,查找,遍历及删除的例子:

#include <map>
#include <string>
#include <iostream>
using namespace std;

void map_insert(map < string, string > *mapStudent, string index, string x)
{
mapStudent->insert(map < string, string >::value_type(index, x));
}

int main(int argc, char **argv)
{
char tmp[32] = "";
map < string, string > mapS;

//insert element
map_insert(&mapS, "192.168.0.128", "xiong");
map_insert(&mapS, "192.168.200.3", "feng");
map_insert(&mapS, "192.168.200.33", "xiongfeng");

map < string, string >::iterator iter;

cout << "We Have Third Element:" << endl;
cout << "-----------------------------" << endl;

//find element
iter = mapS.find("192.168.0.33");
if (iter != mapS.end()) {
cout << "find the elememt" << endl;
cout << "It is:" << iter->second << endl;
} else {
cout << "not find the element" << endl;
}

//see element
for (iter = mapS.begin(); iter != mapS.end(); iter ) {

cout << "| " << iter->first << " | " << iter->
second << " |" << endl;

}
cout << "-----------------------------" << endl;

map_insert(&mapS, "192.168.30.23", "xf");

cout << "After We Insert One Element:" << endl;
cout << "-----------------------------" << endl;
for (iter = mapS.begin(); iter != mapS.end(); iter ) {

cout << "| " << iter->first << " | " << iter->
second << " |" << endl;

}

cout << "-----------------------------" << endl;

//delete element
iter = mapS.find("192.168.200.33");
if (iter != mapS.end()) {
cout << "find the element:" << iter->first << endl;
cout << "delete element:" << iter->first << endl;
cout << "=================================" << endl;
mapS.erase(iter);
} else {
cout << "not find the element" << endl;
}
for (iter = mapS.begin(); iter != mapS.end(); iter ) {

cout << "| " << iter->first << " | " << iter->
second << " |" << endl;

}
cout << "=================================" << endl;

return 0;
}


--
/**************************************/
Name: Xiong Feng
E-mail:linux0818@gmail.com
MSN:linux0818@hotmail.com
QQ:23562033
Address: GuangZhou.China
/**************************************/

用md5()函数生成的16加密数据

一、首先确认你的linux系统已安装openssl开发包libssl-dev,可以查看:
ls /usr/include/openssl/md5.h
ls /usr/lib/libcrypto.so
如果有头文件md5.h和库libcrypto.so,则说明libssl-dev已安装。
如果没有,则需要安装:sudo apt-get install libssl-dev
二、现在可以编写你的数据加密程序md5.c了:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <openssl/md5.h>

int main(int argc, char *argv[])
{
char *buf = "123";
char *md;
int i;
md = MD5(buf, strlen(buf), NULL);
for (i = 0; i < strlen(md); i )
printf("%x ", md[i]);
printf("\n");
return 0;
}


三、编译:
gcc md5.c -lcrypto
四、运行:
./a.out
五、结果:
20 2c ffffffb9 62 ffffffac 59 7 5b ffffff96 4b 7 15 2d 23 4b 70


--
/**************************************/
Name: Xiong Feng
E-mail:linux0818@gmail.com
MSN:linux0818@hotmail.com
QQ:23562033
Address: GuangZhou.China
/**************************************/

防火墙之基础篇(iptable)

我们知道网上的访问通过tcp/ip封包来进入主机系统的。在linux中它一般要同过ip过滤机制来实现第一层防护,如果通过了这层防护还的通过下一关的检查
那就是TCP_Wrappers 的功能。
封包过滤( IP Filter ):
封 包过滤是 linux 提供的第一道防火墙呦!但是不同的核心版本会有不一样的封包过滤机制!以 2.2.xx 为核心的 Linux 主要以
ipchains 作为过滤机制,至于目前新版的 2.4.xx 则以 iptables 为机制!OK!既然我们的 Red Hat 7.1,
7.2, 7.3 为 kernel 2.4.xx ,所以用 iptables 来进行 IP 抵挡的工作啦!那么由于 TCP 封包里头有 IP
及 port ,所以要抵挡来源 IP 或者是自身的 port ,自然就很容易来进行啦!您目前只要知道 iptables 可以经由 TCP
的封包表投资料来进行分析的工作例如:和附规则的就通过,否则就把它丢弃 这样就防止不符合规则的人进入你的电脑。
至于抵挡封包的工作则可以让 TCP_Wrappers 来进行
要常常去看 /var/log/messages 与 /var/log/secure 这两个个档案!都是登陆登录记录等。
要做好主机的防护,第一步就是要建立完善的密码规则啦!因为这个咚咚常常是 cracker
尝试入侵的第一步!你必须要建立好主机的密码规则,可以尝试以 chattr 来将 /etc/passwd 及 /etc/shadow
做成不可变更的档案!较为安全啦!
做好安全的几个常见的工作
1.升级与修补套件漏洞、及移除危险套件:
2.每项系统服务的安全设定项目
3.TCP_Wrappers 的基础防火设定
4.iptables 的防火规则设定
5.主机资源侦测系统( MRTG )
6.登录档案分析系统:

iptables:
iptables 是 linux Kernel 2.4.xx 版本以上的主要 IP 过滤机制!他最大的功能就是可以过滤掉不要的 TCP
封包啦!当然功能还不止于此,他还可以用来进行 IP 伪装,以达成 NAT 的主机功能呢! iptables
的工作方向,必须要依规则的顺序来分析,底下我们简单的谈一谈 iptables 的几个概念吧:
有几个 tables :
跟之前 版本的 ipchains 不同的地方是, iptables 可以自行定义一些 tables
的新规定!将可以让防火墙规则变的更为便于管理呢!基本上,原本的 iptable 至少有两个 table ,一个是 filter (
预设的,没有填写 tables 时,就是 filter 这个 table 啦 ),一个则是相当重要的 nat table 。其中,
filter 可以用来管理主机的安全,至于 nat 则是用来处理 NAT 的功能啦!
清除规则:
iptables 的订定方法其实很简单,就是使用指令列的方式来订定而已,他的基础语法在清除规则时,是这样的:
[root @test /root]# /sbin/iptables [-FXZ]
参数说明:
-F :清除所有的已订定的规则;
-X :杀掉所有使用者建立的 chain (应该说的是 tables )�;
-Z :将所有的 chain 的计数与流量统计都归零
范例:
[root @test /root]# /sbin/iptables -F
[root @test /root]# /sbin/iptables -X
[root @test /root]# /sbin/iptables -Z
请注意,如果在远程联机的时候,『这三个指令必须要用 scripts 来连续执行』,不然肯定『会让你自己被主机挡在门外!』

定义政策( Policy ):
清 除规则之后,再接下来就是要设定规则的政策啦!这个所谓的政策指的是『当你的封包不在你的规则之内时,则该封包的通过与否,以 Policy
的设定为准』,例如:你设定了十条规则,但有一个封包来的时候,这十条规则都不适用,这个时候此一封包就会依据 Policy
的规定为准,来决定是否可以通过防火墙�。通常这个政策在 INPUT 方面可以定义的比较严格一点,而 FORWARD 与 OUTPUT
则可以订定的松一些!
[root @test /root]# /sbin/iptables [-t tables] [-P]
[INPUT,OUTPUT,FORWARD| PREROUTING,OUTPUT,POSTROUTING] [ACCEPT,DROP]
参数说明:
-t   :定义 table !
tables :table 的名称,例如 nat �!
-P   :定义政策( Policy )。
INPUT :封包为输入主机的方向;
OUTPUT :封包为输出主机的方向;
FORWARD:封包为不进入主机而向外再传输出去的方向;
PREROUTING :在进入路由之前进行的工作;
OUTPUT   :封包为输出主机的方向;
POSTROUTING:在进入路由之后进行的工作。
范例:
[root @test /root]# /sbin/iptables -P INPUT ACCEPT
[root @test /root]# /sbin/iptables -P OUTPUT ACCEPT
[root @test /root]# /sbin/iptables -P FORWARD ACCEPT
[root @test /root]# /sbin/iptables -t nat -P PREROUTING ACCEPT
[root @test /root]# /sbin/iptables -t nat -P OUTPUT ACCEPT
[root @test /root]# /sbin/iptables -t nat -P POSTROUTING ACCEPT
将预设的政策都定义为接受�!

增加、插入规则:
接下来则要定义规则啦!我们底下先完全以主机的角度来观察!可以这样来设定啦!
[root @test /root]# /sbin/iptables [-AI] [INPUT,OUTPUT,FORWARD] [-io
interface] [-p TCP,UDP] [-s IP/network] [--sport ports] [-d
IP/network] [--dport ports] -j [ACCEPT,DROP]
参数说明:
-A   :新增加一条规则,该规则增加在最后面一行;
-I   :在第一条规则加入;
INPUT :封包为输入主机的方向;
OUTPUT :封包为输出主机的方向;
FORWARD:封包为不进入主机而向外再传输出去的方向;
-i    :流入的网卡接口
-o    :流出的网卡接口
interface :网络卡接口,例如 ppp0, eth0, eth1....
-p :请注意,这是小写呦!封包的协议啦!
TCP :封包为 TCP 协议的封包;
UDP :封包为 UDP 协议的封包;
-s :来源封包的 IP 或者是 Network ( 网域 );
--sport:来源封包的 port 号码;
-d :目标主机的 IP 或者是 Network ( 网域 );
--dport:目标主机的 port 号码;
-j   :动作,可以接底下的动作;
ACCEPT :接受该封包
DROP  :丢弃封包
范例:
[root @test /root]# /sbin/iptables -A INPUT -i lo -j ACCEPT
所有的来自 lo 这个接口的封包,都予以接受
[root @test /root]# /sbin/iptables -A INPUT -i eth0 -p TCP -s
192.168.0.1 -j ACCEPT
来自 192.168.0.1 这个 IP 的封包都予以接受
[root @test /root]# /sbin/iptables -A INPUT -i eth0 -p TCP -s
192.168.1.0/24 -j ACCEPT
来自 192.168.1.0 这个 C Class 的网域的任何一部计算机,就予以接受!
[root @test /root]# /sbin/iptables -A INPUT -i eth0 -p TCP -s
192.168.1.25 -j DROP
来自 192.168.1.25 的 IP 的封包,就直接全部给他丢弃!
[root @test /root]# /sbin/iptables -A INPUT -i eth0 -p TCP --dport 21 -j DROP
只要想要进来 21 这个 port 的封包,就把他丢弃!
[root @test /root]# /sbin/iptables -A INPUT -i eth0 -p TCP -s
192.168.0.24 --dport 22 -j ACCEPT
来自 192.168.0.24 的主机,想要到我的 port 22 时,就予以接受!
请注意:防火墙的规则是『一行一行依序来检查的,若符合任何一条规则,则予以动作(接受或丢弃),否则继续往下检查到最后一条』上
TCP_Wrappers:
这 个 TCP_Wrappers 实在是很简单的一个设定工作,因为他只要设定 /etc/hosts.allow 及
/etc/hosts.deny 就可以啦!基本上,他是经由 /usr/sbin/tcpd 这个程序来进行 TCP
的检验工作!而检验的方式则是以 /etc/hosts.allow 及 /etc/hosts.deny 来设定的啦!检验的流程是先以
/etc/hosts.allow 这个档案,检验完之后,在到 /etc/hosts.deny 去搜寻!好了,那么 hosts.allow
要怎样设定呢?
<服务名称> : <IP/network> : <action>
特别注意, network 可以使用 192.168.0.0/255.255.255.0 ,但不可使用 192.168.0.0/24
[root @test /root]# vi /etc/hosts.allow
in.telnetd: 127.0.0.1 : allow
in.ftpd: 127.0.0.1 : allow
本机的 127.0.0.1 开放 telnet 及 ftp 哩!
[root @test /root]# vi /etc/hosts.deny
in.telnetd: 192.168.2.3 : deny
将 192.168.2.3 的 telnet 服务关掉!

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=143925


--
/**************************************/
Name: Xiong Feng
E-mail:linux0818@gmail.com
MSN:linux0818@hotmail.com
QQ:23562033
Address: GuangZhou.China
/**************************************/

ROM、RAM、DRAM、SRAM、FLASH的区别

ROM和RAM指的都是半导体存储器,ROM是Read Only Memory的缩写,RAM是Random Access
Memory的缩写。ROM在系统停止供电的时候仍然可以保持数据,而RAM通常都是在掉电之后就丢失数据,典型的RAM就是计算机的内存。

RAM有两大类,一种称为静态RAM(Static
RAM/SRAM),SRAM速度非常快,是目前读写最快的存储设备了,但是它也非常昂贵,所以只在要求很苛刻的地方使用,譬如CPU的一级缓冲,二级缓冲。另一种称为动态RAM(Dynamic
RAM/DRAM),DRAM保留数据的时间很短,速度也比SRAM慢,不过它还是比任何的ROM都要快,但从价格上来说DRAM相比SRAM要便宜很多,计算机内存就是DRAM的。

DRAM分为很多种,常见的主要有FPRAM/FastPage、EDORAM、SDRAM、DDR
RAM、RDRAM、SGRAM以及WRAM等,这里介绍其中的一种DDR RAM。DDR RAM(Date-Rate RAM)也称作DDR
SDRAM,这种改进型的RAM和SDRAM是基本一样的,不同之处在于它可以在一个时钟读写两次数据,这样就使得数据传输速度加倍了。这是目前电脑中用得最多的内存,而且它有着成本优势,事实上击败了Intel的另外一种内存标准-Rambus
DRAM。在很多高端的显卡上,也配备了高速DDR RAM来提高带宽,这可以大幅度提高3D加速卡的像素渲染能力。

ROM也有很多种,PROM是可编程的ROM,PROM和EPROM(可擦除可编程ROM)两者区别是,PROM是一次性的,也就是软件灌入后,就无法修改了,这种是早期的产品,现在已经不可能使用了,而EPROM是通过紫外光的照射擦出原先的程序,是一种通用的存储器。另外一种EEPROM是通过电子擦出,价格很高,写入时间很长,写入很慢。

举个例子,手机软件一般放在EEPROM中,我们打电话,有些最后拨打的号码,暂时是存在SRAM中的,不是马上写入通过记录(通话记录保存在EEPROM中),因为当时有很重要工作(通话)要做,如果写入,漫长的等待是让用户忍无可忍的。

FLASH存储器又称闪存,它结合了ROM和RAM的长处,不仅具备电子可擦出可编程(EEPROM)的性能,还不会断电丢失数据同时可以快速读取数据(NVRAM的优势),U盘和MP3里用的就是这种存储器。在过去的20年里,嵌入式系统一直使用ROM(EPROM)作为它们的存储设备,然而近年来Flash全面代替了ROM(EPROM)在嵌入式系统中的地位,用作存储Bootloader以及操作系统或者程序代码或者直接当硬盘使用(U盘)。

目前Flash主要有两种NOR Flash和NADN Flash。NOR
Flash的读取和我们常见的SDRAM的读取是一样,用户可以直接运行装载在NOR
FLASH里面的代码,这样可以减少SRAM的容量从而节约了成本。NAND
Flash没有采取内存的随机读取技术,它的读取是以一次读取一快的形式来进行的,通常是一次读取512个字节,采用这种技术的Flash比较廉价。用户不能直接运行NAND
Flash上的代码,因此好多使用NAND Flash的开发板除了使用NAND Flah以外,还作上了一块小的NOR
Flash来运行启动代码。

一般小容量的用NOR Flash,因为其读取速度快,多用来存储操作系统等重要信息,而大容量的用NAND FLASH,最常见的NAND
FLASH应用是嵌入式系统采用的DOC(Disk On Chip)和我们通常用的"闪盘",可以在线擦除。目前市面上的FLASH
主要来自Intel,AMD,Fujitsu和Toshiba,而生产NAND Flash的主要厂家有Samsung和Toshiba。


本文引用通告地址:http://jinren1010.spaces.eepw.com.cn/articles/trackback/item/15801


--
/**************************************/
Name: Xiong Feng
E-mail:linux0818@gmail.com
MSN:linux0818@hotmail.com
QQ:23562033
Address: GuangZhou.China
/**************************************/

C语言中的时间函数localtime和gmtime

localtime和gmtime这两个函数采用了time.h中的一个tm结构体:

struct tm
{
int tm_sec; /* Seconds. [0-60] (1 leap second) */
int tm_min; /* Minutes. [0-59] */
int tm_hour; /* Hours. [0-23] */
int tm_mday; /* Day. [1-31] */
int tm_mon; /* Month. [0-11] */
int tm_year; /* Year - 1900. */
int tm_wday; /* Day of week. [0-6] */
int tm_yday; /* Days in year.[0-365] */
int tm_isdst; /* DST. [-1/0/1]*/

#ifdef __USE_BSD
long int tm_gmtoff; /* Seconds east of UTC. */
__const char *tm_zone; /* Timezone abbreviation. */
#else
long int __tm_gmtoff; /* Seconds east of UTC. */
__const char *__tm_zone; /* Timezone abbreviation. */

#else
long int __tm_gmtoff; /* Seconds east of UTC. */
__const char *__tm_zone; /* Timezone abbreviation. */
#endif
};

这两个函数的原型为:

struct tm *localtime(const time_t *timep);

struct tm *gmtime(const time_t *timep);

具体实现为:

localtime.c

---------------------------------------------------------

#include <stdio.h>
#include <time.h>
void cur_time(void);

int main(int argc,char **argv)
{
cur_time();

return 0;
}

void cur_time(void)
{
char *wday[]={"星期天","星期一","星期二","星期三","星期四","星期五","星期六"};
time_t timep;
struct tm *p;
time(&timep);
p=localtime(&timep); /* 获取当前时间 */
printf("%d年%02d月%02d日",(1900+p->tm_year),(1+p->tm_mon),p->tm_mday);
printf("%s %02d:%02d:%02d\n",wday[p->tm_wday],p->tm_hour,p->tm_min,p->tm_sec);
}

---------------------------------------------------------

gcc localtime.c 后运行a.out结果为:

2007年12月26日星期三 11:07:15

gmtime.c

---------------------------------------------------------

#include <stdio.h>
#include <time.h>
void cur_time(void);

int main(int argc,char **argv)
{
cur_time();
return 0;
}

void cur_time(void)
{
char *wday[]={"星期天","星期一","星期二","星期三","星期四","星期五","星期六"};
time_t timep;
struct tm *p;
time(&timep);
p=gmtime(&timep); /* 获取当前时间 */
printf("%d年%02d月%02d日",(1900+p->tm_year),(1+p->tm_mon),p->tm_mday);
printf("%s %02d:%02d:%02d\n",wday[p->tm_wday],(p->tm_hour+8),p->tm_min,p->tm_sec);
}
-----------------------------------------------------------

gcc gmtime.c 后运行a.out结果为:

2007年12月26日星期三 11:08:34

GNU/Linux中解决多线程互斥同步问题

当解决多线程互斥同步的问题时,经常会有如下几个问题:

1. 在一个给定的问题中,需要多少个Mutex,多少个Semaphore?有什么规律?
2. 在对临界区加锁和等待信号量的顺序上有什么要求和规律?
3. 什么样操作适合放在临界区,什么样的不适合?

下面就生产者和消费者问题来分析一些这几个问题.
下面是一个简单的实现程序:
生产者向数组sharedArray中写入数据,而消费者从该数组中读取数据.

#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdlib.h>

#define MAXSIZE 5 /*共享缓冲区的大小*/

int sharedArray[MAXSIZE]; /*sharedArray是共享缓冲区*/
int curr=-1; /*curr是用来指定sharedArray当前存有数据的最大位置*/
/*注意,sharedArray和curr都属于共享数据*/

int empty=0;
int full=MAXSIZE;
pthread_mutex_t sharedMutex=PTHREAD_MUTEX_INITIALIZER; /*锁定临界区的mutex*/
sem_t waitNonEmpty, waitNonFull; /*等待"非空资源"和等待"非满资源"的semaphor*/

void * readData(void * whichone)
{
int data, position;
while (1){
sem_wait(&waitNonEmpty); /*是否有"非空资源"*/

pthread_mutex_lock(&sharedMutex); /*进入临界区*/
data = sharedArray[curr];
position = curr--;
printf ("%s read from the %dth: %d, \n",
(char*)whichone, position, data);
sem_post(&waitNonFull); /*生成一个"非满资源"*/
pthread_mutex_unlock(&sharedMutex); /*离开临界区*/

sleep(2); /*跟同步无关的费时操作*/
}
}

void * writeData(void * whichone)
{
int data, position;
while (1) {
data=(int)(10.0*random()/RAND_MAX); /*生成一个随机数据,注意是10.0而不是10*/
sem_wait(&waitNonFull); /*是否有"非满资源"*/

pthread_mutex_lock(&sharedMutex); /*进入临界区*/
position = ++curr;
sharedArray[curr]=data;
printf ("%s wrote to the %dth: %d, \n",
(char*)whichone, position, data);
sem_post(&waitNonEmpty); /*生成一个"非空资源"*/
pthread_mutex_unlock(&sharedMutex); /*离开临界区*/

sleep(1); /*跟同步无关的费时操作*/

}
}


int main (int argc, char** argv)
{
pthread_t consumer1, consumer2, producer1, producer2; /*两个生产者和两个消费者*/
sem_init(&waitNonEmpty, 0, empty); /*初始化信号量*/
sem_init(&waitNonFull, 0, full);
/*注意,本问题中的两种semaphore是有一定关系的,那就是它们的初始值之和应该等于共享缓冲区大小*/
/*即empty+full等于MAXSIZE*/

pthread_create (&consumer1, NULL, &readData, "consumer1");
pthread_create (&consumer2, NULL, &readData, "consumer2");
pthread_create (&producer1, NULL, &writeData, "producer1");
pthread_create (&producer2, NULL, &writeData, "producer2");
pthread_join (consumer1, NULL);
pthread_join (consumer2, NULL);
pthread_join (producer1, NULL);
pthread_join (producer2, NULL);
sem_destroy(&waitNonEmpty);
sem_destroy(&waitNonFull);

}


分析和说明:

1. 在一个给定的问题中,需要多少个Mutex,多少个Semaphore?有什么规律?

在本问题中,共需要一个Mutex和两个Semaphore.
其中,Mutex是用来锁定临界区的,以解决对共享数据的互斥访问问题(无论是对生成者还是对消费者);
我们共需要两个Semaphore,这是因为在本问题中共有两个稀缺资源.
第一种是"非空"这种资源,是在消费者之间进行竞争的.
第二种是"非满"这种资源,是在生产者之间进行竞争的.
所以,一般来说,需要锁定临界区,就需要Mutex;有几种稀缺资源就需要几个Semaphore.
对稀缺资源的分析不能想当然.稀缺资源不一定是指被共享的资源,很多时候是指线程会被阻塞的条件(除了要进临界区被阻塞外).
本例中,消费者会在缓冲区为空时被阻塞,所以"非空"是一种稀缺资源;
生产者会在缓冲区为满时被阻塞,所以"非满"也是一种稀缺资源.

2. 在对临界区加锁和等待信号量的顺序上有什么要求和规律?

这里要说两点:
第一,不要将等待信号量的语句放在被锁定的临界区内,这样会造成死锁.而且这也是很没有必要的.
比如,消费者在缓冲区没有数据的时候进入临界区,这样就会把临界区锁上,由于没有数据,消费者也会被锁上.
这时,任何生产者都会由于临界区被锁上而被block住,这样就造成了死锁.
第二,如果有多个Semaphore需要等待,那么每个线程中,最好对这多个信号量进行等待的顺序一致,
不然的话很容易造成死锁.

3. 什么样操作适合放在临界区,什么样的不适合?

一般来说,临界区中只放对共享数据进行访问的语句,这样会改善程序的性能.
很多时候,取出共享数据的副本后,对副本进行费时的各种操作就不需要放在临界区了.
比如,本例中的sleep语句就根本不需要放入临界区.
原文地址:http://www.yuanma.org/data/2007/1108/article_2883.htm

--
/**************************************/
Name: Xiong Feng
E-mail:linux0818@gmail.com
MSN:linux0818@hotmail.com
QQ:23562033
Address: GuangZhou.China
/**************************************/