linux笔记1

IO重定向
作者 codercjg 在 31 七月 2015, 3:22 下午

FILE*指针stdin、stdout和stderr连接在终端tty上,一般从键盘读取数据输入并把输出和错误消息写到屏幕。
stdin、stdout和stderr对应的文件描述符分别为0、1、2,可以把0、1、2连接到其他文件描述符,实现IO重定向。
有一个重要的原则:
当进程向内核申请文件描述符时,内核始终为进程分配最低可用文件描述符
方法1:close then open

include

include

void
main()

{

char
line[100];

int
fd;

fgets
(line, 100, stdin);

fputs
(line, stdout);

close(0);

fd = open(
"/etc/passwd"
, O_RDONLY);

if
(fd != 0)

{

printf
(
"error: %d\n"
, fd);

exit
(0);

}

fgets
(line, 100, stdin);

fputs
(line, stdout);

}

方法2:open…close…dup…close****方法3:open..dup2…close

#include 

include

void
main()

{

char
line[100];

int
fd;

fgets
(line, 100, stdin);

fputs
(line, stdout);

fd = open(
"/etc/passwd"
, O_RDONLY);

// close(0);

// dup(fd);

dup2(fd, 0);

close(fd);

fgets
(line, 100, stdin);

fputs
(line, stdout);

}

其实本质就是先关闭文件描述符0和tty输入(键盘)的连接,然后把0和要重定向的文件建立连接,
这个是通过内核始终为进程分配最低可用文件描述符这个特点实现的。

分类: Linux | 评论

信号驱动IO
作者 codercjg 在 30 七月 2015, 5:24 下午

信号驱动IO, 是指当文件或设备可读或可写时,内核发送信号SIGIO给进程,通知进程进行相应的读或写操作。
相关操作分三步:
1.signal()设置SIGIO信号处理函数
2.fcntl()设置SIGIO信号要发送的进程
3.fcntl()设置IO为O_ASYNC,设置文件或设备可读或可写时,内核发送信号给进程
例子:

include

include

include

include

include

int
over = 0;

void
signal_hanlder(
int
signo)

{

char
ch;

if
(signo == SIGIO)

{

fscanf
(stdin,
"%c"
, &ch);

fprintf
(stdout,
"input: %c\r\n"
, ch);

fflush
(stdout);

if
(ch ==
'Q'
)

{

over = 1;

endwin();

exit
(0);

}

}

}

void
main(
void
)

{

int
flag;

initscr();

signal
(SIGIO, signal_hanlder);

fcntl(0, F_SETOWN, getpid());

flag = fcntl(0, F_GETFL);

flag |= O_ASYNC;

fcntl(0, F_SETFL, flag);

while
(over == 0);

endwin();

}
setvbuf()设置流的缓冲区
作者 codercjg 在 24 七月 2015, 3:14 下午

setvbuf
用 法: *int setvbuf(FILE *stream, char buf, int type, unsigned size);
type : 期望缓冲区的类型:
_IOFBF(满缓冲):当缓冲区为空时,从流读入数据。或者当缓冲区满时,向流写入数 据。
_IOLBF(行缓冲):每次从流中读入一行数据或向流中写入一行数据。
_IONBF(无缓冲):直接从流中读入数据或直接向流中写入数据,而没有缓冲区。
size : 缓冲区内字节的数量。
注意:This function should be called once the file associated with the stream has already been opened but before any input or output operation has taken place.
意思是这个函数应该在打开流后,立即调用,在任何对该流做输入输出前

例子:

include

define BUF_SIZE 4

char
buf[BUF_SIZE];

void
main(
void
)

{

//setvbuf(stdout, buf, _IOFBF, BUF_SIZE);

//setvbuf(stdout, buf, _IONBF, BUF_SIZE);

setvbuf
(stdout, NULL, _IOLBF, 0);

fputs
(
"11"
, stdout);

fputs
(
"22"
, stdout);

fputs
(
"\n"
, stdout);

fputs
(
"33"
, stdout);

fputs
(
"44"
, stdout);

fputs
(
"55"
, stdout);

fputs
(
"\n"
, stdout);

fputs
(
"66"
, stdout);

fputs
(
"\n"
, stdout);

}

分类: Linux | 评论

getopt()获取命令行参数
作者 codercjg 在 24 七月 2015, 3:00 下午

getopt()用于从命令行获取参数,声明如下:

include ;

*int getopt(int argc, char * const argv[], const char optstring);
extern char *optarg;
extern int optind, opterr, optopt;
该函数的argc和argv参数通常直接从main()的参数直接传递而来。optstring是选项字母组成的字串。
如果该字串里的任一字符后面有一个冒号,那么这个选项就要求有参数,选项和参数之间用空格隔开,如gcc main.c -o main。
如果该字串里的任一字符后面有两个冒号,那么这个选项就要求有参数,选项之后就是参数, 如gcc main.c -o main -lpthread。

当给定getopt()命令参数的数量 (argc)、指向这些参数的数组 (argv) 和选项字串 (optstring) 后,getopt() 将返回第一个选项,并设置一些全局变量。使用相同的参数再次调用该函数时,它将返回下一个选项,并设置相应的全局变量。如果不再有可识别的选项,将返回 -1,此任务就完成了。
getopt() 所设置的全局变量包括:
char *optarg——当前选项参数字串(如果有)。
int optind——argv的当前索引值。当getopt()在while循环中使用时,循环结束后,剩下的字串视为操作数,在argv[optind]至argv[argc-1]中可以找到。
int opterr——这个变量非零时,getopt()函数为“无效选项”和“缺少参数选项,并输出其错误信息。
int optopt——当发现无效选项字符之时,getopt()函数或返回’?'字符,或返回’:'字符,并且optopt包含了所发现的无效选项字符。

例子如下:

include ;

include ;

void
main(
int
argc,
char
*argv[])

{

int
oc;

while
((oc=getopt(argc, argv,
"ab:c::"
))!=-1)

{

switch
(oc)

{

case
'a'
:

printf
(
"get a\n"
);

break
;

case
'b'
:

printf
(
"%s\n"
, optarg);

break
;

case
'c'
:

printf
(
"%s\n"
, optarg);

break
;

case
'?'
:

printf
(
"no argument\n"
);

break
;

default
:

printf
(
"usage error\n"
);

break
;

}

}

}

分类: Linux | 评论

select()用法
作者 codercjg 在 21 七月 2015, 3:32 下午

select()的功能是使进程阻塞一定时间,直到监视的文件描述符集合中有描述符可读、可写或出错。
函数原型:
int
select(
int
nfds,
struct
fd_set readfds,
struct
fd_set writefds,
struct
fd_set* exceptfds,
struct
timeval *timeout)

参数说明:
参数n为监视的最大文件描述符加1;
fd_set为文件描述符集合,下面的宏提供了处理这三种描述词组的方式:
FD_CLR(inr fd,fdset *set):用来清除描述词组set中相关fd 的位
FD_ISSET(int fd,fd_set *set):用来测试描述词组set中相关fd 的位是否为真
FD_SET(int fd,fd_set *set):用来设置描述词组set中相关fd的位:
FD_ZERO(fd_set *set):用来清除描述词组set的全部位
参数timeout为结构timeval,用来设置select()的等待时间,其结构定义如下:
struct
timeval{

timet tvsec;

timet tvusec;

};

1)如果timeout设为NULL,则表示select()一直阻塞,直到有描述符状态发生变化
2)如果timeout值为0,则select直接返回
3)如果timeout为某个特定值,则在特定时间内阻塞直到有描述符状态变化,如果这个时间内所有句柄状态都无变化,则select()超时返回0
返回值:
执行成功则返回文件描述词状态已改变的个数,如果返回0代表在描述词状态改变前已超过timeout时间;当有错误发生时则返回-1,错误原因存于errno
下面是一个用select()等待标准输入有数据的例子,标准输入的文件描述符为0, select()中参数n为0+1.

include

include

include

include

void
main(
void
)

{

fd_set inset;

struct
timeval timeout;

int
ret;

int
ch;

while
(1)

{

timeout.tv_sec = 2;

timeout.tv_usec = 0;

FD_ZERO(&inset);

FD_SET(0, &inset);

ret = select(0+1, &inset, NULL, NULL, &timeout);

if
(ret>0 && FD_ISSET(0, &inset))

{

ch =
getchar
();

printf
(
"%c\n"
, ch);

if
(ch ==
'q'
)

break
;

}
else
if
(ret==0)

{

printf
(
"time out\n"
);

}
else
{

printf
(
"error\n"
);

}

}

printf
(
"finish\n"
);

}

分类: Linux | 评论

linux线程实例
作者 codercjg 在 20 七月 2015, 3:06 下午

线程用法:

include

include

include

void

  • tfunc1(
    void
  • arg);

void

  • tfunc2(
    void
  • arg);

void
main(
void
)

{

pthread_t tid1, tid2;

void
*arg;

if
(pthread_create(&tid1, NULL, tfunc1, NULL))

{

printf
(
"create error\n"
);

}

printf
(
"child pid1 %lu\n"
, tid1);

sleep(1);

if
(pthread_create(&tid2, NULL, tfunc2, NULL))

{

printf
(
"create error\n"
);

}

if
(pthread_join(tid2,&arg))

{

printf
(
"join error\n"
);

}

printf
(
"return val:%d\n"
, *(
int
*)arg);

printf
(
"exit\n"
);

}

void

  • tfunc1(
    void
  • arg)

{

printf
(
"child thread \n"
);

pthread_exit(NULL);

}

int
a=1;

void

  • tfunc2(
    void
  • arg)

{

printf
(
"child thread \n"
);

sleep(5);

a = 2;

//pthread_exit(&a);

return
&a;

}

编译时要加上线程库 gcc -lpthread
互斥锁用法:

include

include

include

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

int
a = 1;

void

  • thread1(
    void
  • arg)

{

pthread_mutex_lock(&mutex);

a++;

sleep(1);

a--;

pthread_mutex_unlock(&mutex);

return
NULL;

}

void

  • thread2(
    void
  • arg)

{

sleep(1);

pthread_mutex_lock(&mutex);

printf
(
"a: %d\n"
, a);

pthread_mutex_unlock(&mutex);

return
NULL;

}

void
main(
void
)

{

pthread_t tid1, tid2;

pthread_create(&tid1, NULL, thread1, NULL);

pthread_create(&tid2, NULL, thread2, NULL);

pthread_join(tid1, NULL);

pthread_join(tid2, NULL);

}

信号量用法:

include

include

include

include

sem_t sem;

int
a = 1;

void

  • thread1(
    void
  • arg)

{

a++;

sleep(1);

a--;

sem_post(&sem);

return
NULL;

}

void

  • thread2(
    void
  • arg)

{

sleep(1);

sem_wait(&sem);

printf
(
"a: %d\n"
, a);

return
NULL;

}

void
main(
void
)

{

pthread_t tid1, tid2;

sem_init(&sem, 0, 0);

pthread_create(&tid1, NULL, thread1, NULL);

pthread_create(&tid2, NULL, thread2, NULL);

pthread_join(tid1, NULL);

pthread_join(tid2, NULL);

sem_destroy(&sem);

}

分类: Linux | 评论

Linux信号
作者 codercjg 在 17 七月 2015, 11:27 上午

信号一般由一个进程发给另一个进程(或自己),也可以由内核发送给一个进程。
例子如下:

include

include

include

static
void
signal_usr(
int
signal
)

{

if
(
signal
== SIGUSR1)

printf
(
"recv SIGUSR1\n"
);

else
if
(
signal
== SIGUSR2)

printf
(
"recv SIGUSR2\n"
);

else

printf
(
"recv unknown signal\n"
);

}

void
main()

{

if
(
signal
(SIGUSR1, signal_usr) == SIG_ERR)

printf
(
"can't catch SIGUSR1\n"
);

if
(
signal
(SIGUSR2, signal_usr) == SIG_ERR)

printf
(
"can't catch SIGUSR2\n"
);

while
(1)

pause();

}

SIGUSR1和SIGUSR2是用户自定义信号,通过ps -a命令可列出进程id为2913,通过kill -SIGUSR1 2913和kill -SIGUSR2 2913发送信号给该进程。
kill命令准确的说不是杀死对应的进程,而是向指定进程发送信号,而默认发送的信号是SIGTERM, 收到该信号后进程终止。

分类: Linux | 评论

你可能感兴趣的:(linux笔记1)