# 附录A Wrapper 库参考 ## 概述 Wrapper 库是课程提供的 C 语言工具库,封装了课程用到的所有系统调用。每个 Wrapper 函数在内部调用对应的系统调用并检查返回值,出错时自动打印错误信息并终止程序,从而简化实验代码的编写。 源文件组成: | 文件 | 说明 | |------|------| | `wrapper.h` | 头文件,包含所有函数声明、类型定义和常量 | | `wrapper.c` | Wrapper 函数实现 | | `ptwrapper.c` | POSIX 线程相关 Wrapper 函数 | | `libwrapper.a` | 预编译的静态库 | ## 编译与使用 ```bash # 方法一:链接静态库 gcc -o program program.c -L. -lwrapper # 方法二:链接静态库 + 线程支持 gcc -o program program.c -L. -lwrapper -lpthread # 方法三:自行编译 gcc -c wrapper.c ptwrapper.c ar rc libwrapper.a wrapper.o ptwrapper.o gcc -o program program.c -L. -lwrapper -lpthread ``` ## 头文件包含的系统头文件 ```c #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include ``` ## 常量与类型定义 ```c typedef struct sockaddr SA; // 简化 socket 地址类型转换 #define MAXLINE 8192 // 最大文本行长度 #define MAXBUF 8192 // 最大 I/O 缓冲区大小 #define LISTENQ 1024 // listen() 第二参数(连接队列长度) #define DEF_MODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH #define DEF_UMASK S_IWGRP|S_IWOTH // Robust I/O 缓冲区 typedef struct { int rio_fd; int rio_cnt; char *rio_bufptr; char rio_buf[8192]; } rio_t; // System V 信号量联合体 union semun { int val; struct semid_ds *buf; unsigned short *array; struct seminfo *__buf; }; ``` --- ## 进程控制 | 函数原型 | 对应系统调用 | 说明 | |----------|-------------|------| | `pid_t Fork(void)` | `fork` | 创建子进程 | | `void Execve(const char *f, char *const a[], char *const e[])` | `execve` | 执行程序 | | `pid_t Wait(int *status)` | `wait` | 等待任意子进程 | | `pid_t Waitpid(pid_t pid, int *iptr, int options)` | `waitpid` | 等待指定子进程 | | `void Kill(pid_t pid, int signum)` | `kill` | 发送信号 | | `unsigned int Sleep(unsigned int secs)` | `sleep` | 休眠指定秒数 | | `void Pause(void)` | `pause` | 暂停直到信号到达 | | `unsigned int Alarm(unsigned int seconds)` | `alarm` | 设置定时器 | | `void Setpgid(pid_t pid, pid_t pgid)` | `setpgid` | 设置进程组 | | `pid_t Getpgrp(void)` | `getpgrp` | 获取当前进程组 | **示例:** ```c pid_t pid = Fork(); if (pid == 0) { char *args[] = {"ls", "-la", NULL}; Execve("/bin/ls", args, environ); } else { int status; Waitpid(pid, &status, 0); printf("子进程退出状态: %d\n", WEXITSTATUS(status)); } ``` --- ## 文件 I/O | 函数原型 | 对应系统调用 | 说明 | |----------|-------------|------| | `int Open(const char *path, int flags, mode_t mode)` | `open` | 打开/创建文件 | | `ssize_t Read(int fd, void *buf, size_t count)` | `read` | 读取数据 | | `ssize_t Write(int fd, const void *buf, size_t count)` | `write` | 写入数据 | | `off_t Lseek(int fd, off_t offset, int whence)` | `lseek` | 文件偏移定位 | | `void Close(int fd)` | `close` | 关闭文件描述符 | | `int Dup2(int fd1, int fd2)` | `dup2` | 复制文件描述符 | | `int Select(int n, fd_set *r, fd_set *w, fd_set *e, struct timeval *t)` | `select` | I/O 多路复用 | | `void Stat(const char *filename, struct stat *buf)` | `stat` | 获取文件状态 | | `void Fstat(int fd, struct stat *buf)` | `fstat` | 获取文件状态 | **示例:** ```c int fd = Open("data.txt", O_RDONLY, 0); char buf[MAXLINE]; ssize_t n = Read(fd, buf, MAXLINE); Write(STDOUT_FILENO, buf, n); Close(fd); ``` --- ## 信号 | 函数原型 | 对应系统调用 | 说明 | |----------|-------------|------| | `handler_t *Signal(int signum, handler_t *handler)` | `signal` | 注册信号处理函数 | | `void Sigprocmask(int how, const sigset_t *set, sigset_t *old)` | `sigprocmask` | 修改信号屏蔽字 | | `void Sigemptyset(sigset_t *set)` | `sigemptyset` | 清空信号集 | | `void Sigfillset(sigset_t *set)` | `sigfillset` | 填满信号集 | | `void Sigaddset(sigset_t *set, int signum)` | `sigaddset` | 添加信号到集合 | | `void Sigdelset(sigset_t *set, int signum)` | `sigdelset` | 从集合移除信号 | | `int Sigismember(const sigset_t *set, int signum)` | `sigismember` | 判断信号是否在集合中 | **示例:** ```c void handler(int sig) { printf("收到信号 %d\n", sig); } Signal(SIGINT, handler); // Ctrl+C 时调用 handler ``` --- ## 标准 I/O | 函数原型 | 对应标准库函数 | 说明 | |----------|--------------|------| | `FILE *Fopen(const char *name, const char *mode)` | `fopen` | 打开文件 | | `void Fclose(FILE *fp)` | `fclose` | 关闭文件 | | `char *Fgets(char *ptr, int n, FILE *stream)` | `fgets` | 读取一行 | | `void Fputs(const char *ptr, FILE *stream)` | `fputs` | 写入一行 | | `size_t Fread(void *ptr, size_t size, size_t nmemb, FILE *stream)` | `fread` | 二进制读取 | | `void Fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)` | `fwrite` | 二进制写入 | | `FILE *Fdopen(int fd, const char *type)` | `fdopen` | 文件描述符转 FILE* | --- ## 内存管理 | 函数原型 | 对应标准库函数 | 说明 | |----------|--------------|------| | `void *Malloc(size_t size)` | `malloc` | 分配内存 | | `void *Realloc(void *ptr, size_t size)` | `realloc` | 重新分配内存 | | `void *Calloc(size_t nmemb, size_t size)` | `calloc` | 分配并清零 | | `void Free(void *ptr)` | `free` | 释放内存 | --- ## 内存映射 | 函数原型 | 对应系统调用 | 说明 | |----------|-------------|------| | `void *Mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)` | `mmap` | 创建内存映射 | | `void Munmap(void *start, size_t length)` | `munmap` | 取消内存映射 | --- ## Socket 编程 | 函数原型 | 对应系统调用 | 说明 | |----------|-------------|------| | `int Socket(int domain, int type, int protocol)` | `socket` | 创建套接字 | | `void Setsockopt(int s, int level, int opt, const void *val, int len)` | `setsockopt` | 设置套接字选项 | | `void Bind(int sockfd, struct sockaddr *addr, int addrlen)` | `bind` | 绑定地址 | | `void Listen(int s, int backlog)` | `listen` | 监听连接 | | `int Accept(int s, struct sockaddr *addr, socklen_t *addrlen)` | `accept` | 接受连接 | | `void Connect(int sockfd, struct sockaddr *addr, int addrlen)` | `connect` | 发起连接 | --- ## DNS 解析 | 函数原型 | 说明 | |----------|------| | `struct hostent *Gethostbyname(const char *name)` | 按主机名解析 | | `struct hostent *Gethostbyaddr(const char *addr, int len, int type)` | 按地址解析 | --- ## 线程控制 | 函数原型 | 对应系统调用 | 说明 | |----------|-------------|------| | `void Pthread_create(pthread_t *tid, pthread_attr_t *attr, void *(*r)(void *), void *arg)` | `pthread_create` | 创建线程 | | `void Pthread_join(pthread_t tid, void **retval)` | `pthread_join` | 等待线程结束 | | `void Pthread_detach(pthread_t tid)` | `pthread_detach` | 分离线程 | | `void Pthread_cancel(pthread_t tid)` | `pthread_cancel` | 取消线程 | | `void Pthread_exit(void *retval)` | `pthread_exit` | 终止线程 | | `pthread_t Pthread_self(void)` | `pthread_self` | 获取当前线程 ID | | `void Pthread_once(pthread_once_t *once, void (*init)())` | `pthread_once` | 一次性初始化 | --- ## POSIX 信号量 | 函数原型 | 对应系统调用 | 说明 | |----------|-------------|------| | `void Sem_init(sem_t *sem, int pshared, unsigned int value)` | `sem_init` | 初始化信号量 | | `void P(sem_t *sem)` | `sem_wait` | 等待(P 操作,值减 1) | | `void V(sem_t *sem)` | `sem_post` | 释放(V 操作,值加 1) | **示例(生产者-消费者):** ```c sem_t mutex, slots, items; Sem_init(&mutex, 0, 1); Sem_init(&slots, 0, N); Sem_init(&items, 0, 0); // 生产者 P(&slots); P(&mutex); // 放入缓冲区 V(&mutex); V(&items); // 消费者 P(&items); P(&mutex); // 从缓冲区取出 V(&mutex); V(&slots); ``` --- ## Robust I/O (Rio) | 函数原型 | 说明 | |----------|------| | `ssize_t rio_readn(int fd, void *buf, size_t n)` | 无缓冲读取 n 字节 | | `ssize_t rio_writen(int fd, void *buf, size_t n)` | 无缓冲写入 n 字节 | | `void rio_readinitb(rio_t *rp, int fd)` | 初始化缓冲读取 | | `ssize_t rio_readnb(rio_t *rp, void *buf, size_t n)` | 带缓冲读取 n 字节 | | `ssize_t rio_readlineb(rio_t *rp, void *buf, size_t maxlen)` | 带缓冲读取一行 | **Wrapper 版本:** `Rio_readn`、`Rio_writen`、`Rio_readinitb`、`Rio_readnb`、`Rio_readlineb` --- ## 客户端/服务器辅助函数 | 函数原型 | 说明 | |----------|------| | `int open_client_sock(char *hostname, int port)` | 创建客户端套接字并连接 | | `int open_listen_sock(int port)` | 创建服务器套接字并监听 | | `int Open_client_sock(char *hostname, int port)` | 同上(带错误检查) | | `int Open_listen_sock(int port)` | 同上(带错误检查) | **示例(服务器):** ```c int listen_fd = Open_listen_sock(8080); struct sockaddr_in clientaddr; socklen_t clientlen = sizeof(clientaddr); int conn_fd = Accept(listen_fd, (SA *)&clientaddr, &clientlen); ``` **示例(客户端):** ```c int sock_fd = Open_client_sock("localhost", 8080); Send(sock_fd, "Hello", 5, 0); ``` --- ## System V IPC ### 消息队列 | 函数原型 | 说明 | |----------|------| | `int Msgget(key_t key, int msgflg)` | 创建/获取消息队列 | | `int Msgsnd(int msqid, const void *msg, size_t sz, int msgflg)` | 发送消息 | | `int Msgrcv(int msqid, void *msg, size_t sz, long type, int msgflg)` | 接收消息 | | `int Msgctl(int msqid, int cmd, struct msqid_ds *buf)` | 控制消息队列 | ### 共享内存 | 函数原型 | 说明 | |----------|------| | `int Shmget(key_t key, size_t size, int shmflg)` | 创建/获取共享内存 | | `char *Shmat(int shmid, const void *addr, int shmflg)` | 附加共享内存 | | `int Shmdt(const void *addr)` | 分离共享内存 | | `int Shmctl(int shmid, int cmd, struct shmid_ds *buf)` | 控制共享内存 | ### System V 信号量 | 函数原型 | 说明 | |----------|------| | `int Semget(key_t key, int nsems, int semflg)` | 创建/获取信号量集 | | `int Semctl(int semid, int semnum, int cmd, union semun arg)` | 控制信号量 | | `int Semop(int semid, struct sembuf *sem, int sops)` | 操作信号量 | ### 命名管道 | 函数原型 | 说明 | |----------|------| | `int Mkfifo(const char *pathname, mode_t mode)` | 创建命名管道 (FIFO) | --- ## 错误处理函数 Wrapper 库内部使用以下错误处理函数,也可在自己的代码中直接调用: | 函数 | 说明 | |------|------| | `void unix_error(char *msg)` | 打印系统调用错误并退出 | | `void posix_error(int code, char *msg)` | 打印 POSIX 错误并退出 | | `void dns_error(char *msg)` | 打印 DNS 错误并退出 | | `void app_error(char *msg)` | 打印应用错误并退出 |