系統(tǒng)調(diào)用是操作系統(tǒng)提供給用戶的一組“特殊接口”。系統(tǒng)調(diào)用并非直接和程序員或系統(tǒng)管理員直接打交道,而是通過軟中斷的方式向內(nèi)核提交請求,從而獲取內(nèi)核函數(shù)的服務入口(系統(tǒng)調(diào)用表)。系統(tǒng)調(diào)用讓系統(tǒng)從用戶空間進入內(nèi)核空間內(nèi)運行,運行后將結(jié)果返回給應用程序(內(nèi)核態(tài)->用戶空間)。
成都創(chuàng)新互聯(lián)主要從事成都網(wǎng)站制作、網(wǎng)站建設、網(wǎng)頁設計、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務。立足成都服務洛川,10余年網(wǎng)站建設經(jīng)驗,價格優(yōu)惠、服務專業(yè),歡迎來電咨詢建站服務:13518219792
系統(tǒng)API
主要是通過C庫libc來實現(xiàn),程序員多采用這種方式與內(nèi)核交互,這些API通過系統(tǒng)調(diào)用來實現(xiàn)
系統(tǒng)命令
系統(tǒng)管理員采用系統(tǒng)命令與內(nèi)核交互,是一個可執(zhí)行文件,通過系統(tǒng)API及系統(tǒng)調(diào)用來實現(xiàn)
外殼程序
一系列系統(tǒng)命令和SHELL腳本共同組合成的程序。
-每個進程PCB結(jié)構(gòu)中有文件描述符指針,指向files_struct的文件描述符表,記錄每個進程打開的文件列表
-系統(tǒng)內(nèi)核不允許應用程序訪問進程的文件描述符表,只返回這些結(jié)構(gòu)的索引即文件描述符ID(File Description)給應用程序
-Linux系統(tǒng)中,應用程序通過這些文件描述符來實現(xiàn)讓內(nèi)核對文件的訪問
-每個進程能夠訪問的文件描述符是有限制的,通過#ulimit –n可以查看
標準輸入STDIN_FILENO
標準輸出STDOUT_FILENO
標準錯誤STDERR_FILENO
每個進程被加載后,默認打開0,1,2這三個文件描述符
-函數(shù)原型
int open(const char *path, int flags,mode_t mode);
-參數(shù)
path :文件的名稱,可以包含(絕對和相對)路徑
flags:文件打開模式
mode: 用來規(guī)定對該文件的所有者,文件的用戶組及系統(tǒng)中其他用戶的訪問權(quán)限,則文件權(quán)限為:mode&(~umask)
-返回值
打開成功,返回文件描述符;
打開失敗,返回-1
O_CREATE會產(chǎn)生特殊權(quán)限,需要設置訪問權(quán)限:
S_IRWXU等價于 S_IRUSR|S_IWUSR|S_IXUSR (文件所有者)
S_IRWXG 等價于 S_IRGRP|S_IWGRP|S_IXGRP (文件用戶組)
S_IRWXO 等價于 S_IROTH|S_IWOTH|S_IXOTH (文件其他用戶)
關(guān)閉文件close(將進程中fd對應的文件描述表結(jié)構(gòu)釋放):
函數(shù)原型:int close(int fd); //如果出現(xiàn)錯誤,返回-1;調(diào)用成功返回0
-函數(shù)原型:
int read(int fd, void *buf, size_t nbytes);
-參數(shù)
fd :想要讀的文件的文件描述符
buf: 指向內(nèi)存塊的指針,從文件中讀取來的字節(jié)放到這個內(nèi)存塊中
nbytes: 從該文件復制到buf中的字節(jié)個數(shù)
-返回值
如果出現(xiàn)錯誤,返回-1;
返回從該文件復制到規(guī)定的緩沖區(qū)中的字節(jié)數(shù)!
-函數(shù)原型:int write(int fd,void *buf,size_t nbytes);
-函數(shù)參數(shù):
fd :要寫入的文件的文件描述符
buf: 指向內(nèi)存塊的指針,從這個內(nèi)存塊中讀取數(shù)據(jù)寫入 到文件中
nbytes: 要寫入文件的字節(jié)個數(shù)
-返回值
如果出現(xiàn)錯誤,返回-1
如果寫入成功,則返回寫入到文件中的字節(jié)個數(shù)
練習:采用文件系統(tǒng)調(diào)用的方式,完成串口通訊配置文件的讀寫
配置文件serial.cfg如下:
要求:1、程序運行命令格式:
serialchat [-options];
[options]:
p-輸出打印serial.cfg各個配置項信息,格式:參數(shù)-----參數(shù)值;
s-進行菜單(有保存和退出)讓用戶設置;
f-指定配配置項設置,輸出各選項置文件名,并輸出各配置項信息
其他選項提示該程序用法幫助。
2、不支持serialchat運行兩次
3、如果無法找到配置文件,則提示運行失敗,原因:配置文件無法找到
代碼如下:
#include < stdio.h>
#include < string.h>
#include < sys/types.h>
#include < sys/stat.h>
#include < unistd.h>
#include < fcntl.h>
int icount = 0;
//去空格 '\0'
void rm_space(char *pStr)
{
char *pos = pStr;
pos = strchr(pStr,' ');
while(pos != NULL)
{
strcpy(pos,pos+1);
pos = strchr(pos,' ');
}
}
//去注釋 '#' '\n#'和中文,留下\n ... \r之間的數(shù)據(jù)
void rm_annotation(char *pStr)
{
icount++;
char *pos = pStr;
char *end = NULL;
if(icount == 1) //第一行有可能頂格
{
pos = strchr(pStr,'#');
}
else
{
pos = strstr(pStr,"\n#");
}
while(pos != NULL)
{
end = strchr(pos+1,'\n');
strcpy(pos,end);
pos = strstr(pStr,"\n#");
}
}
//輸出配置項信息
void printMsg(char *buf)
{
char key[20] = " ";
char value[20] = " ";
char line[50] = " ";
char *pos = buf;
char *end = NULL;
int flag = 0;
printf("配置項信息如下:\n");
pos = strchr(buf,'\n');
end = strchr(pos,'=');
while(end != NULL)
{
memset(key,0,sizeof(key));
memset(value,0,sizeof(value));
memcpy(key,pos+1,end - (pos + 1));
pos = end;
end = strchr(pos,'\r');
if(end == NULL) //if the final data
{
flag = 1;
break;
}
memcpy(value,pos+1,end - (pos + 1));
sprintf(line,"%s-----%s",key,value);
printf("%s\n",line);
pos = end + 1;
end = strchr(pos,'=');
}
if(flag)
{
end = strchr(pos,'\0');
memcpy(value,pos+1,end - (pos + 1));
sprintf(line,"%s-----%s",key,value);
printf("%s\n",line);
}
}
//修改配置文件 (傳入的buf是未經(jīng)處理的)
void updateFile(int fd,char *buf)
{
char *pos = buf;
char *end = NULL;
char key[20] = "";
char newvalue[20] = "";
int lse;
int count;
printf("請輸入配置參數(shù): ");
scanf("%s",key);
printf("請輸入配置參數(shù)的值: ");
scanf("%s",newvalue);
strcat(key,"=");
pos = strstr(buf,key);
if(pos == NULL)
{
printf("輸入?yún)?shù)不存在!");
return;
}
pos = pos + strlen(key);
while(*pos == ' ') //處理'='后面有空格的情況
{
pos = pos + 1;
}
end = strchr(pos,'\r');
if(end == NULL) //if the final data
{
end = strchr(pos,'\0');
}
//修改文件
lse = lseek(fd,pos-buf,SEEK_SET);
write(fd,newvalue,end-pos); //注意新舊值的長度
printf("修改成功!\n");
}
/*--------------------主函數(shù)---------------------*/
int main(int argc,char *argv[])
{
int fd;
int readByte = 0;
char buf[512] = "";
char option[3] = "";
char filename[20] = "";
int index;
int s_flag = 0;
int f_flag = 0;
struct flock lock = {0};
//判斷參數(shù)個數(shù)
if(argc !=2 && argc != 3)
{
printf("輸入格式有誤!\n");
return 1;
}
//打開配置文件
strcpy(option,argv[1]);
if(strcmp(option,"-f") == 0) //打開指定文件
{
if(argc != 3)
{
printf("輸入格式有誤!\n");
return 1;
}
f_flag = 1;
strcpy(filename,argv[2]);
fd = open(filename,O_RDWR,S_IRWXU|S_IRGRP);
}
else
{
fd = open("serial.cfg",O_RDWR,S_IRWXU|S_IRGRP);
}
if(fd == -1)
{
printf("運行失敗,無法找到配置文件!\n");
return 1;
}
//讀取配置文件
readByte = read(fd,buf,512);
if(readByte <= 0)
{
printf("讀文件失敗!\n");
return 1;
}
//判斷是否已經(jīng)加鎖
fcntl(fd,F_GETLK,&lock);
if(lock.l_type != F_UNLCK)
{
printf("文件已經(jīng)被上鎖!執(zhí)行錯誤\n");
return 1;
}
//上鎖
memset(&lock,0,sizeof(struct flock));
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = sizeof(buf);
lock.l_type =F_WRLCK;
if((fcntl(fd,F_SETLK,&lock)) == -1)
{
printf("設置寫鎖失??!\n");
return 1;
}
//操作
if(f_flag || strcmp(option,"-p") == 0) //打印配置信息
{
rm_space(buf);
rm_annotation(buf);
printMsg(buf);
}
else if(strcmp(option,"-s") == 0) //進行菜單
{
while(!s_flag)
{
printf("1.修改配置項\n2.退出\n請輸入選擇: ");
scanf("%d",&index);
switch(index)
{
case 1:
updateFile(fd,buf);
break;
case 2:
s_flag = 1;
break;
}
}
}
else
{
printf("serialchat用法:\n");
printf("\t命令格式:serialchat [-options]\n ");
printf("\t [options]: p-輸出打印serial.cfg各個配置項信息\n ");
printf("\t [options]: s-進行菜單\n ");
printf("\t [options]: f-指定配置文件\n ");
printf("\t [options]: 其他-查看幫助\n ");
}
//關(guān)閉文件
close(fd);
//釋放鎖
lock.l_type =F_UNLCK;
fcntl(fd,F_SETLK,&lock);
return 0;
}
運行結(jié)果:
1、 serialchat –p
2、 serialchat-s
3、 serialchat-f
4、 異常處理
5、 上鎖
終端1:
終端2: