如何在C语言Socket中单次发送文本与二进制混合消息?
在C语言中构建包含文本与二进制的Socket复合消息
1. 明确消息结构规范
你需要的复合消息分为两部分:
- 文本头部:以键值对形式携带
messageId和messageLength,末尾用两个连续换行作为头部与二进制数据的分隔符 - 二进制数据段:图片的原始字节流,长度由头部的
messageLength指定
这种结构既保证头部的可读性,又能通过明确的长度值避免二进制数据(可能包含换行等特殊字节)与头部混淆。
2. 发送端:构建并发送复合消息
核心思路是先拼接文本头部,再将二进制数据追加到头部之后,最后一次性发送完整缓冲区(或循环发送直到全部数据发出)。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #define MAX_BUFFER (1024 * 1024) // 按需调整,确保能容纳头部+图片数据 int main() { // 替换为实际已建立连接的socket描述符 int sockfd = ...; // 1. 准备头部信息 int messageId = 12; int imgDataLen = 34; // 实际应替换为图片文件的真实字节长度 char header[256]; snprintf(header, sizeof(header), "messageId: %d, messageLength: %d\n\n", messageId, imgDataLen); int headerLen = strlen(header); // 2. 读取图片二进制数据(示例:模拟读取,实际用fread从文件获取) unsigned char* imgData = malloc(imgDataLen); if (!imgData) { perror("malloc failed"); return -1; } memset(imgData, 0x00, imgDataLen); // 模拟填充图片数据 // 3. 构建完整消息缓冲区 unsigned char* fullMsg = malloc(headerLen + imgDataLen); if (!fullMsg) { perror("malloc failed"); free(imgData); return -1; } memcpy(fullMsg, header, headerLen); memcpy(fullMsg + headerLen, imgData, imgDataLen); // 4. 发送完整消息(循环确保全部数据发出) ssize_t totalSent = 0; size_t totalSize = headerLen + imgDataLen; while (totalSent < totalSize) { ssize_t sent = send(sockfd, fullMsg + totalSent, totalSize - totalSent, 0); if (sent == -1) { perror("send failed"); break; } totalSent += sent; } printf("Sent %zd bytes total\n", totalSent); // 清理资源 free(imgData); free(fullMsg); close(sockfd); return 0; }
3. 接收端:解析复合消息
接收端需要先读取头部直到找到分隔符,解析出messageLength后,再精准读取对应长度的二进制数据。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #define HEADER_BUF_SIZE 1024 int main() { // 替换为实际已建立连接的socket描述符 int sockfd = ...; char headerBuf[HEADER_BUF_SIZE] = {0}; ssize_t headerRead = 0; int foundSeparator = 0; // 1. 循环读取头部,直到找到"\n\n"分隔符 while (!foundSeparator && headerRead < HEADER_BUF_SIZE - 1) { ssize_t bytes = recv(sockfd, headerBuf + headerRead, HEADER_BUF_SIZE - 1 - headerRead, 0); if (bytes <= 0) { perror("recv header failed"); close(sockfd); return -1; } headerRead += bytes; headerBuf[headerRead] = '\0'; char* sep = strstr(headerBuf, "\n\n"); if (sep) { *sep = '\0'; // 截断头部,仅保留键值对部分 foundSeparator = 1; } } if (!foundSeparator) { fprintf(stderr, "No header separator found\n"); close(sockfd); return -1; } // 2. 解析头部参数 int messageId = -1; int msgLength = -1; if (sscanf(headerBuf, "messageId: %d, messageLength: %d", &messageId, &msgLength) != 2) { fprintf(stderr, "Invalid header format\n"); close(sockfd); return -1; } printf("Received messageId: %d, messageLength: %d\n", messageId, msgLength); // 3. 读取二进制图片数据 unsigned char* imgData = malloc(msgLength); if (!imgData) { perror("malloc failed"); close(sockfd); return -1; } ssize_t totalRead = 0; while (totalRead < msgLength) { ssize_t bytes = recv(sockfd, imgData + totalRead, msgLength - totalRead, 0); if (bytes <= 0) { perror("recv image data failed"); free(imgData); close(sockfd); return -1; } totalRead += bytes; } // 4. 处理图片数据(示例:写入文件) FILE* fp = fopen("received_img.jpg", "wb"); if (fp) { fwrite(imgData, 1, msgLength, fp); fclose(fp); printf("Image saved to received_img.jpg\n"); } // 清理资源 free(imgData); close(sockfd); return 0; }
关键注意事项
- 必须依赖
messageLength:二进制数据可能包含换行符,不能仅靠分隔符判断数据结束 - 循环收发:
send和recv不一定一次性传输全部数据,必须循环处理直到完成 - 内存安全:动态分配的缓冲区要及时释放,避免内存泄漏
- 缓冲区大小:头部缓冲区要足够容纳完整头部,消息缓冲区要能装下头部+最大尺寸的二进制数据
内容的提问来源于stack exchange,提问作者Manifestor
相关产品推荐
相关产品推荐

