我正在尝试在单个数据包中发送 HTTP 响应
这永远行不通。 TCP,就其本质而言,是流式传输的,并且永远不会保证使用单个数据包。没有充分的理由尝试将所有内容都填充到单个缓冲区中。充其量,这是等待发生的缓冲区溢出。但是现在,您甚至无法将文件名放入正确分配的字符缓冲区,更不用说打开文件并将其读入 HTTP 响应缓冲区了。
char *root;
char PATH[9999];
root = getenv("PWD");
strcpy(PATH, root);
strcpy(&PATH[strlen(root)], URL);
int filefd = open(PATH, O_RDONLY);
这会导致段错误,因为您没有检查 getenv() 的结果是否为 NULL。 getenv("PWD") 不是获取调用进程当前工作目录的正确方法。将 NULL 指针传递给strcpy() 或strlen() 是未定义的行为。
char *root = getenv("PWD");
if (root) {
char PATH[9999];
strcpy(PATH, root);
strcpy(&PATH[strlen(root)], URL);
int filefd = open(PATH, O_RDONLY);
...
}
char *PATH;
getcwd(PATH, sizeof(PATH));
strcat(PATH, URL);
int filefd = open(PATH, O_RDONLY);
这失败了,因为您没有为PATH 分配任何内存来指向所以getpwd() 和strcat() 有一些东西要写入。改用固定数组:
char PATH[9999];
if (getcwd(PATH, sizeof(PATH))) {
strcat(PATH, URL);
int filefd = open(PATH, O_RDONLY);
...
}
char body[fileLen];
if ( read(filefd, body, fileLen) != -1 )
strcat(response, body);
这也是错误的。 strcat() 需要一个以 null 结尾的字符串来复制,但 read() 的结果不是以 null 结尾的。 read() 返回它实际读取的字节数:
char body[fileLen];
int numRead;
if ( (numRead = read(filefd, body, fileLen)) > 0 )
memcpy(&response[strlen(response)], body, numRead);
或者:
char body[fileLen];
int numRead = read(filefd, &response[strlen(response)], fileLen);
...
当然,无论哪种情况,在调用read() 之前,您都必须确保分配给response 的空间足够大以实际容纳整个HTTP 响应标头+ 文件数据。
这就是利用 TCP 的流式传输特性而不是将整个 HTTP 响应存储到单个缓冲区中的地方。先发送HTTP响应头,然后循环调用read()发送每一个读取成功的缓冲区,例如:
int sendRaw(int sckt, const void *buf, size_t buflen) {
const char *ptr = (const char*) buf;
int numSent;
while ( buflen > 0 ) {
if ( (numSent = send(sckt, ptr, buflen, 0)) < 0 ) {
return -1;
}
ptr += numSent;
buflen -= numSent;
}
return 0;
}
int sendStr(int sckt, const char *str) {
return sendStr(sckt, str, strlen(str));
}
...
const char *URL = "/index.html";
char PATH[9999];
if (getcwd(PATH, sizeof(PATH))) {
strcat(PATH, URL);
} else {
PATH[0] = '\0';
}
int filefd = open(PATH, O_RDONLY);
if ( filefd < 0 ) {
// error handling as needed ...
sendStr(sckt, "HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\nConnection: close\r\n\r\n");
close(sckt);
return;
}
fileLen = ...; // get file length as needed ...
if ( dprintf(sckt, "HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream\r\nContent-Length: %d\r\n\r\n", fileLen) < 0 ) {
// error handling as needed ...
close(filefd);
close(sckt);
return;
}
char body[1024];
int numRead;
while ( fileLen > 0 ) {
if ( (numRead = read(filefd, body, min(fileLen, 1024))) <= 0 ) {
// error handling as needed ...
close(filefd);
close(sckt);
return;
}
if ( sendRaw(sckt, body, numRead) < 0 ) {
// error handling as needed ...
close(filefd);
close(sckt);
return;
}
fileLen -= numRead;
}
close(filefd);
...