《Unix Network Programming》示例代碼 `#include "unp.h"` 編譯失敗:找不到頭文件、類型重複定義。`unp.h` 是作者 Stevens 自己封裝的教學頭文件,**非系統標準頭文件**。
// 替代 unp.h 的標準頭文件組合
#include // 基礎類型: pid_t, size_t, ssize_t, in_addr_t, in_port_t
#include // 套接字 API: socket, bind, listen, accept, connect, send, recv
#include // 網際網路地址結構: sockaddr_in, in_addr, htons, htonl, INADDR_ANY
#include // IP 地址轉換: inet_pton, inet_ntop, inet_addr, inet_ntoa
#include // 域名解析: gethostbyname, getaddrinfo, addrinfo, servent
#include // POSIX 基礎: read, write, close, fork, exec, pipe
#include // 標準 I/O: printf, perror
#include // 標準庫: exit, malloc, free
#include // 字符串: memset, strcmp, strlen
#include // 錯誤碼: errno, EAGAIN, ECONNREFUSED
#include // 信號: signal, sigaction
#include // 進程等待: wait, waitpid
#include // I/O 多路復用: select, fd_set, FD_*
#include // 時間: timeval, gettimeofday
#include // poll (System V)
#include // epoll (Linux 專用, 高性能)
#include // 文件控制: fcntl, O_NONBLOCK
| unp.h 定義 | 標準替代 | 所需頭文件 |
|---|---|---|
| MAXLINE | 自定義 `#define MAXLINE 4096` | — |
| SA | `struct sockaddr` (直接用) | ` |
| Listenfd, Connfd | `int listenfd, connfd;` | — |
| err_sys, err_quit | 自定義錯誤處理函數 (見下) | — |
#include
#include
void err_sys(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
perror(buf); // 打印 errno 對應信息
exit(1);
}
void err_quit(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
fprintf(stderr, "%s\n", buf);
exit(1);
}
# 基礎編譯
gcc -Wall -Wextra -std=c11 -o daytimetcpcli daytimetcpcli.c
# 鏈接實時庫 (如用 clock_gettime)
gcc -Wall -Wextra -std=c11 -o daytimetcpcli daytimetcpcli.c -lrt
# 啟用線程支持 (pthread)
gcc -Wall -Wextra -std=c11 -pthread -o server server.c
# 靜態分析
clang --analyze -Wall -Wextra daytimetcpcli.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MAXLINE 4096
void err_sys(const char *fmt, ...) {
va_list ap; va_start(ap, fmt);
char buf[1024];
vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
perror(buf);
exit(1);
}
void err_quit(const char *fmt, ...) {
va_list ap; va_start(ap, fmt);
char buf[1024];
vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
fprintf(stderr, "%s\n", buf);
exit(1);
}
int main(int argc, char **argv) {
int sockfd, n;
char recvline[MAXLINE + 1];
struct sockaddr_in servaddr;
if (argc != 2) err_quit("usage: %s ", argv[0]);
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
err_sys("socket error");
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(13); // Daytime server port
if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0)
err_quit("inet_pton error for %s", argv[1]);
if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
err_sys("connect error");
while ((n = read(sockfd, recvline, MAXLINE)) > 0) {
recvline[n] = 0;
if (fputs(recvline, stdout) == EOF)
err_sys("fputs error");
}
if (n < 0) err_sys("read error");
exit(0);
}
最佳回答核心:「unp頭文件不是系統自帶的。是作者自己封裝的。所以你找不到。你可以參考網上其他socket例子。一般只用了規范的頭文件。基本都能編譯通過。」—— 直接指出教材配套庫非標準,指引使用標準頭文件。