Socket 傳輸本質:**發送內存中連續字節序列**。無論文本、結構體、圖片、視頻,對 Socket 都是 char* (或 void*) + 長度。
int sendImage(int sockfd, const char *filepath) {
// 1. 讀取文件到內存
FILE *fp = fopen(filepath, "rb");
if (!fp) return -1;
fseek(fp, 0, SEEK_END);
long fsize = ftell(fp);
fseek(fp, 0, SEEK_SET);
char *buffer = malloc(fsize);
fread(buffer, 1, fsize, fp);
fclose(fp);
// 2. 發送長度 (網絡字節序)
uint32_t netLen = htonl(fsize);
send(sockfd, &netLen, 4, 0); // 固定 4 字節長度頭
// 3. 發送數據 (分包循環)
long sent = 0;
while (sent < fsize) {
int n = send(sockfd, buffer + sent, fsize - sent, 0);
if (n <= 0) { free(buffer); return -1; }
sent += n;
}
free(buffer);
return 0;
}
int recvImage(int sockfd, const char *savePath) {
// 1. 接收長度頭
uint32_t netLen;
int n = recv(sockfd, &netLen, 4, MSG_WAITALL);
if (n != 4) return -1;
long fsize = ntohl(netLen);
// 2. 分配內存並接收數據
char *buffer = malloc(fsize);
long received = 0;
while (received < fsize) {
n = recv(sockfd, buffer + received, fsize - received, 0);
if (n <= 0) { free(buffer); return -1; }
received += n;
}
// 3. 寫入文件
FILE *fp = fopen(savePath, "wb");
fwrite(buffer, 1, fsize, fp);
fclose(fp);
free(buffer);
return 0;
}
| 環節 | 關鍵 |
|---|---|
| 文件讀取 | fopen(..., "rb") 二進制模式,fread 一次性讀入 |
| 長度協議 | 固定 4/8 字節頭 + htonl/ntohl 網絡序,雙端解析一致 |
| 分包處理 | send/recv 返回實際字節數,**必須循環**直到完成 |
| 內存管理 | 大文件考慮分塊讀寫 (mmap/文件映射) 避免 OOM |
| 結構體傳輸 | 同樣原理:send(sock, &struct, sizeof(struct), 0),但需處理對齊、端序、指針無效化 |
// 發送端:邊讀邊發
while ((n = fread(buf, 1, BUFSIZE, fp)) > 0) {
sendAll(sockfd, buf, n);
}
// 接收端:邊收邊寫
while (received < fsize) {
n = recv(sockfd, buf, BUFSIZE, 0);
fwrite(buf, 1, n, fp);
received += n;
}
**完全相同原理**。結構體只是特定格式的二進制數據。區別在於:
#pragma pack 對齊、端序轉換、指針字段無法直接傳輸。Socket 傳輸二進制圖片 = **讀文件入內存 → 發長度頭 → 循環發數據**。核心就是一個指針、一個長度、一個循環。結構體傳輸同理,額外處理對齊與端序。