如何在阻塞TCP套接字上实现getdelim函数的FILE*同款功能?
在阻塞TCP套接字上复用getdelim函数的POSIX方案
能否在未做任何配置的阻塞TCP套接字上,实现与FILE上getdelim函数相同的功能?期望如下原本适配FILE的代码可直接用于this->socketfd:
// code before char* buffer = nullptr; char* valueBuffer = nullptr; size_t length = 0; while (true) { getdelim(&buffer, &length, ':', this->socketfd); if (buffer[0] == '-') break; getdelim(&valueBuffer, &length, ';', this->socketfd); // code after in which I save {buffer, valueBuffer} pairs } // code after仅需支持POSIX 2008标准,虽可通过有限状态机实现该功能,但好奇是否有新的解决方案。
直接解决方案:使用fdopen()转换套接字为FILE*
POSIX 2008标准提供了fdopen()函数,可以将已有的文件描述符(包括TCP套接字的fd)转换为FILE*指针,这样就能直接复用getdelim()等标准stdio函数,完全不需要自己实现有限状态机。
实现步骤
- 调用
fdopen()将阻塞TCP套接字的文件描述符转换为FILE*对象,模式指定为"r"(只读,适配套接字的读操作) - 将原代码中传入
getdelim()的socketfd替换为转换后的FILE*指针 - 处理可能的错误(比如
fdopen()失败、getdelim()返回-1的情况) - 最后通过
fclose()清理FILE*对象(注意:fclose()会同时关闭对应的文件描述符,如果后续还需要使用原套接字fd,需先调用dup()复制fd)
修改后的示例代码
// code before char* buffer = nullptr; char* valueBuffer = nullptr; size_t length = 0; // 将阻塞TCP套接字fd转换为FILE* FILE* sock_stream = fdopen(this->socketfd, "r"); if (!sock_stream) { perror("fdopen failed"); // 这里添加错误处理逻辑,比如退出或返回错误码 } while (true) { ssize_t read_len = getdelim(&buffer, &length, ':', sock_stream); if (read_len == -1) { if (feof(sock_stream)) { // 套接字连接关闭 } else { perror("getdelim failed"); } break; } if (buffer[0] == '-') break; read_len = getdelim(&valueBuffer, &length, ';', sock_stream); if (read_len == -1) { if (feof(sock_stream)) { // 套接字连接关闭 } else { perror("getdelim failed"); } break; } // code after in which I save {buffer, valueBuffer} pairs } // 清理资源 if (sock_stream) { fclose(sock_stream); // 此操作会关闭原socketfd,若需保留原fd请先dup } free(buffer); free(valueBuffer); // code after
注意事项
fdopen()是POSIX 2008的标准函数,完全符合要求- 转换后的
FILE*默认带有stdio缓冲,不会影响getdelim()的行为(getdelim()会持续读取直到遇到指定分隔符或出错) - 如果后续仍需使用原套接字fd,需先调用
int dup_fd = dup(this->socketfd);,再用dup_fd调用fdopen(),这样fclose(sock_stream)只会关闭复制后的fd,原fd可继续使用 - 必须检查
getdelim()的返回值:返回-1时需通过feof()或ferror()判断是连接关闭还是读错误
内容的提问来源于stack exchange,提问作者FLAK-ZOSO
相关产品推荐
相关产品推荐

