int printf(const char *fmt, ...); // = fprintf(stdout, fmt, ...) int scanf(const char *fmt, ...); // = fscanf(stdin, fmt, ...) int fprintf(FILE *stream, const char *fmt, ...); int fscanf(FILE *stream, const char *fmt, ...); int sprintf(char *str, const char *fmt, ...); // 寫入字串緩衝區 int sscanf(const char *str, const char *fmt, ...); // 從字串讀取
f* 系列操作檔案串流,s* 系列操作記憶體字串。
核心為每進程維護開啟檔案表,描述符為小正整數(0-1023,0/1/2 已佔用)。常用函式:open/creat/close/read/write/ftruncate/lseek/fsync/fstat/fchmod/flock/fcntl/dup/dup2/select/ioctl。
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int open(const char *path, int flags); // flags: O_RDONLY/O_WRONLY/O_CREAT 等 int open(const char *path, int flags, mode_t mode); // 帶權限模式 // 失敗回傳 -1,flags/mode 為位元遮罩組合
#include <unistd.h> ssize_t read(int fd, void *buf, size_t count); // 讀至 buf,成功回傳位元組數,EOF 0,錯誤 -1 ssize_t write(int fd, const void *buf, size_t count); // 從 buf 寫入 // fd=1 寫標準輸出,fd=0 讀標準輸入
#include <sys/stat.h> int stat(const char *path, struct stat *buf); // 透過路徑取得 int fstat(int fd, struct stat *buf); // 透過描述符取得 // 成功 0,失敗 -1(errno 存錯誤碼),man stat 查結構體欄位
#include <sys/select.h> #include <sys/time.h> int select(int maxfd, fd_set *readset, fd_set *writeset, fd_set *exceptset, struct timeval *timeout); // 回傳:就緒描述符數、0(超時)、-1(錯誤) // maxfd: 最大描述符+1;timeout: NULL=永久等待,0=非阻塞輪詢
fd_set 操作巨集:FD_ZERO 清空、FD_SET 加入、FD_CLR 移除、FD_ISSET 測試。使用流程:初始化集合 → select 等待 → 輪詢 FD_ISSET 處理就緒描述符 → FD_CLR 清理。
struct timeval { long tv_sec; long tv_usec; };
fdopenFILE *fdopen(int fildes, const char *mode);
將現有描述符(來自 open/pipe/socket 等)關聯標準 I/O 串流。mode 必須與原描述符讀寫模式一致。常用於管道、網路通訊通道無法用 fopen 開啟的情況。
popen/pcloseFILE *popen(const char *command, const char *mode); // mode: "r" 讀命令輸出, "w" 寫命令輸入 int pclose(FILE *fp);
範例 1:讀取命令輸出
FILE *fp = popen("cat /etc/profile", "r");
char buf[512];
while (fgets(buf, sizeof(buf), fp)) puts(buf);
pclose(fp);
範例 2:寫入命令輸入
char buf[] = "aaa bbb ccc";
FILE *fp = popen("wc -w", "w");
fwrite(buf, sizeof(buf), 1, fp);
pclose(fp);
pipe()int pipe(int fds[2]); // fds[0] 讀端, fds[1] 寫端,成功 0,失敗 -1 // 必須有父子關係繼承描述符,進程結束管道自動消失
父寫子讀範例
int fds[2]; pipe(fds);
if (fork() == 0) { // 子進程
close(fds[1]); sleep(2);
read(fds[0], buf, sizeof(buf)); puts(buf);
close(fds[0]); exit(0);
} else { // 父進程
close(fds[0]);
write(fds[1], "hello", 6);
waitpid(-1, NULL, 0);
close(fds[1]); exit(0);
}
伺服器端:永久 FIFO 僅讀 → select 監聽上線/訊息/下線 → 廣播訊息給所有在線客戶端。
客戶端:向伺服器 FIFO 寫入 PID → 建立雙向 FIFO → fork 父進程寫/子進程讀。
完整代碼請參考原文(含 sever.c 與 myclient.c 實現)。