『壹』 linux fopen返回NULL,errno為0,用perror輸出的是Success,求解釋。
你直接1:touch /home/1 創建一個文件;
2:vi 1;
3.輸入幾個字母abcde
4:wq//保存
fp = fopen( /home/1, "r");
if(fp==NULL) //如果失敗了
{
printf("錯誤!");
exit(1); //中止程序
}
看看打開能行么,可能是宏定義的問題。
errno 記錄系統的最後一次錯誤代碼。代碼是一個int型的值,在errno.h中定義的,你看到不一定是fopen失敗記錄的值。
手工,望採納!
『貳』 linux下 C語言perror、strerror函數的作用
void perror(const char *s);
perror ("open_port");
函數說明
perror()用 來 將 上 一 個 函 數 發 生 錯 誤 的 原 因 輸 出 到 標 准 設備 (stderr) 。參數 s 所指的字元串會先列印出,後面再加上錯誤原因字元串。此錯手困誤原因依照全局變數errno 的值來決定要輸出的字元串。 在庫函數中有個errno變數,每個errno值對應著以字元串族薯吵表示的錯誤類型。當你調用"某些"函數出錯時,該函數已經重新設置了errno的值。perror函數只是將你輸入的一些信息和現在的errno所對應的錯誤一兆侍起輸出。
範例:
運行結果:
@ubuntu:~/work/dev/test ./perrortest
error code = 2, error msg = No such file or directory
noexitfile: No such file or directory
『叄』 linux內核 perror 什麼作用
perror是用來輸出錯誤的租擾穗,如果某些函數調用不正確的話,調用perror會李閉先輸出錯誤號,然後輸出你在perror()參數中指定的內容。printf則是用來輸出內容的,內容弊卜由參數指定
『肆』 linux關於管道說法錯誤的是什麼
Linux關於管道 原創
2018-09-14 12:22:41
Gaodes
碼齡5年
關注
管道的概念
管道是Unix中棗鎮蔽最古老的進程間通信的形式。 我們把從一個進程連接到另一個進程的一個數據流稱為一個「管道」 我們通常把是把一個進程的輸出連接或「管接」(經過管道來連接)到另一個進程的輸入。
管道特點
管道是半雙工的,數據只能向一個方向流動;需要雙方通信時,需要建立起兩個管道 只能用於父子進程或者兄弟進程之間(具有親凳州緣關系的進程)進行通信;通常,一個管道由一個進程創建,然後該進程調用fork,此後父、子進程之間就可應用該管道。
pipe函數
包含頭文件<unistd.h> 功能:創建一無名管道 原型
int pipe(int file_descriptor[2]);
參數 file_descriptor:文件描述符數組,其中file_descriptor[0]表示讀端,file_descriptor[1]表示寫端 返回值:成功返回0,失敗返回錯誤代碼
示例代碼:
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<signal.h>
#include<string.h>
int main(int argc,char *argv[])
{
int fd[2];
printf("f[0]=%d,f[1]=%d\n",fd[0],fd[1]);
pipe(fd);
printf("f[0]=%d,f[1]=%d\n",fd[0],fd[1]);
char buf[1024]={0};
int fid = fork();
if(fid > 0)
{
read(fd[0],buf,1024);
printf("read data %s\n",buf);
}
else if(fid == 0)
{
write(fd[1],"helloworld",strlen("helloworld"));
}
else
{
perror("fork error");
}
return 0;
}
列印結果
管道讀寫規則:如果試圖從管道寫端旅塌讀取數據,或者向管道讀端寫入數據都將導致錯誤發生 當沒有數據可讀時,read調用就會阻塞,即進程暫停執行,一直等到有數據來到為止。 如果管道的另一端已經被關閉,也就是沒有進程打開這個管道並向它寫數據時,read調用就會阻塞
復制文件描述符p
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<signal.h>
int main()
{
int fd = p(1);
printf("file fd= %d\n",fd);
write(fd,"helloworld",strlen("helloworld"));
return 0;
}
列印結果:
1為輸入到終端
shell管道的實現
原理通過把發的fd[1]寫復制到shell的1(標准輸入),fd[0]復制到shell的2(標准輸出)
以下是代碼:
#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
#include<signal.h>
int main()
{
int fd[2];
char buf[1024] ={0};
pipe(fd);
int pid = fork();
if(pid > 0)
{
read(fd[0],buf,1024);
printf(buf);
}
else if(pid == 0)
{
p2(fd[1],1);
close(fd[0]);
close(fd[1]);
execlp("ls","ls","-al",NULL);
}
else
{
}
return 0;
}
實現結果:
popen函數
作用:允許一個程序把另外一個程序當作一個新的進程來啟 動,並能對它發送數據或接收數據
FILE* popen(const char *command, const char *open_mode);
command:待運行程序的名字和相應的參數 open_mode:必須是「r」或「w」 如果操作失敗,popen會返回一個空指針
以下代碼:
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>
int main()
{
FILE *file = popen("ls -al","r");
char buf[1024] = {0};
fread(buf,1,1024,file);
fclose(file);
FILE *wcfile = popen("wc","w");
fwrite(buf,1,strlen(buf),wcfile);
fclose(wcfile);
return 0;
}
代碼結果:
命名管道破裂測試
我們首先要知道命名管道,要讀段和寫段同時開啟,才能向文件讀寫數據。
貼上代碼來理解命名管道的規則
首先是讀端:
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<signal.h>
#include<string.h>
#include<fcntl.h>
int main(int argc,char *argv[])
{
printf("open before\n");
int fd = open("/home/gao/tmp/fifo",O_RDONLY);
printf("open after\n");
//休眠5秒,讀端退出
sleep(5);
return 0;
}
接下來是寫端:
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<signal.h>
#include<string.h>
#include<fcntl.h>
void handle(int signo)
{
printf("cat signale = %d\n",signo);
}
int main(int argc,char *argv[])
{
signal(SIGPIPE,handle);
printf("open before\n");
int fd = open("/home/gao/tmp/fifo",O_WRONLY);
printf("open after\n");
//命名管道規則,如果寫入讀斷被中斷,寫入會返回-1,並且管道會破裂,產生信號(SIGPIPE)
while(1)
{
int wrsize = write(fd,"helloworld",strlen("helloworld"));
printf("size data:%d\n",wrsize);
sleep(1);
}
}
執行寫端:
它在等待另一端的開啟,才能向裡面寫入數據
此時我們開啟讀端:
馬上可以看到寫段可以寫數據
而執行5秒後,我們可以看到寫的時候返回-1,並且獲取到管道破裂的信息(SIGPIPE)
所以這里就是我們所注意的點,當我們寫客戶端和伺服器進行管道傳輸的時候,如果客戶端一旦退出來,就會使管道破裂,所以我們必須通過捕捉信號,來避免這種事情發生。
『伍』 linux c 程序 運行出現 斷錯誤 小菜求助!
由於逗斗右括弧寫錯位置,導致山瞎磨fp=0,即神帆為空指針,再往下執行就錯了。因此:
if((fp=popen(cmd,"r")==NULL))
要改為
if((fp=popen(cmd,"r"))==NULL)
『陸』 Linux命令SYSTEM()啟動命令
system是一個使用簡單,設計復雜的程序。
它主要包含fork exec waitpid三個步驟。
下來我來還原樓主的錯誤:
程序A:
/* socksrv.c*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h> /* for struct sockaddr_in*/
#define BACKLOG 10
#define MYPORT 4000
int main()
{
char *addr;
int sockfd;
int new_fd;
struct sockaddr_in my_addr, their_addr;
int res;
int sin_size;
char *buf;
/* 取得套接字描述符*/
sockfd = socket(AF_INET, /* domain*/
SOCK_STREAM, /* type*/
0); /* protocol*/
if (sockfd == -1) {
perror("socket");
exit(1);
}
/* Init sockaddr_in */
my_addr.sin_family = AF_INET; /* 注意: 應使用主機位元組順序*/
my_addr.sin_port = htons(MYPORT); /* 注意: 應使用網路位元組順序*/
my_addr.sin_addr.s_addr = htonl(INADDR_ANY); /* 使用自己的 IP 地址 */
bzero(&(my_addr.sin_zero), 8); /* 結構的其餘的部分須置 0*/
/* 指定一個套接字使用的地址及埠*/
res = bind(sockfd, (struct sockaddr*)&my_addr, sizeof(struct sockaddr));
if (res == -1) {
perror("bind");
exit(1);
}
/* 監聽請求, 等待連接*/
res = listen(sockfd,
BACKLOG); /* 未經處理的連接請求隊列可容納的最大數目*/
if (res == -1) {
perror("listen");
exit(1);
}
system("./hello&");
/* 接受對方的連接請求, 建立連接,返回一個新的連接描述符.
* 而第一個套接字描述符仍在你的機器上原來的埠 listen()
*/
sin_size = sizeof(struct sockaddr_in);
new_fd = accept(sockfd, (void *)&their_addr, &sin_size);
buf = (char *)malloc(255);
if (buf == NULL) {
printf("malloc failed\n");
exit(1);
}
/* 接受對方發來的數據*/
res = recv(new_fd, buf, 255, 0);
if (res == -1) {
perror("recv()");
exit(1);
}
/* 關閉本次連接*/
close(new_fd);
/* 關閉系統監聽*/
close(sockfd);
printf("recv data:%s\n", buf);
free(buf);
return 0;
}
程序B:hello,在主程序中用system("./hello&)調用。
#include <stdlib.h>
int main(){
while(1){
sleep(1000);
}
return 0;
}
編譯後運行程序A。我們可以在其它終端窗口看到 ./A ./hello正在運行,netstat -a 看到,tcp 4000埠被 佔用。
我們用Ctrl+c中斷程序A模擬樓主的崩潰操作。
這時,再在其它終端窗口看看,./A沒有了。./hello還在運行。netstat -a看到。4000埠還在佔用。
這時再次運行./A,提示bind: Address already in use而退出。
情況就是這樣。
因為執行system時,系統會fork一個A的子進程,再去執行B.
當你的A崩潰以後,它的一個子進程實際上還在運行,它打開的埠,文件,等還在使用。
所以再次運行A時,由於自定的互斥機制而退出。
如:再次綁定埠時提示埠已在使用。
殺死B後,A的子進程結束,它的資源釋放,所以才能再次運行A。
我建議樓主使用exec系列函數來啟動B。
『柒』 Linux系統中的守護進程講解
守護進程daemon,是生存期較長的一種進程。它們常常在系統自舉時啟動,僅在系統關閉時才終止。因為它們沒有控制終端,所以說它們是在後台運行的。UNIX系統有很多守護進程,它們執行日常事務活動。
1、系統自舉
自舉(bootstrapping)一詞來自於人都是靠自身的自舉機構站立起來的這一思想。計算機必須具備自舉能力將自己所有的元件激活,以便能完成載入操作系統這一目的,然後再由操作系統承擔起那些單靠自舉代碼無法完成的更復雜的任務。
自舉只有兩個功能:加電自檢和磁碟引導。
加電自檢:當我們按下計算機電源開關時,頭幾秒鍾機器似乎什麼反應也沒有,其實,這時的計算機正在進行加電自檢,以斷定它的所有元件都在正確地工作。如果某個元件有故障,顯示器上就會出現報警提示信息(如果顯示器也不能正常工作,則以一串嘟嘟聲來報警)。由於大多數計算機工作非常可靠,加電自檢報警非常罕見。
磁碟引導:查找裝有操作系統的磁碟驅動器。從磁碟載入操作系統的原因有二,一是操作系統升級簡單容易,二是使用戶擁有選擇操作系統的自由。
當加電自檢和磁碟引導完成時,自舉操作就啟動一個讀寫操作系統文件和將它們復制到隨機存儲器中的過程,此時的機器才是真正意義上的計算機。計算機的啟動可以有冷啟動和熱啟動兩種方式 ,它們之間的差別是熱啟動不進行機器的自檢(機器本身配置的檢查與測試),當計算機在使用過程中由於某些原因造成死機時,可以對計算機進行熱啟動處理。
2、守護進程的概念
通過ps axj命令可以查看到守護進程:
參數a表示不僅列當前用戶的進程,也列出所有其他用戶的進程,參數x表示不僅列有控制終端的進程,也列出所有無控制終端的進程,參數j表示列出與作業控制相關的信息。
代碼如下:PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND 0 1 1 1 ? -1 Ss 0 0:01 /sbin/init 0 2 0 0 ? -1 S< 0 0:00 [kthreadd] 2 3 0 0 ? -1 S< 0 0:00 [migration/0] 2 4 0 0 ? -1 S< 0 0:00 [ksoftirqd/0]... 1 2373 2373 2373 ? -1 S<s 0 0:00 /sbin/udevd --daemon... 1 4680 4680 4680 ? -1 Ss 0 0:00 /usr/sbin/acpid -c /etc... 1 4808 4808 4808 ? -1 Ss 102 0:00 /sbin/syslogd -u syslog...
凡是TPGID一欄寫著-1的都是沒有控制終端的進程,也就是守護進程。在COMMAND一列用[]括起來的名字表示內核線程,這些線程在內核里創建,沒有用戶空間代碼,因此沒有程序文件名和命令行,通常採用以k開頭的名字,表示Kernel。init進程我們已經很熟悉了,udevd負責維護/dev目錄下的設備文件,acpid負責電源管理,syslogd負責維護/var/log下的日誌文件,可以看出,守護進程通常採用以d結尾的`名字,表示Daemon。 創建守護進程最關鍵的一步是調用setsid函數創建一個新的Session,並成為Session Leader。 例子: C/C++ Code復制內容到剪貼板 void daemonize(void) { pid_t pid; printf("into deamonizen"); if (pid=fork() < 0) { perror("fork"); exit(1); } else if (pid !=0) { exit(0); } setsid(); if (chdir("/") < 0) { perror("chdir"); exit(1); } close(0); open("/dev/null", O_RDWR); p2(0, 1); p2(0, 2); printf("out deamonizen"); }
3、編寫守護進程 在編寫守護進程程序時,需遵循一些基本規則:
(1)首先要做的是調用umask將文件模式創建屏蔽字設置為0。
(2)調用fork,然後使父進程退出。
(3)調用setsid以創建一個新會話。
(4)將當前工作目錄更改為根目錄。
(5)關閉不再需要的文件描述符。
(6)某些守護進程打開/dev/null使其具有文件描述符0、1和2,任何一個試圖讀標准輸入、寫標准輸出或標准出錯的庫常式都不會產生任何效果。 與守護進程有關的一個問題是如何處理出錯消息,需要有一個集中的守護進程出錯記錄設施,這就是syslogd進程。
4、守護進程慣例 為了正常運作,某些守護進程實現為單實例的,有就是在任一時刻只運行該守護進程的一個副本。文件鎖和記錄鎖機制是一種方法的基礎,該方法用來保證一個守護進程只有一個副本在運行。
在UNIX系統中,守護進程遵循下列公共慣例:
(1)若守護進程使用鎖文件,那麼該文件通常存放在/var/run目錄中。鎖文件的名字通常是name.pid,name是該守護進程或服務的名字。
(2)若守護進程支持配置選項,那麼配置文件通常存放在/etc目錄中。配置文件的名字通常是name.conf。
(3)守護進程可用命令行啟動,但通常它們是由系統初始化腳本啟動的。
(4)若一守護進程有一配置文件,那麼當該守護進程啟動時,它讀該文件,但在此之後一般就不會再查看它。
『捌』 LinuxC語言頭裡面的ERROR函數怎麼使用
errno會返回一個數字,每個數字代表一個錯誤類型。詳細的可以查看頭文件。/usr/include/asm/errno.h
如何把errno的數字轉換成相應的文字說明?
方式一:可以使用strerrno函數
char
*strerror(int
errno)
使用方式如下:
fprintf(stderr,"error
in
CreateProcess
%s,
Process
ID
%d
",strerror(errno),processID)
將錯誤代碼轉換為字元串錯誤信息,可以將該字元串和其它的信息組合輸出到用戶界面。
註:假設processID是一個已經獲取了的整形ID
方式二:使用perror函數
void
perror(const
char
*s)
函數說明
perror
(
)用來將上一個函數發生錯誤的原因輸出到標准錯誤(stderr),參數s
所指的字元串會先列印出,後面再加上錯誤原因
字元串。此錯誤原因依照全局變數
errno
的值來決定要輸出的字元串。
另外並不是所有的c函數調用發生的錯誤信息都會修改errno。例如gethostbyname函數。
errno是否是線程安全的?
errno是支持線程安全的,而且,一般而言,編譯器會自動保證errno的安全性。
我們看下相關頭文件
/usr/include/bits/errno.h
會看到如下內容:
#
if
!defined
_LIBC
||
defined
_LIBC_REENTRANT
/*
When
using
threads,
errno
is
a
per-thread
value.
*/
#
define
errno
(*__errno_location
())
#
endif
#
endif
/*
!__ASSEMBLER__
*/
#endif
/*
_ERRNO_H
*/
也就是說,在沒有定義__LIBC或者定義_LIBC_REENTRANT的時候,errno是多線程/進程安全的。
為了檢測一下你編譯器是否定義上述變數,不妨使用下面一個簡單程序。
#include
<stdio.h>
#include
<errno.h>
int
main(
void
)
{
#ifndef
__ASSEMBLER__
printf(
"Undefine
__ASSEMBLER__/n"
);
#else
printf(
"define
__ASSEMBLER__/n"
);
#endif
#ifndef
__LIBC
printf(
"Undefine
__LIBC/n"
);
#else
printf(
"define
__LIBC/n"
);
#endif
#ifndef
_LIBC_REENTRANT
printf(
"Undefine
_LIBC_REENTRANT/n"
);
#else
printf(
"define
_LIBC_REENTRANT/n"
);
#endif
return
0;
}
『玖』 linux 程序運行錯誤 perror輸出之後 前面的printf輸出在顯示器上也沒有了嗎
不會的 perror對比printf 無非就是多了一個錯誤原因
『拾』 Linux, rmdir系統調用後perror顯示錯誤「illegal seek」, 什麼意思
你是在寫一段代碼?然後執行過後,出現的,那個報錯提示?圖片看的不是很清楚!```system在成功執行時會返回0,在失敗時會睜槐敗返回1, 這樣明茄的話,system語句則應該為:悉顫
system($cmd)==0 or die $!;