我想构建一个web服务器,以便客户端可以使用http 1.1在本地Linux环境中查看index.html文档。
我不知道如何发送正确的html信息给客户端,因为我缺乏编程知识。
如何在c语言环境中配置web服务器来发送这样的响应?
HTTP/1.1 400 Bad Request
Date: Tue, 10 Jan 2023 11:27:27 GMT
Server: Apache/2.4.54 (FreeBSD)
Content-Length: 226
Connection: close
Content-Type: text/html; charset=iso-8859-1
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
HTTP/1.1 200 OK
Date: Mon, 28 Nov 2022 06:11:52 GMT
Server: Apache/2.4.54 (FreeBSD)
Accept-Ranges: bytes
Connection: close
Content-Type: text/html
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
代码void send_data(int s, char * path) { //path='/index.html'
char buf[1024];
char filename[256];
char protocol[] = "HTTP/1.0 200 OKrn ";
char server[] = "Server: Linux Web Serverrn ";
char cnt_len[] = "Content-length:2048rnrn";
FILE * send_file;
sprintf(filename, "htdocs%s", path);
printf("[%s]n", filename);
send_file = fopen(filename, "rb");
printf("%d fileopenn", send_file);
if (send_file == NULL) {
send_error(s);
printf("%s %dn", __FUNCTION__, __LINE__);
return;
}
send(s, protocol, strlen(protocol), 0);
send(s, server, strlen(server), 0);
send(s, cnt_len, strlen(cnt_len), 0);
int len = 1;
while (len != 0) {
len = fread(buf, 1, 1024, send_file);
send(s, buf, len, 0);
}
}
除非文件实际大小为2048字节,否则将Content-length
头硬编码为2048
值是错误的。您需要发送文件的实际大小。
还需要更好的错误处理。
试试这样写:
int send_raw(int s, const char *data, size_t size) {
while (size > 0) {
int sent = send(s, data, size, 0);
if (sent < 0) {
return -1;
}
data += sent;
size -= sent;
}
return 0;
}
int send_str(int s, const char *data) {
return send_raw(s, data, strlen(data));
}
void send_data(int s, const char *path) { //path='/index.html'
char buf[1024];
char filename[256];
char protocol[] = "HTTP/1.0 200 OKrn";
char server[] = "Server: Linux Web Serverrn";
char cnt_len_fmt[] = "Content-Length: %ldrnrn";
char cnt_len[48];
FILE *send_file;
snprintf(filename, 256, "htdocs%s", path);
printf("[%s]n", filename);
send_file = fopen(filename, "rb");
printf("%p fileopenn", send_file);
if (send_file == NULL) {
send_error(s);
printf("%s %dn", __FUNCTION__, __LINE__);
return;
}
if (fseek(send_file, 0, SEEK_END) != 0) {
send_error(s);
fclose(send_file);
printf("%s %dn", __FUNCTION__, __LINE__);
return;
}
long file_size = ftell(send_file);
if (file_size == -1L) {
send_error(s);
fclose(send_file);
printf("%s %dn", __FUNCTION__, __LINE__);
return;
}
rewind(send_file);
sprintf(cnt_len, cnt_len_fmt, file_size);
if (send_str(s, protocol) < 0) {
fclose(send_file);
printf("%s %dn", __FUNCTION__, __LINE__);
return;
}
if (send_str(s, server) < 0) {
fclose(send_file);
printf("%s %dn", __FUNCTION__, __LINE__);
return;
}
if (send_str(s, cnt_len) < 0) {
fclose(send_file);
printf("%s %dn", __FUNCTION__, __LINE__);
return;
}
size_t len;
for(long offset = 0; offset < file_size; offset += len) {
len = fread(buf, 1, min(file_size-offset, 1024), send_file);
if (len < 1) {
printf("%s %dn", __FUNCTION__, __LINE__);
break;
}
if (send_raw(s, buf, len) < 0) {
printf("%s %dn", __FUNCTION__, __LINE__);
break;
}
}
fclose(send_file);
}
否则,您可以省略Content-length
报头,而发送Connection: close
报头。但是,当您完成发送文件时,您必须实际close()
套接字,例如:
...
void send_data(int s, const char * path) { //path='/index.html'
char buf[1024];
char filename[256];
char protocol[] = "HTTP/1.0 200 OKrn";
char server[] = "Server: Linux Web Serverrn";
char conn[] = "Connection: closernrn";
FILE *send_file;
snprintf(filename, 256, "htdocs%s", path);
printf("[%s]n", filename);
send_file = fopen(filename, "rb");
printf("%d fileopenn", send_file);
if (send_file == NULL) {
send_error(s);
close(s);
printf("%s %dn", __FUNCTION__, __LINE__);
return;
}
if (send_str(s, protocol) < 0) {
close(s);
printf("%s %dn", __FUNCTION__, __LINE__);
return;
}
if (send_str(s, server) < 0) {
close(s);
printf("%s %dn", __FUNCTION__, __LINE__);
return;
}
if (send_str(s, conn) < 0) {
close(s);
printf("%s %dn", __FUNCTION__, __LINE__);
return;
}
size_t len;
while ((len = fread(buf, 1, 1024, send_file)) > 0) {
if (send_raw(s, buf, len) < 0) {
close(s);
fclose(send_file);
printf("%s %dn", __FUNCTION__, __LINE__);
return;
}
}
while (true);
if (ferror(send_file) && !feof(send_file)) {
printf("%s %dn", __FUNCTION__, __LINE__);
}
fclose(send_file);
close(s);
}