C++ UNIX简单TCP服务端文件读取失败修复及传参问题咨询
问题修复与解决方案
一、文件请求返回空行的BUG修复
你遇到的文件读取返回空行的核心问题出在文件读取逻辑的长度参数错误,同时还有两处隐藏的缓冲区合法性问题:
- 从socket读取客户端发来的路径后,没有手动加字符串终止符
\0,stat函数可能读到路径缓冲区后的垃圾内存,导致判断异常 - 读取文件时用了
strlen(buffer)作为读取长度:buffer是栈上未初始化的局部变量,strlen会从开头找\0的位置,大概率返回0,所以根本没读到文件内容,最后只输出了手动拼接的换行符
修复代码如下:
void processClientRequest(int connSock) { int received; char path[1024], buffer[1024]; // Read from the client if((received = read(connSock, path, sizeof(path)-1)) < 0) { perror("receive"); exit(EXIT_FAILURE); } // 新增:给路径加字符串终止符 path[received] = '\0'; // Check if it is a directory or a file struct stat s; if(stat(path,&s) == 0 ) { // It is a directory if(s.st_mode & S_IFDIR) { DIR *dirp = opendir(path); if (dirp == 0) { close(2); dup(connSock); perror(path); close(connSock); exit(EXIT_SUCCESS); } struct dirent *dirEntry; while((dirEntry = readdir(dirp)) != NULL) { if(dirEntry->d_name[0] != '.') { strcpy(buffer, dirEntry->d_name); strcat(buffer, "\n"); if(write(connSock, buffer, strlen(buffer)) < 0) { perror("write"); exit(EXIT_FAILURE); } } } closedir(dirp); close(connSock); exit(EXIT_SUCCESS); } // It is a file else if(s.st_mode & S_IFREG) { int fd = open(path, O_RDONLY); if(fd < 0) { close(2); dup(connSock); perror("open"); close(connSock); exit(EXIT_SUCCESS); } int readBytes; // 循环读文件,适配大文件场景 while((readBytes = read(fd, buffer, sizeof(buffer)-1)) > 0) { if(write(connSock, buffer, readBytes) < 0) { perror("write"); close(fd); close(connSock); exit(EXIT_FAILURE); } } // 末尾加换行符对齐原有输出格式 const char* newline = "\n"; write(connSock, newline, 1); close(fd); close(connSock); exit(EXIT_SUCCESS); } // Not a file or directory else { const char* err = "Error: not a regular file or directory\n"; write(connSock, err, strlen(err)); close(connSock); exit(EXIT_FAILURE); } } else { close(2); dup(connSock); perror("stat"); exit(EXIT_SUCCESS); } close(connSock); exit(EXIT_SUCCESS); }
二、特定指令字识别实现
要支持GET xxx这类带指令的请求格式,提前约定请求结构为[指令字] [请求内容],服务端收到请求后先拆分字符串即可:
// 读取到path并加终止符之后新增逻辑 char* cmd = strtok(path, " "); char* req_path = strtok(NULL, ""); // 取第一个空格后的所有内容作为请求路径,保留后续空格 if(cmd == NULL || strcmp(cmd, "GET") != 0) { const char* err = "Error: only support GET command\n"; write(connSock, err, strlen(err)); close(connSock); exit(EXIT_SUCCESS); } // 后续stat、读写逻辑都用req_path变量即可
三、带空格路径的传参处理
你遇到的"pathname/name with spaces"格式传参报错问题,根源在客户端的参数发送逻辑,和服务端无关:
- 终端下的引号是shell的参数分隔标记,
./client localhost 4000 "GET pathname/filename"执行时,argv[3]会自动去掉外层引号,拿到完整的GET pathname/filename字符串 - 客户端直接把
argv[3]完整发送给服务端即可,不要做任何拆分、截断操作,服务端配合上面的指令拆分逻辑,就能正常拿到带空格的完整路径
注意不要用strtok(NULL, " ")拆分路径,这会把路径内的连续空格合并,导致路径匹配失败。
内容的提问来源于stack exchange,提问作者Long Huang
相关产品推荐
相关产品推荐

