linux高階程式設計day05 筆記 (轉)
阿新 • • 發佈:2018-12-27
一.IO與檔案目錄管理
1.pread=lseek+read
pread讀取以後不改變讀寫位置
2.mmap對映:
/proc/${pid}/mem 無法對映
3.IO的有效使用者與實際使用者
預設情況:實際使用者與有效使用者一致。
實際使用者:執行使用者
有效使用者:許可權使用者
uid_t getuid()
uid_t geteuid()
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
main()
{
int fd;
char buf[1025];
int r;
printf("real user:%d\n",getuid());
printf("effective user:%d\n",geteuid());
fd=open("../day05",O_RDWR);
if(fd==-1) printf("open error:%m\n"),exit(-1);
bzero(buf,1024);
while((r=read(fd,buf,1024))>0)
{
buf[r]=0;
printf("%s",buf);
}
close(fd);
}
#include <stdio.h>
#include <unistd.h>
#include <dirent.h>
#include <stdlib.h>
main()
{
DIR *d;
struct dirent *de;
//開啟目錄 d=opendir("/home");
if(d==NULL)
{
printf("opendir:%m\n");
exit(-1);
}
// 迴圈讀取目錄 while(de=readdir(d))
{
printf("%s,\t%d\n",de->d_name,de->d_type);
}
//關閉目錄 closedir(d);
}int scandir(const char*dirname,//目錄名 struct dirent***namelist,//返回目錄列表 int (*)(struct dirent*),//回撥函式,過濾目錄
//NULL:不過濾 int (*)(struct dirent*,struct dirent*)//排序返回目錄
//NULL:不排序 ); 返回:
>=0 目錄個數
=-1 目錄查詢失敗
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
int mysort(const void*d1,const void*d2)
{
return -alphasort(d1,d2);
}
int myfilter(const struct dirent*d)
{
if(memcmp(d->d_name,".",1)==0)
{
return 0;
}
else
{
return -1;
}
}
main()
{
struct dirent**d;
int r;
int i;
r=scandir("/home",&d,myfilter,mysort);
printf("子目錄個數:%d\n",r);
for(i=0;i<r;i++)
{
printf("%s\n",d[i]->d_name);
}
/*
while(*d)
{
printf("%s\n",(*d)->d_name);
d++;
}
*/
}二.程序
1.什麼是程序
執行的程式:程式碼->資源->CPU
程序有很多資料維護:程序狀態/程序的屬性
所有程序屬性採用的結構體維護->樹形資料結構
ps 察看程序常見屬性
top 察看系統程序執行狀況
pstree(ptree)
kill 向程序傳送訊號
kill -s 訊號 程序id
kill -l 顯示程序能接受的所有訊號
知道程序有很多屬性:ps可以察看的屬性
2.建立程序
1.程式碼?載入到記憶體?分配CPU時間片?
程式碼由獨立的程式存在.
2.程序有關的建立函式
int system(const char*filename);
建立獨立程序,擁有獨立的程式碼空間,記憶體空間
等待新的程序執行完畢,system才返回.(阻塞)
案例:
使用system呼叫一個程式。
觀察程序ID。
觀察阻塞。
新的返回值與system返回值有關係。
任何程序的返回值:不要超過255。一個位元組。
system的返回值中8-15位存放返回碼
練習:
使用system呼叫"ls -l"。"ls -l home"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
main()
{
int r;
printf("%d\n",getpid());
r=system("ls -l ");
//printf("%d\n",r>>8&255); printf("%d\n",WEXITSTATUS(r));
system("clear");
} 子程序:被建立程序。
父程序:相對被建立者的程序。
popen:建立子程序
在父子程序之間建立一個管道
案例:
使用popen呼叫ls -l,並且建立一個管道讀取輸出
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
main()
{
char buf[1024];
FILE *f=popen("ls -l","r");
int fd=fileno(f);
int r;
printf("=============\n");
while((r=read(fd,buf,1024))>0)
{
buf[r]=0;
printf("::%s\n",buf);
}
printf("=============\n");
close(fd);
pclose(f);
} exec系列函式:
execl execlp
替換當前程序的程式碼空間中的程式碼資料
函式本身不建立新的程序。
int execl(const char*path,const char *arg,....);
第一個引數:替換的程式,
第二個引數....:命令列
命令列格式:命令名 選項引數
命令列結尾必須空字串結尾
案例:
使用exec執行一個程式。
體會:*是否建立新的程序?沒有
*體會execl的引數的命令列的格式
*體會execl與execlp的區別(execl只當前路徑)
execlp 使用系統的搜尋路徑
*體會execl替換當前程序的程式碼
#include <stdio.h>
#include <unistd.h>
int main()
{
//printf("main:%d\n",getpid()); int r=execlp("ls","ls","-l",NULL);
printf("結束%d\n",r);
return 0;
} fork
pid_t fork();
//1.建立程序
//2.新程序的程式碼是什麼:克隆父程序的程式碼
而且克隆了執行的位置.
//3.在子程序不呼叫fork所以返回值=0;
//4.父子程序同時執行.#include <stdio.h>
#include <unistd.h>
int main()
{
int pid;
printf("建立程序前!\n");
pid=fork();
if(pid==0)
{
while(1)
{
printf("子程序\n");
sleep(1);
}
}
else
{
while(1)
{
printf("父程序\n");
sleep(1);
}
}
return 0;
} 3.應用程序
使用fork建立新的程序有什麼應用價值呢?
使用fork實現多工.(Unix系統本身是不支援執行緒)
1.程序
2.執行緒
3.訊號
4.非同步
5.程序池與執行緒池
案例:
使用程序建立實現多工
1.UI
2.建立多工框架
3.分別處理不同的任務
#include <curses.h>
#include <unistd.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
WINDOW *wtime,*wnumb;
main()
{
initscr();
wtime=derwin(stdscr,3,10,0,(COLS-10));
wnumb=derwin(stdscr,3,11,(LINES-3)/2,(COLS-11)/2);
box(wtime,0,0);
box(wnumb,0,0);
refresh();
wrefresh(wtime);
wrefresh(wnumb);
if(fork())
{//show time time_t tt;
struct tm *t;
while(1)
{
time(&tt);
t=localtime(&tt);
mvwprintw(wtime,1,1,"%02d:%02d:%02d",
t->tm_hour,t->tm_min,t->tm_sec);
refresh();
wrefresh(wtime);
wrefresh(wnumb);
sleep(1);
}
}
else
{//show number int num=0;
int i;
while(1)
{
num=0;
for(i=0;i<7;i++)
{
num=num*10+rand()%10;
}
mvwprintw(wnumb,1,2,"%07d",num);
refresh();
wrefresh(wtime);
wrefresh(wnumb);
usleep(10000);
}
}
endwin();
} 4.理解程序
1.父子程序的關係
獨立的兩個程序
互為父子關係
2.問題:
2.1.父程序先結束?
子程序就依託根程序init:孤兒程序
孤兒程序沒有任何危害.
2.2.子程序先結束?
子程序會成為僵死程序.
僵死程序不佔用記憶體,CPU.但在程序任務管理樹佔用一個節點.
僵死程序造成程序名額資源浪費.
所以處理僵死程序.
3.僵死程序使用wait回收
4.父程序怎麼知道子程序退出?
子程序結束通常會向父程序傳送一個訊號
SIGCHLD
5.父程序處理子程序退出訊號
signal(int sig,void(*fun)(int));
向系統註冊:只要sig訊號發生,系統停止程序,並呼叫函式fun
當函式執行完畢,繼續原來程序
5.1.實現處理函式
5.2.使用signal邦定訊號與函式
僵死程序回收案例:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <signal.h>
void deal(int s)
{
int status;
wait(&status);
printf("回收中..\n");
sleep(5);
printf("回收完畢:%d!\n",WEXITSTATUS(status));
}
main()
{
if(fork()==0)
{
//child printf("child!\n");
sleep(20);
printf("退出!\n");
exit(88);
}
else
{
//parent signal(17,deal);
while(1)
{
printf("parent!\n");
sleep(1);
} //sleep(20000); 這裡父程序也會被sigchld訊號喚醒,在執行完訊號處理程式後,繼續向下執行
printf("parent!\n");
}
} 6.父子程序的資源訪問
6.1.記憶體資源
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <signal.h>
#include <sys/mman.h>
main()
{
/*
int *a=mmap(0,4,PROT_READ|PROT_WRITE,
MAP_ANONYMOUS|MAP_PRIVATE,0,0);
*/
int *a=sbrk(4);
*a=40;
if(fork())
{
printf("parent:%d\n",*a);
*a=90;
}
else
{
printf("child:%d\n",*a);
sleep(3);
printf("child:%d\n",*a);
}
}6.2.檔案資源
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <signal.h>
#include <sys/mman.h>
#include <fcntl.h>
main()
{
if(fork())
{
int fd=open("test.txt",O_RDWR);
printf("%d\n",fd);
sleep(5);
write(fd,"Killer",6);
close(fd);
}
else
{
int fd=open("test.txt",O_RDWR);
printf("%d\n",fd);
write(fd,"Clinton",7);
sleep(8);
close(fd);
}
}
1.pread=lseek+read
pread讀取以後不改變讀寫位置
2.mmap對映:
/proc/${pid}/mem 無法對映
3.IO的有效使用者與實際使用者
預設情況:實際使用者與有效使用者一致。
實際使用者:執行使用者
有效使用者:許可權使用者
uid_t getuid()
uid_t geteuid()
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
main()
{
int
char buf[1025];
int r;
printf("real user:%d\n",getuid());
printf("effective user:%d\n",geteuid());
fd=open("../day05",O_RDWR);
if(fd==-1) printf("open error:%m\n"),exit(-1);
bzero(buf,1024);
while((r=read(fd,buf,1024))>0)
{
buf[r]=0;
printf("%s",buf);
}
close(fd);
}
4.目錄相關函式
chdir 切換目錄
mkdir 建立目錄
rmdir 刪除目錄
unlink 刪除檔案
umask 設定檔案許可權遮蔽位
stat 檔案目錄狀態
5.目錄的遍歷
opendir系列函式
readdir
closedir
seekdir
dirfd
#include <stdio.h>
#include <unistd.h>
#include <dirent.h>
#include <stdlib.h>
main()
{
DIR *d;
struct dirent *de;
//開啟目錄 d=opendir("/home");
if(d==NULL)
{
printf("opendir:%m\n");
exit(-1);
}
//
{
printf("%s,\t%d\n",de->d_name,de->d_type);
}
//關閉目錄 closedir(d);
}int scandir(const char*dirname,//目錄名 struct dirent***namelist,//返回目錄列表 int (*)(struct dirent*),//回撥函式,過濾目錄
//NULL:不過濾 int (*)(struct dirent*,struct dirent*)//排序返回目錄
//NULL:不排序 ); 返回:
>=0 目錄個數
=-1 目錄查詢失敗
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
int mysort(const void*d1,const void*d2)
{
return -alphasort(d1,d2);
}
int myfilter(const struct dirent*d)
{
if(memcmp(d->d_name,".",1)==0)
{
return 0;
}
else
{
return -1;
}
}
main()
{
struct dirent**d;
int r;
int i;
r=scandir("/home",&d,myfilter,mysort);
printf("子目錄個數:%d\n",r);
for(i=0;i<r;i++)
{
printf("%s\n",d[i]->d_name);
}
/*
while(*d)
{
printf("%s\n",(*d)->d_name);
d++;
}
*/
}二.程序
1.什麼是程序
執行的程式:程式碼->資源->CPU
程序有很多資料維護:程序狀態/程序的屬性
所有程序屬性採用的結構體維護->樹形資料結構
ps 察看程序常見屬性
top 察看系統程序執行狀況
pstree(ptree)
kill 向程序傳送訊號
kill -s 訊號 程序id
kill -l 顯示程序能接受的所有訊號
知道程序有很多屬性:ps可以察看的屬性
2.建立程序
1.程式碼?載入到記憶體?分配CPU時間片?
程式碼由獨立的程式存在.
2.程序有關的建立函式
int system(const char*filename);
建立獨立程序,擁有獨立的程式碼空間,記憶體空間
等待新的程序執行完畢,system才返回.(阻塞)
案例:
使用system呼叫一個程式。
觀察程序ID。
觀察阻塞。
新的返回值與system返回值有關係。
任何程序的返回值:不要超過255。一個位元組。
system的返回值中8-15位存放返回碼
練習:
使用system呼叫"ls -l"。"ls -l home"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
main()
{
int r;
printf("%d\n",getpid());
r=system("ls -l ");
//printf("%d\n",r>>8&255); printf("%d\n",WEXITSTATUS(r));
system("clear");
} 子程序:被建立程序。
父程序:相對被建立者的程序。
popen:建立子程序
在父子程序之間建立一個管道
案例:
使用popen呼叫ls -l,並且建立一個管道讀取輸出
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
main()
{
char buf[1024];
FILE *f=popen("ls -l","r");
int fd=fileno(f);
int r;
printf("=============\n");
while((r=read(fd,buf,1024))>0)
{
buf[r]=0;
printf("::%s\n",buf);
}
printf("=============\n");
close(fd);
pclose(f);
} exec系列函式:
execl execlp
替換當前程序的程式碼空間中的程式碼資料
函式本身不建立新的程序。
int execl(const char*path,const char *arg,....);
第一個引數:替換的程式,
第二個引數....:命令列
命令列格式:命令名 選項引數
命令列結尾必須空字串結尾
案例:
使用exec執行一個程式。
體會:*是否建立新的程序?沒有
*體會execl的引數的命令列的格式
*體會execl與execlp的區別(execl只當前路徑)
execlp 使用系統的搜尋路徑
*體會execl替換當前程序的程式碼
#include <stdio.h>
#include <unistd.h>
int main()
{
//printf("main:%d\n",getpid()); int r=execlp("ls","ls","-l",NULL);
printf("結束%d\n",r);
return 0;
} fork
pid_t fork();
//1.建立程序
//2.新程序的程式碼是什麼:克隆父程序的程式碼
而且克隆了執行的位置.
//3.在子程序不呼叫fork所以返回值=0;
//4.父子程序同時執行.#include <stdio.h>
#include <unistd.h>
int main()
{
int pid;
printf("建立程序前!\n");
pid=fork();
if(pid==0)
{
while(1)
{
printf("子程序\n");
sleep(1);
}
}
else
{
while(1)
{
printf("父程序\n");
sleep(1);
}
}
return 0;
} 3.應用程序
使用fork建立新的程序有什麼應用價值呢?
使用fork實現多工.(Unix系統本身是不支援執行緒)
1.程序
2.執行緒
3.訊號
4.非同步
5.程序池與執行緒池
案例:
使用程序建立實現多工
1.UI
2.建立多工框架
3.分別處理不同的任務
#include <curses.h>
#include <unistd.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
WINDOW *wtime,*wnumb;
main()
{
initscr();
wtime=derwin(stdscr,3,10,0,(COLS-10));
wnumb=derwin(stdscr,3,11,(LINES-3)/2,(COLS-11)/2);
box(wtime,0,0);
box(wnumb,0,0);
refresh();
wrefresh(wtime);
wrefresh(wnumb);
if(fork())
{//show time time_t tt;
struct tm *t;
while(1)
{
time(&tt);
t=localtime(&tt);
mvwprintw(wtime,1,1,"%02d:%02d:%02d",
t->tm_hour,t->tm_min,t->tm_sec);
refresh();
wrefresh(wtime);
wrefresh(wnumb);
sleep(1);
}
}
else
{//show number int num=0;
int i;
while(1)
{
num=0;
for(i=0;i<7;i++)
{
num=num*10+rand()%10;
}
mvwprintw(wnumb,1,2,"%07d",num);
refresh();
wrefresh(wtime);
wrefresh(wnumb);
usleep(10000);
}
}
endwin();
} 4.理解程序
1.父子程序的關係
獨立的兩個程序
互為父子關係
2.問題:
2.1.父程序先結束?
子程序就依託根程序init:孤兒程序
孤兒程序沒有任何危害.
2.2.子程序先結束?
子程序會成為僵死程序.
僵死程序不佔用記憶體,CPU.但在程序任務管理樹佔用一個節點.
僵死程序造成程序名額資源浪費.
所以處理僵死程序.
3.僵死程序使用wait回收
4.父程序怎麼知道子程序退出?
子程序結束通常會向父程序傳送一個訊號
SIGCHLD
5.父程序處理子程序退出訊號
signal(int sig,void(*fun)(int));
向系統註冊:只要sig訊號發生,系統停止程序,並呼叫函式fun
當函式執行完畢,繼續原來程序
5.1.實現處理函式
5.2.使用signal邦定訊號與函式
僵死程序回收案例:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <signal.h>
void deal(int s)
{
int status;
wait(&status);
printf("回收中..\n");
sleep(5);
printf("回收完畢:%d!\n",WEXITSTATUS(status));
}
main()
{
if(fork()==0)
{
//child printf("child!\n");
sleep(20);
printf("退出!\n");
exit(88);
}
else
{
//parent signal(17,deal);
while(1)
{
printf("parent!\n");
sleep(1);
} //sleep(20000); 這裡父程序也會被sigchld訊號喚醒,在執行完訊號處理程式後,繼續向下執行
printf("parent!\n");
}
} 6.父子程序的資源訪問
6.1.記憶體資源
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <signal.h>
#include <sys/mman.h>
main()
{
/*
int *a=mmap(0,4,PROT_READ|PROT_WRITE,
MAP_ANONYMOUS|MAP_PRIVATE,0,0);
*/
int *a=sbrk(4);
*a=40;
if(fork())
{
printf("parent:%d\n",*a);
*a=90;
}
else
{
printf("child:%d\n",*a);
sleep(3);
printf("child:%d\n",*a);
}
}6.2.檔案資源
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <signal.h>
#include <sys/mman.h>
#include <fcntl.h>
main()
{
if(fork())
{
int fd=open("test.txt",O_RDWR);
printf("%d\n",fd);
sleep(5);
write(fd,"Killer",6);
close(fd);
}
else
{
int fd=open("test.txt",O_RDWR);
printf("%d\n",fd);
write(fd,"Clinton",7);
sleep(8);
close(fd);
}
}
案例:
說明:子程序克隆整個記憶體區域,
但記憶體區域指向不同的物理空間
儘管克隆,但記憶體獨立. 不能相互訪問.
多程序實現多工,程序之間的資料交換是大問題.(IPC)
Inter-Process Commucation
對映記憶體:
MAP_SHARED:對映到同一實體記憶體
MAP_PRIVATE:對映到不同的實體記憶體.
案例:
兩個程序之間,檔案描述符號指向的是同一個檔案核心物件.
回顧:
1.目錄遍歷
2.程序建立system popen exec fork
3.僵死程序出現的條件以及回收
4.利用多程序實現簡單的多工
5.理解程序的克隆.
作業:
1.使用兩個程序,查詢素數:(多工)
A程序查詢1-5000
B程序查詢5001-10000
把素數寫入檔案.
2.寫一個多工:(兩個程序資料共享)
A.程序查詢素數,放入mmap分配的空間
B.程序把mmap的資料取出來,判定兩個資料是否相鄰.
相鄰就列印這兩個素數.
思考:
3.使用opendir/readir遍歷指定目錄下的所有*.c檔案.
scandir
明天:
一.程序的基本控制
二.程序的高階控制-訊號