所以我已經在 Web 服務器上作業了幾個月,但我無法解決這個問題。這個問題是大多數時候,當服務器嘗試將資料發送到 Web 客戶端時,某些影像不會發送/不加載。我已經瀏覽了一段時間,但沒有找到解決方案。我知道它有很多代碼,但這是讓它正常作業所需的最后一件事。
這是代碼:
//this is where you enter the default file directories
char *defaultDir1 = "/enter/website/path/here";
char *defaultDir2 = "/enter/server/path/here";
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <pthread.h>
struct sockaddr_in sockaddr;
char webFileDir[9000];
char servFileDir[9000];
#define THREAD_POOL_SIZE 200
#define BACKLOG 200
pthread_t thread_pool[THREAD_POOL_SIZE];
//creates a lock and unlock system for enqueue and dequeue
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
//creates a sleep timer for the threads/does something until given a signal or condition.
pthread_cond_t condition_var = PTHREAD_COND_INITIALIZER;
struct node {
int *client_socket;
struct node *next;
};
typedef struct node node_t;
node_t *head = NULL;
node_t *tail = NULL;
void enqueue(int *client_socket) {
node_t *newnode = malloc(sizeof(node_t)); //create node
newnode->client_socket = client_socket; //assign client socket
newnode->next = NULL; //add node to the end of the list
if (tail == NULL) { //checks if there is nothing on the tail and if so adds a head
head = newnode;
} else {
//if there is a tail then add a new node onto the tail
tail->next = newnode;
}
tail = newnode;
//this all basically creates a new node then moves it over over and over again until stopped
}
int *dequeue() {
if (head == NULL) {
//if the head is empty or nothing has been enqueued then return null
return NULL;
}
if (head != NULL) { //else...
int *result = head->client_socket;
node_t *temp = head;
head = head->next;
if (head == NULL) {tail = NULL;}
free(temp);
return result;
}
//this function removes everything off of the queue
return 0;
}
int *handleClient(int *pClientSock) {
FILE *fpointer;
char *findExtention;
char *clientIP;
char *endDir;
int freadErr;
int fsize;
int bin;
int readSock;
char recvLine[2];
char fileDir[9000];
char recvLineGET1[70];
char recvLineGET[60];
char httpResponseReport[1000];
char *fileLine;
char httpResponse[1000];
char *endOfPost;
char *splitPost;
char *postContentLength;
char *finalPostLength;
char tempPost[2000];
int contentLen;
char *refindBody;
char finalBody[100000];
char fullResp[100000];
char *sendFileDirectory;
int checkSend;
char *startDir;
char *getEnd;
int responseCode = 200;
memset(fileDir, 0, sizeof(fileDir));
memset(recvLineGET, 0, sizeof(recvLineGET));
//get client ip
int acceptSock = *pClientSock;
socklen_t addrSize = sizeof(struct sockaddr_in);
getpeername(acceptSock, (struct sockaddr *)&sockaddr, &addrSize);
clientIP = inet_ntoa(sockaddr.sin_addr);
fullResp[0] = '\0';
//handles reading client http request
while (1) {
if ((readSock = read(acceptSock, recvLine, 1)) != 1) {
perror("error reading from socket");
send(acceptSock, "HTTP/1.1 500\r\n\r\n", 16, MSG_NOSIGNAL);
memset(recvLine, 0, sizeof(recvLine));
memset(fullResp, 0, sizeof(fullResp));
close(acceptSock);
return 0;
}
recvLine[1] = '\0';
strcat(fullResp, recvLine);
printf("%s", recvLine);
if ((endOfPost = strstr(fullResp, "\n")) != NULL) {
break;
} else if (readSock < 0) {
memset(fullResp, 0, sizeof(fullResp));
close(acceptSock);
return 0;
}
memset(recvLine, 0, sizeof(recvLine));
}
printf("fullResp: %s\n", fullResp);
strcpy(fileDir, webFileDir);
//
//POSSIBLE ERROR HERE
//
if ((getEnd = strstr(fullResp, "HTTP")) == NULL) {
memset(fullResp, 0, sizeof(fullResp));
send(acceptSock, "HTTP/1.0 400\r\n\r\n", 16, MSG_NOSIGNAL);
close(acceptSock);
return 0;
}
strcpy(getEnd, "");
if ((startDir = strchr(fullResp, '/')) == NULL) {
perror("this shouldnt happen .-.");
printf("startDir: %s\n", startDir);
send(acceptSock, "HTTP/1.0 400\r\n\r\n", 16, MSG_NOSIGNAL);
memset(fullResp, 0, sizeof(fullResp));
close(acceptSock);
return 0;
}
//handles the file retrieving
if ((endDir = strchr(startDir, ' ')) == NULL) {
perror("endDir error");
send(acceptSock, "HTTP/1.0 500\r\n\r\n", 16, MSG_NOSIGNAL);
memset(fileDir, 0, sizeof(fileDir));
memset(fullResp, 0, sizeof(fullResp));
close(acceptSock);
return 0;
}
strcpy(endDir, "");
//checks for requested directory
if (strcmp(startDir, "/") == 0) {
findExtention = ".html";
strcpy(fileDir, webFileDir);
strcat(fileDir, "index.html");
responseCode = 200;
} else {
if ((findExtention = strchr(startDir, '.')) == NULL) {
perror("invalid webpage");
findExtention = ".html";
strcpy(fileDir, servFileDir);
strcat(fileDir, "err404.html");
responseCode = 404;
}
strcat(fileDir, startDir);
}
//
//START POSSIBLE ERROR
//
if ((fpointer = fopen(fileDir, "rb")) != NULL) {
fseek(fpointer, 0L, SEEK_END);
fsize = ftell(fpointer);
} else if (strcmp(startDir-1, "/favicon.ico") == 0 && access(fileDir, F_OK) != 0) {
strcpy(fileDir, servFileDir);
strcat(fileDir, "favicon.ico");
if (access(fileDir, F_OK) != 0) {
printf("\n\n\nERROR: please do not delete the default favicon.ico file. the program will not work properly if it is deleted\n\n\n");
//error 500: internal server error
send(acceptSock, "HTTP/1.0 500\r\n\r\n", 16, MSG_NOSIGNAL);
exit(1);
}
if ((fpointer = fopen(fileDir, "rb")) == NULL) {
perror("fopen error");
//error 500: internal server error
send(acceptSock, "HTTP/1.0 500\r\n\r\n", 16, MSG_NOSIGNAL);
memset(fullResp, 0, sizeof(fullResp));
close(acceptSock);
return 0;
}
fseek(fpointer, 0L, SEEK_END);
fsize = ftell(fpointer);
} else if (access(fileDir, F_OK) != 0) {
perror("webpage doesnt exist");
findExtention = ".html";
strcpy(fileDir, servFileDir);
strcat(fileDir, "err404.html");
responseCode = 404;
if ((fpointer = fopen(fileDir, "r")) == NULL) {
perror("fopen error");
send(acceptSock, "HTTP/1.0 500\r\n\r\n", 16, MSG_NOSIGNAL);
memset(fullResp, 0, sizeof(fullResp));
close(acceptSock);
return 0;
}
fseek(fpointer, 0L, SEEK_END);
fsize = ftell(fpointer);
}
//
//END POSSIBLE ERROR
//
fclose(fpointer);
//sets the server http response
if ((strcmp(findExtention, ".jpeg")) == 0 || (strcmp(findExtention, ".jpg")) == 0) {
bin = 1;
sprintf(httpResponse, "HTTP/1.0 %d\r\nConnection: close\r\nContent-Type: image/jpeg\r\nContent-Length: %d\r\nContent-Transfer-Encoding: binary\r\n\r\n", responseCode, fsize);
} else if ((strcmp(findExtention, ".png")) == 0) {
bin = 1;
sprintf(httpResponse, "HTTP/1.0 %d\r\nConnection: close\r\nnContent-Type: image/png\r\nContent-Length: %d\r\nContent-Transfer-Encoding: binary\r\n\r\n", responseCode, fsize);
} else if ((strcmp(findExtention, ".ico")) == 0) {
bin = 1;
sprintf(httpResponse, "HTTP/1.0 %d\r\nConnection: close\r\nContent-Type: image/x-icon\r\nContent-Length: %d\r\nContent-Transfer-Encoding: binary\r\n\r\n", responseCode, fsize);
} else if ((strcmp(findExtention, ".mp3")) == 0) {
bin = 1;
sprintf(httpResponse, "HTTP/1.0 %d\r\nConnection: close\r\nContent-Type: audio/mpeg\r\nContent-length: %d\r\nContent-Transfer-Encoding: binary\r\n\r\n", responseCode, fsize);
} else if ((strcmp(findExtention, ".html")) == 0) {
bin = 0;
sprintf(httpResponse, "HTTP/1.0 %d\r\nConnection: close\r\nContent-Type: text/html\r\nContent-Length: %d\r\n\r\n", responseCode, fsize);
} else {
strcpy(fileDir, "err404.html");
fpointer = fopen(fileDir, "r");
fseek(fpointer, 0L, SEEK_END);
fsize = ftell(fpointer);
fclose(fpointer);
bin = 0;
sprintf(httpResponse, "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nContent-Length: %d\r\n\r\n", fsize);
}
strcpy(httpResponseReport, httpResponse);
if (readSock < 0) {
perror("readsock is less than 0");
send(acceptSock, "HTTP/1.0 500\r\n\r\n", 16, MSG_NOSIGNAL);
memset(fullResp, 0, sizeof(fullResp));
memset(fileDir, 0, sizeof(fileDir));
memset(httpResponseReport, 0, sizeof(httpResponseReport));
memset(httpResponse, 0, sizeof(httpResponse));
close(acceptSock);
return 0;
}
//checks if i need to read plaintext or binary
if (bin == 0) {
fpointer = fopen(fileDir, "r");
} else if (bin == 1) {
fpointer = fopen(fileDir, "rb");
}
if (fpointer == NULL) {
perror("file open error");
send(acceptSock, "HTTP/1.0 500\r\n\r\n", 16, MSG_NOSIGNAL);
memset(fullResp, 0, sizeof(fullResp));
memset(fileDir, 0, sizeof(fileDir));
memset(httpResponseReport, 0, sizeof(httpResponseReport));
memset(httpResponse, 0, sizeof(httpResponse));
close(acceptSock);
return 0;
}
//sends server http response to client
fseek(fpointer, 0L, SEEK_END);
fsize = ftell(fpointer);
fclose(fpointer);
//checks if i need to read plaintext or binary (again)
if (bin == 0) {
fpointer = fopen(fileDir, "r");
} else if (bin == 1) {
fpointer = fopen(fileDir, "rb");
}
if (fpointer == NULL) {
perror("fopen error");
//error 500: internal server error
send(acceptSock, "HTTP/1.0 500\r\n\r\n", 16, MSG_NOSIGNAL);
memset(fullResp, 0, sizeof(fullResp));
memset(fileDir, 0, sizeof(fileDir));
memset(httpResponse, 0, sizeof(httpResponse));
memset(httpResponseReport, 0, sizeof(httpResponseReport));
close(acceptSock);
return 0;
}
fileLine = malloc(fsize * sizeof(char));
while ((freadErr = fread(fileLine, fsize, fsize, fpointer)) > 0);
if (feof(fpointer) < 0) {
perror("fread error");
send(acceptSock, "HTTP/1.0 500\r\n\r\n", 16, MSG_NOSIGNAL);
memset(fullResp, 0, sizeof(fullResp));
memset(fileDir, 0, sizeof(fileDir));
memset(httpResponseReport, 0, sizeof(httpResponseReport));
memset(httpResponse, 0, sizeof(httpResponse));
close(acceptSock);
return 0;
}
//set 5 second socket timeout
struct timeval timeout;
timeout.tv_sec = 15;
timeout.tv_usec = 0;
if (setsockopt(acceptSock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) < 0) {
perror("setsockopt error");
//error 500: internal server error
send(acceptSock, "HTTP/1.0 500\r\n\r\n", 16, MSG_NOSIGNAL);
close(acceptSock);
return 0;
}
//
//POSSIBLE ERROR HERE
//
while (1) {
if ((checkSend = send(acceptSock, httpResponse,
strlen(httpResponse), MSG_NOSIGNAL)) == -1) {
break;
}
//send full response
if ((checkSend = send(acceptSock, fileLine, fsize,
MSG_NOSIGNAL)) == -1) {
break;
}
sleep(1);
}
//
//END POSSIBLE ERROR
//
memset(httpResponse, 0, sizeof(httpResponse));
memset(fullResp, 0, sizeof(fullResp));
fclose(fpointer);
close(acceptSock);
free(fileLine);
//handles the clearing of variables and logs client ip and requested directory
printf("\nclient with the ip: %s has requested %s.\n", clientIP, fileDir);
memset(fileDir, 0, sizeof(fileDir));
memset(httpResponseReport, 0, sizeof(httpResponseReport));
return 0;
}
//assign work to each thread
void *giveThreadWork() {
while (1) {
int *pclient;
pthread_mutex_lock(&mutex);
//makes thread wait until signaled
if ((pclient = dequeue()) == NULL) {
pthread_cond_wait(&condition_var, &mutex);
pclient = dequeue();
}
pthread_mutex_unlock(&mutex);
//i dont think i need this rn. might need it later so dont delete
if (pclient != NULL) {
handleClient(pclient);
} else {
//printf("\n\n\n\n\n no more listener \n\n\n\n\n");
}
}
}
int main() {
int clientSock;
int readSock;
int sock;
int portNum;
int defaultOrNo;
int openDir;
char readTemp[1];
printf("\n\n\nWeb Server\n\n\n");
printf("would you like to use default directories (1 = yes, 0 = no): ");
scanf("%d", &defaultOrNo);
if (defaultOrNo == 0) {
printf("enter the directory of the files to be served (with '/' at the end): ");
scanf("%s", webFileDir);
printf("enter the directory of the web server folder (with '/' at the end): ");
scanf("%s", servFileDir);
} else if (defaultOrNo == 1) {
strcpy(webFileDir, defaultDir1);
strcpy(servFileDir, defaultDir2);
}
printf("what port would you like to host the site on?: ");
scanf("%d", &portNum);
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("sock error");
}
sockaddr.sin_family = AF_INET;
sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
sockaddr.sin_port = htons(portNum);
if ((bind(sock, (struct sockaddr *) &sockaddr, sizeof(sockaddr))) < 0) {
perror("bind error");
exit(1);
}
printf("socket bind success\n");
//create all the threads for the thread pool
for (int i = 0; i < THREAD_POOL_SIZE; i ) {
pthread_create(&thread_pool[i], NULL, giveThreadWork, NULL);
}
printf("created thread pool of size %d successfully\n", THREAD_POOLSIZE);
if ((listen(sock, BACKLOG)) < 0) {
perror("listen error");
}
printf("listen success\n");
while (1) {
//checks for client connection
if ((clientSock = accept(sock, NULL, NULL)) < 0) {
perror("accept error");
//oh no too bad
} else {
int *pclient = &clientSock;
pthread_mutex_lock(&mutex);
enqueue(pclient);
//sends a signal to wait until needed
pthread_cond_signal(&condition_var);
pthread_mutex_unlock(&mutex);
}
}
return 0;
}
最新編輯:我要么沒有收到來自客戶端的一些請求,要么我沒有正確發送它們。一旦我發現它是哪個問題,我就會編輯這個問題。
我已經標記了我認為主要問題是使用注釋的地方,所以你們更容易除錯這個。祝你好運,非常感謝任何能解決這個問題的人!!!
代碼審查鏈接:https : //codereview.stackexchange.com/questions/270459/multi-threaded-web-server-serving-html-images-etc
ps:特別感謝@AndreasWenzel 的所有幫助
uj5u.com熱心網友回復:
您的鏈表應包含必須處理的 HTTP 請求的所有套接字檔案描述符的串列。因此,鏈表中的每個節點都應該包含一個檔案描述符。
您目前正在做的是創建一個鏈表,其中每個節點都包含一個指向檔案描述符的指標。但是,每個節點都指向同一個檔案描述符變數(clientSock在函式中指向main)。因此,您的鏈表實際上只存盤了一個檔案描述符,每當新的 HTTP 請求到達時,它就會不斷地被覆寫。
因此,您應該更改鏈表節點的定義,以便每個節點都包含自己的檔案描述符(而不是指向一個的指標):
struct node {
int client_socket;
struct node *next;
};
此外,您應該更改函式的函式原型enqueue并handleClient接受一個int引數而不是 a int *,并且dequeue應該回傳 anint而不是int *。當串列為空時,該函式dequeue應回傳-1。應該使用這個值,因為它不能代表一個有效的檔案描述符。
當然,您還應該相應地調整呼叫這些函式的代碼。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/368136.html
上一篇:從curl回應中提取HTTP正文
