gpt4 book ai didi

c - 服务器 - 浏览器仅在服务器终止后显示站点

转载 作者:可可西里 更新时间:2023-11-01 02:55:11 25 4
gpt4 key购买 nike

我正在尝试使用 fork() 编写一个小型 HTTP 服务器。当我通过 firefox 连接到它时,它不会显示页面,直到我终止服务器。

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdbool.h>
#include <sys/socket.h>
#include <signal.h>

#define LISTEN_MAX 5
#define CONT_MAX 10000
#define PORT 8081
#define MAX_FILE 2
#define S_SHORT 50
#define MAX_CONTENT 1000
#define MAX_HEADER 200
const size_t BUF_LEN = 1024; //was 128
const size_t REQUEST_LEN=1024;
char file_names[MAX_FILE][S_SHORT];
FILE *file_deskriptors[MAX_FILE];
int file_sizes[MAX_FILE];
char file_contents[MAX_FILE][MAX_CONTENT];

// Something unexpected happened. Report error and terminate.
void sysErr( char *msg, int exitCode ) {
fprintf( stderr, "%s\n\t%s\n", msg, strerror( errno ) );
exit( exitCode );
}

// get_line was borrowed from Tiny HTTPd under GPLv2
// https://sourceforge.net/projects/tinyhttpd/?source=typ_redirect
int get_line(int sock, char *buf, int size) {
int i = 0;
char c = '\0';
int n;

while ((i < size - 1) && (c != '\n'))
{
n = recv(sock, &c, 1, 0);
/* DEBUG printf("%02X\n", c); */
if (n > 0)
{
if (c == '\r')
{
n = recv(sock, &c, 1, MSG_PEEK);
/* DEBUG printf("%02X\n", c); */

if ((n > 0) && (c == '\n'))
recv(sock, &c, 1, 0);
else
c = '\n';
}
buf[i] = c;
i++;
}
else
c = '\n';
}
buf[i] = '\0';
return(i);
}

void copyHeaderToBuffer(char *tx_buff, int *status) {
switch(*status) {
case 200: strcpy(tx_buff,"HTTP/1.0 200 OK\r\nContent­type: text/html\r\n\r\n"); break;

}
return;
}

void answer(int *accfd, char *request ) {
int file_size, file_index, status, sent_bytes;
file_size, file_index, status = 0;
char method[S_SHORT], ressource[S_SHORT], proto[S_SHORT];
char tx_buff[MAX_CONTENT+MAX_HEADER];

//rehash query
splitRequest(request, method, ressource, proto);

//check for <GET>
checkMethod(method);

//search the file and get index
getFileIndexByName(ressource, &file_index);

file_size = file_sizes[file_index];

status = getFileStatus(&file_index);

createAnswerMessage(tx_buff, &status, &file_index);

//send the answer
if ( (sent_bytes= write( accfd, tx_buff, strlen(tx_buff))) == -1 ) {
sysErr( "[-] Client Fault: SEND", -4 );
}

return;
}

void createAnswerMessage(char *tx_buff, int *status, int *file_index) {
copyHeaderToBuffer(tx_buff, status);
strcat(tx_buff,file_contents[*file_index]);
strcat(tx_buff,"\r\n");
return;
}

int getFileStatus(int *file_index) {
return 200;
}

void splitRequest(char *request, char *method, char *ressource, char *proto) {
char *temp;
if ((temp = strtok(request, " ")) != NULL) {
strcpy(method, temp);
}

if ((temp = strtok(NULL, " ")) != NULL) {
strcpy(ressource, temp);
}

if ((temp = strtok(NULL, " ")) != NULL) {
strcpy(proto, temp);
}
//remove leading "/" from ressource
cleanRessource(ressource);
return;
}

void cleanRessource(char *ressource) {
if (*ressource == '/') {
printf("\nstr_len_ressource: %i",strlen(ressource));
for ( int i=0; i < strlen(ressource); i++ ) {
ressource[i]=ressource[i+1];
}
}
return;
}

void checkMethod(char *method){
if (strcmp(method, "GET") ) {
printf("\n[-] Error: Method \"%s\" not known .",method);
exit(0);
}
printf("\nincheckMethod method = %s",method);
return;
}

void getFileIndexByName (char *ressource, int *file_index) {
for (int i=0; i<MAX_FILE; i++) {
if ( !strcmp(ressource, file_names[i]) ) {
*file_index = i;
return;
}
}
printf("\[-] Error: File \"%s\" not known.",ressource);
exit(0);
}

void filesInit () {
memset(file_names, '\0', sizeof(file_names));
memset(file_contents, '\0', sizeof(file_contents));
//define your files here:
strcpy(file_names[0],"index.htm");
for (int i=0; i<MAX_FILE; i++) {
//choose only existing files
if (file_names[i][0]!='\0') {
//open file
file_deskriptors[i] = fopen(file_names[i],"r");
//get file size
fseek(file_deskriptors[i], 0, SEEK_END);
file_sizes[i] = ftell(file_deskriptors[i]);
//read the file content to file_contents
fseek(file_deskriptors[i], 0, SEEK_SET);
fread(file_contents[i], 1, CONT_MAX, file_deskriptors[i]);
}
}
return;
}

void filesClose() {
return;
}

int main(int argc, char **argv)
{
//kill childs if recieving SIGCHLD
signal(SIGCHLD,SIG_IGN);
int connfd, accfd;

struct sockaddr_in server_addr, client_addr;
socklen_t sockaddr_len = sizeof(struct sockaddr_in);

//initial the available files on server
filesInit();
// create socket
if ( ( connfd = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0) {
sysErr( "Server Fault : SOCKET", -1 );
}
// Set params so that we receive IPv4 packets from anyone on the specified port
memset( &server_addr, 0, sockaddr_len );
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons( PORT );

//bind socket to port
if ( bind( connfd, (struct sockaddr *) &server_addr, sockaddr_len ) < 0 ) {
sysErr( "\n[-] Server Fault : BIND", -2 );
}else{printf("[+] SERVER ONLINE");}

//let server listen for incoming connections
if ( listen( connfd, LISTEN_MAX) < 0 ) {
sysErr( "[-] Server Fault : LISTEN", -3 );
}

//main loop for accepting clients
while ( true ) {
pid_t pid;
//connecting specific client
if ( (accfd=accept( connfd, (struct sockaddr *) &client_addr, &sockaddr_len )) < 0 ) {
sysErr( "[-] Server Fault : ACCEPT", -4 );
}
//fork & answer
else {
printf("\n[+] CLIENT CONNECTED\n");
switch ( pid = fork() ) {
case -1: {
printf("\n[-] Error while fork()");
return EXIT_FAILURE;
}
case 0: {
int req_line_len=1; //length of request line
int first_line_on = 1; //set first line parameter
char req_line[S_SHORT]; //current read line
char first_line[S_SHORT]; //save first line

memset(req_line, 0, S_SHORT);
memset(first_line, 0, S_SHORT);

printf("\n[+] HTTP REQUEST on accfd: %i",accfd);
//reading line by line from socket
while((req_line_len > 0) && strcmp("\n", req_line)){
req_line_len = get_line( accfd, req_line, S_SHORT-1);
//get first line and save it
if (first_line_on) { first_line_on = 0; strcpy(first_line,req_line); }
if((req_line_len > 0) && strcmp("\n", req_line)) printf("%s",req_line);
}
//answering to client
answer(accfd, first_line);
//close connection
if (!close(accfd)) {printf("\n[+] CONNECTION CLOSED");}
exit(0);
break;
}
default: {
//main process
break;
}
}
}
}
//close listening socket
close( connfd );
//close server files
filesClose();
return 0;
}

child 被终止了,我得到了 CONNECTION CLOSED 的答案

我的代码中是否存在逻辑错误?

编辑:

我添加了完整的最少代码。我在传输消息中添加的“\r\n”。如果我添加

它工作正常
close(accfd);

到 main(),但我认为这实际上不是问题(只是一个副作用解决方案)

index.htm 可以是:

<html><body><b>index</b><br>C is a interesting language!</body></html>

最佳答案

当你调用 fork() 时,父进程的文件描述符被复制到子进程中,这就是为什么你仍然可以访问子进程中的套接字的原因。只要您至少有一个文件描述符对套接字打开,网络堆栈就会使套接字保持事件状态。您关闭了子进程中的套接字,但它仍然在父进程中打开。

换句话说,在父级中添加对 close(accfd) 的调用应该可以解决您的问题。

关于c - 服务器 - 浏览器仅在服务器终止后显示站点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40687716/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com