私は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;
}
子供が終了し、私は
を解答接続をクローズします私のコード内の論理間違いはありますか?
編集:
完全な最小コードを追加しました。 送信メッセージに「\ r \ n」を追加します。 私は)(メインに
close(accfd);
を追加する場合は正常に動作しますが、私はそれが実際に問題(唯一の副作用溶液)
があるindex.htmをすることができないと思う。
<html><body><b>index</b><br>C is a interesting language!</body></html>
必須の '\ n '終端文字はありますか? – Tibrogargan
@Tibrogargan: '\ r \ n' – alk
サーバは、不完全なデータセットをクライアントに送信する可能性が最も高いです。そのため、クライアントは欠落しているものを待ってから、何を得たかをレンダリングします。接続が途絶えた瞬間、クライアントは何も来ていないことを認識し、待機を停止し、何が得られたかを試します。バグは 'createAnswerMessage'にあります。 – alk