網路程式中直接呼叫 read()/write() 存在風險:
健壯的封裝函數應自動處理重試與錯誤轉換。
write_n()ssize_t write_n(int fd, const void *buf, size_t n) {
size_t left = n;
const char *ptr = (const char *)buf;
ssize_t written;
while (left > 0) {
written = write(fd, ptr, left);
if (written <= 0) {
if (errno == EINTR) { written = 0; continue; } // 被中斷,重試
if (errno == EPIPE) { return -1; } // 連線斷裂,上層處理
return -1; // 其他錯誤
}
left -= written;
ptr += written;
}
return n; // 成功寫入全部
}
read_n()ssize_t read_n(int fd, void *buf, size_t n) {
size_t left = n;
char *ptr = (char *)buf;
ssize_t nread;
while (left > 0) {
nread = read(fd, ptr, left);
if (nread < 0) {
if (errno == EINTR) { nread = 0; continue; }
return -1;
} else if (nread == 0) { // EOF (對端關閉)
break;
}
left -= nread;
ptr += nread;
}
return n - left; // 返回實際讀取位元組數 (可能小於 n)
}
readline() 範例針對行協議(以 \n 結尾),需逐字元讀取或使用緩衝:
ssize_t readline(int fd, void *buf, size_t maxlen) {
char *ptr = (char *)buf;
ssize_t n, rc;
char c;
for (n = 1; n < maxlen; n++) {
rc = read(fd, &c, 1);
if (rc == 1) {
*ptr++ = c;
if (c == '\n') break;
} else if (rc == 0) { // EOF
if (n == 1) return 0;
break;
} else {
if (errno == EINTR) continue;
return -1;
}
}
*ptr = '\0';
return n;
}
// 發送端
struct MyData { int id; char msg[100]; };
struct MyData data = { .id = 1, .msg = "Hello" };
if (write_n(sockfd, &data, sizeof(data)) != sizeof(data))
handle_error("write_n");
// 接收端
struct MyData recv_data;
if (read_n(sockfd, &recv_data, sizeof(recv_data)) != sizeof(recv_data))
handle_error("read_n");
// 注意:跨架構傳輸需處理位元組序 (htonl/ntohl) 與結構對齊
read/write。SO_SNDTIMEO/SO_RCVTIMEO 防止無限阻塞。SIGPIPE (signal(SIGPIPE, SIG_IGN)),改由 write_n 返回 EPIPE 處理。Linux 系統 Crash 與 Hang 根因分析與應對策略
Linux 系統效能監測:虛擬記憶體管理與 vmstat 實戰分析
CentOS 7/8 部署 PPTP VPN 服務端完整教程(含防火牆/轉發)
Linux 網路程式設計:健壯的讀寫函數實作(處理 EINTR、EPIPE 等錯誤)
Linux 防火牆框架深度解析:Netfilter 五大核心組件與 iptables/nftables 實作
解決 Apache 啟動報錯:Cannot load libphp5.so Permission denied